Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-使用strncpy()函数后的随机字符_C_Null_Integer_Termination - Fatal编程技术网

C-使用strncpy()函数后的随机字符

C-使用strncpy()函数后的随机字符,c,null,integer,termination,C,Null,Integer,Termination,我有以下C语言程序: 该程序的主要问题是,在执行复制操作后,在复制字母后会显示大量垃圾字符。我知道这是因为目标变量没有正确地以null结尾。但是,如果仔细检查代码,我将执行空终止。为什么问题仍然存在?那么,呃,你认为strlen()如何计算字符串的长度?你认为它需要终止吗 提示:是的。字符数组在C中不是字符串,除非它以0字符结尾。strlen()所做的就是计算字符数,直到找到终止符为止,因此在逻辑中使用它来终止缓冲区以使其成为字符串是一种类似鸡蛋的情况 您的问题是错误地使用了strncpy()。

我有以下C语言程序:


该程序的主要问题是,在执行复制操作后,在复制字母后会显示大量垃圾字符。我知道这是因为目标变量没有正确地以null结尾。但是,如果仔细检查代码,我将执行空终止。为什么问题仍然存在?

那么,呃,你认为strlen()如何计算字符串的长度?你认为它需要终止吗

提示:是的。字符数组在C中不是字符串,除非它以0字符结尾。strlen()所做的就是计算字符数,直到找到终止符为止,因此在逻辑中使用它来终止缓冲区以使其成为字符串是一种类似鸡蛋的情况

您的问题是错误地使用了
strncpy()
。这是一件很容易出错的事情,因为从典型(初学者)C程序员的角度来看,函数有点疯狂。从名字上看,它根本没有达到你所期望的效果

只要您确定
nob
,您可能就应该手动执行此操作:

memcpy(destination, source, nob);
destination[nob] = '\0';

strncpy
不保证您的
destination
字符串在复制后将以null结尾。我的做法是:

destination[ nob ] = '\0';
而不是:

destination[strlen(destination)] = '\0';
拥有:


strlen
一直读取,直到找到
'\0'
字符。

经过一些非常小的修改后,这将非常有效:

char destination[18] = {'\0'};

这是失败的,因为strncpy只复制第一个nob字符,并且不附加尾部0。您尝试在目标字符串上添加带有strlen()的尾随0是没有帮助的,因为它会将字符计数到第一个0,并在该位置放置一个零(这将无效)

“破解”修复程序的一种方法是清除目标字符串:

memset( destination, 0, sizeof(destination));

可能有更好的解决方案,包括将>17的测试设置为>18

Matthew,当您已经知道要复制的字符串的长度时,您不需要
strcpy
strncpy
(检查每个字符的末尾是否有\0)。相反,您应该使用
memcpy
,然后终止新字符串:

memcpy(destination, source, nob);
destination[nob] = '\0';

memcpy
不检查'\0',因此速度更快。

不要使用strncpy,它非常危险。正如我们从您的示例中看到的,程序员总是忘记输入正确的参数,结果导致字符串损坏。这是一个非常常见的错误

strcpy()更安全,但也不理想,因为它没有边界检查。如果使用不当,可能会导致缓冲区溢出,这是一个安全问题。这也是一个常见的bug

复制字符串最快、最安全的方法是通过memcpy:

memcpy(destination, source, nob);
desitnation[nob] = '\0';

你错了!这将在所有元素都设置为“\0”的情况下初始化表。如果将实际缓冲区长度传递给strncpy(这是导致此错误的最常见原因),这将不会有帮助。您能解释一下为什么这不会有帮助吗?对于strncpy,传递的大小被检查为小于缓冲区大小“if(nob>17)”@codewarrior在这种特殊情况下有边界检查,通常没有边界检查,因为大多数程序员不知道strncpy工作的模糊方式。即使您设法规避了这种风险,这种特殊情况也会像这样工作:1)用零填充18字节的空白空间。2) 用实际数据覆盖零。3) 在覆盖零的同时,检查源字符串的每个字节是否以null结尾。4) 用零(再次)填充剩余的缓冲区。总的来说,非常低效且毫无意义。如果您使用memcpy,然后将单个字节设置为零,您将得到以下结果:1)使用实际数据填充缓冲区。2) 空终止它。完成。不要摆弄无用的零或额外的检查。如果实际的缓冲区长度被传递给strncpy,那么你的黑客攻击将不会有帮助,这是这个bug最常见的原因。因为空终止不能适用于任何地方,所以strncpy跳过它,并愉快地让您的程序进入laland。C11 7.24.3
如果s2指向的数组是一个短于n个字符的字符串,则s1指向的数组中的副本将追加空字符,直到总共写入了n个字符。
但是如果数组不短于n个字符,则会出现厄运、崩溃和烧坏点——memset()若nob被允许年满18岁,那个么这个解决方案就行不通了。@Matthew,若你们觉得这个答案对你们有帮助的话,请随意接受。谢谢。从每个人的角度来看,strncpy都是疯子。除了空终止问题外,它还检查每个字符的空终止,并在实际复制完成后在空终止上附加一个泛洪。这是C中比较晦涩的函数之一。@Lundin是的,很糟糕。我想,当年使用“记录”编程是有道理的,但也许那个时代的程序员没有一个幸存下来,在这种情况下,我完全同意你的看法。:)它确实保证了这一点,但前提是您传递的是字符串长度,而不是内存缓冲区长度(总是至少是字符串长度+1)。@Lundin:反过来说。如果传递字符串长度(字符串中非空字符的数量),则只复制多个字符(并且它们都是非空的)。如果您传递缓冲区长度,并且源缓冲区中有一个空字符,那么第一个空字符将复制到目标(目标中的以下字节也设置为空)。@EricPostIschil是的,这与我所说的并不矛盾。我的意思是,如果你有
char str1[3]
char str2[]=“abc”
然后
strncpy(str1,str2,3)
memcpy(destination, source, nob);
desitnation[nob] = '\0';