【问题标题】:Strange strncpy response奇怪的 strncpy 反应
【发布时间】:2016-04-03 20:11:57
【问题描述】:

我只是运行这段代码,我得到的 n=1 不是我期望得到的。你能解释一下为什么会这样吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRIGA 11
int main()
{
    char s[MAXRIGA+2];
    char a[MAXRIGA]="pippo";
    strncpy(s, a, 1); //       n=1
    printf("%s", s);
    return 0;
}

返回

pF

如果 n=2 或更多,我会得到我想要的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRIGA 11
int main()
{
    char s[MAXRIGA+2];
    char a[MAXRIGA]="pippo";
    strncpy(s, a, 2); //       n=2
    printf("%s", s);
    return 0;
}

返回

pi

【问题讨论】:

  • 试试char s[MAXRIGA+2] = {0};
  • 请勿使用strncpy,它不会像您认为的那样做。如果您认为自己知道,请再想一想并阅读 C 文档进行验证。
  • 我对@9​​87654328@函数的咆哮:the-flat-trantor-society.blogspot.com/2012/03/…
  • 阅读 Keith 的专栏,内容丰富。请注意,strncat 也不是strcat 的更安全版本,它只是限制附加到目标缓冲区的字符数的变体,但使用它来避免缓冲区溢出很麻烦。

标签: c string strcpy strncpy


【解决方案1】:

来自man strncpy

strncpy() 函数类似,只是src最多n个字节 被复制。警告:如果前 n 个字节中没有空字节 src 中,放置在 dest 中的字符串不会以 null 结尾。

您仅从源字符串中复制一个字节,该字节不是空终止符。因此,您会在此处得到未定义的行为,例如尝试打印未终止的字符串。 n=2 也是如此,似乎是偶然的。

【讨论】:

  • 成语:strncpy(s, a, n)[n] = '\0'; 将解决空终止符的缺失。
  • 这是另一种可能性,如果有的话。
  • @JohnHascall 这个成语的诀窍是size of the array - 1 --&gt; n
【解决方案2】:

strncpy 不会将空终止符附加到字符串上。使用strncpy后需要手动添加。

像这样:

strncpy(s, a, 1); //       n=1
s[1]=0;
printf("%s", s);

F(来自 pF)只是任何任意字符,它仍然恰好位于内存中在找到任何空终止符之前遇到的位置。严格来说你的代码应该会产生缓冲区溢出错误,或者访问冲突错误。

使用strncpy 后添加空终止符,您的问题就会消失:)

【讨论】:

  • strncpy 不会将空终止符附加到字符串上除非有足够的空间这样做
  • @KeithThompson 无论如何都不会附加它们。如果源包含它们,它正在复制它们。
  • @EugeneSh。实际上,如果有空间,它正在将空字节一直附加到目标缓冲区的末尾!!!这东西是一个专门的功能,不应该成为标准。
  • 其实 EugeneSh 是正确的。 strncpy 不附加任何内容。它只复制它被“告知”要复制的内容......要复制的字符中是否存在空终止符是无关紧要的,警告任何使用 strncpy 以确保空终止符被“附加”的人是很痛苦的。 (除非你真的知道自己在做什么,不像 OP)
  • 嗯,是的。从手册页:If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written. 所以它是 padding 源代码。但前提是它已经有一个:)
【解决方案3】:

由于您没有初始化数组s,它包含随机值。 C 中的字符串以 NULL 字符终止,因此当您使用“pippo”初始化数组 a 时,它包含的值是:

offset | 0 | 1 | 2 | 3 | 4 |  5 |
value  | p | i | p | p | o | \0 |

当您调用printf 时,它需要确定字符串的结尾在哪里,并通过打印字符来执行此操作,直到它到达终止的 NULL。如果s 包含随机数据并且您只复制单个字符,那么printf 将打印字符串,直到它到达恰好为NULL 的字节。在这种情况下,随机数据的第 3 个字节似乎是 \0,因此 printf 会打印到该点为止的字符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 2013-04-04
    • 1970-01-01
    • 2019-08-12
    相关资源
    最近更新 更多