有人知道,当我这样写时,程序会崩溃。
#include<stdio.h>
#include<stdlib.h>
void mystrcat(char *s,char *t) {
while(*s++);
s--;
while(*s++ = *t++);
}
int main(void) {
int size = 1024;
char *s1, *s2;
s1 = (char *)malloc(size);
//s1[0] = '\0'; ********NOTE THIS********
s2 = (char *)malloc(size);
//s2[0] = '\0'; ********NOTE THIS********
mystrcat( s1, "Hello " );
mystrcat( s2, "World" );
mystrcat( s1, s2 );
printf( "\"%s\"\n", s1 );
return 0;
}
但奇怪的是,当我不使用那两个&#34; //&#34;评论,它的作品!
那么为什么添加那些简单的s2[0] = '\0';
可以使这个程序工作。
答案 0 :(得分:4)
当您通过旧的C malloc
函数或C ++ new
运算符分配内存时,该内存不会以任何方式初始化。在初始化时读取该内存会导致未定义的行为,并且未定义的行为(或UB因为它经常被缩短)是崩溃的主要原因之一。
答案 1 :(得分:3)
malloc()
返回的指针不能保证为0
- 已填充,(或,根据任何值初始化为任何值)。除了s1[0] = '\0';
部分之外,while(*s++);
可能没有按照您的期望行事。
没有初始归零部分,while(*s++);
无法阻止先读后读方案。
因为
而undefined behavior在这种情况下,正如彼得先生在评论中指出的那样,第一点本身会导致UB,并且无法保证它达到到第二点。但是,在某些其他情况下,即使内存已初始化但未以空终止,您也会点击第二个点来调用UB。
答案 2 :(得分:1)
在C中,每个字符串都由&#39; \ 0&#39;终止。字符。
malloc
只是分配内存,它不会写入&#39; \ 0&#39;为你。
如果你没有添加它,程序就不知道字符串的结尾在哪里,并且可能会尝试在实际字符串之后读取一些未分配的内存,因此它将导致未定义的行为。
实际上,mystrcat
函数会使指针递增,直到它指向&#39; \ 0&#39;字符或0
但是如果在分配的内存中找不到0,那么在指针的下一个增量之后,它将指向一些未分配的内存。
现在取消引用它将导致未定义的行为。
答案 3 :(得分:1)
正如其他答案所说,你需要初始化那个记忆。你可以通过多种方式实现这一点,但一种方法是使用calloc而不是malloc。如果你改变这两行:
s1 = (char *)malloc(size);
s2 = (char *)malloc(size);
为:
s1 = calloc(size,sizeof(*s1));
s2 = calloc(size,sizeof(*s2));
您的程序将会运行。
答案 4 :(得分:0)
当您致电malloc
时,您会收到char*
一些内存。您拥有该内存的size
个字节。但是malloc
并没有以任何方式准备你现在拥有的记忆。它保留在先前拥有的进程留在其中的任何状态。因此,很可能是您收到的内存已经包含长度超过size
的字符串。
因此,当您开始strcat
并运行到第一个字符串的末尾时,它将超过size
的长度,并尝试开始写入此内存。这里出现了问题,因为你没有在那个位置拥有内存,因此程序会出现段错误。
另一方面,如果通过让第一个字节为"\0"
来初始化字符串,则实际上将字符串的长度设置为0(因为在结束标记之前有0个字节:{{ 1}})。因此,当您开始"\0"
时,它将再次运行到第一个字符串的末尾,但这次结束时间在strcat
之内。
请注意,如果组合字符串的长度超过size
,则可能会遇到问题。
答案 5 :(得分:-1)
声明
while(*s++);
对mystrcat
的前两次调用没有任何意义,并调用未定义的行为。你不应该读取未初始化的内存。
你需要知道传递的第一个参数是否为空字符串
void mystrcat(char *s,char *t) {
if(strlen(s))
{
while(*s++);
s--;
}
while(*s++ = *t++);
}