int main() {
char src[] = "santosh";
char dest[0];
strncpy(dest, src, 4);
printf("%sn", dest); // expecting o/p "sant" but o/p was "santtosh"
int i = 0;
while (dest[i]) {
printf("%c", dest[i]); //expecting output "sant" but it was "santtosh"
i++;
}
printf("n");
i = 0;
while (src[i]) {
printf("%c", src[i]); // expecting o/p "santosh" but it was "anttosh"
i++;
}
return 0;
}
我在这段代码上遇到了问题,我使用 gcc 编译器运行代码,这是我得到的输出(注释部分)。为什么行为不符合预期?为什么strncpy()
即使 dest buff 不够,也能复制源字符串?
您的代码调用未定义的行为,试图解释为什么它会产生一些输出或其他输出是没有意义的。
以下是问题:
-
您不包括
<stdio.h>
,也不包括<string.h>
。调用以前未定义的函数是不行的。 包含正确的头文件以避免未定义的行为。 -
char dest[0];
定义了一个大小为0
的数组。无法访问这样的对象,甚至它的地址也没有意义。gcc
和clang
允许这样做,但作为C标准的扩展。 这个定义看起来像一个错别字,使用gcc -Wall -W
或clang -Weverything
来启用有用的警告,以防止这种愚蠢的错误。 -
strncpy(dest, src, 4);
调用未定义的行为,因为dest
的长度小于4
。请注意,如果dest
长度为4
,则行为仍然容易出错,因为如果源字符串的长度大于或等于 size 参数,strncpy
不会 null 终止目标数组。这里"santosh"
的长度是7
,所以dest
可以保存字符s
、a
、n
和t
,但没有空终止符。 您的while
循环将调用未定义的行为,因为while (dest[i])
将访问超出其大小的dest
。strncpy()
容易出错,它的语义被广泛误解,很容易导致错误。请勿使用此功能。 -
如上所述,
while (dest[i])
调用未定义的行为,因为dest
不能按当前定义取消引用,或者即使它被定义为char dest[4];
。
这是一个改进的版本,使用snprintf()
和strncat()
:
#include <stdio.h>
#include <string.h>
int main(void) {
char src[] = "santosh";
char dest[5];
*dest = ' ';
strncat(dest, src, 4);
printf("%sn", dest); // will output "sant"
for (int i = 0; dest[i]; i++) {
printf("%c", dest[i]); // will output "sant" too
}
printf("n");
snprintf(dest, sizeof dest, "%s", src);
printf("%sn", dest); // will output "sant"
for (int i = 0; dest[i]; i++) {
printf("%c", dest[i]); // will output "sant" again
}
printf("n");
for (int i = 0; src[i]; i++) {
printf("%c", src[i]); // will output "santosh"
}
printf("n");
return 0;
}