[英]strcat implementation using pointers
有人知道,当我这样写时,程序崩溃了。
#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;
}
但奇怪的是,当我不使用这两个“//”评论时,它有效! 那么为什么要添加那些简单的s2[0] = '\\0';
可以使这个程序工作。
当您通过旧的C malloc
函数或C ++ new
运算符分配内存时,该内存不会以任何方式初始化。 在初始化时读取该内存会导致未定义的行为 ,并且未定义的行为(或UB因为它经常被缩短)是崩溃的主要原因之一。
malloc()
返回的指针不保证是0
填充的( 或者,就此而言,根据任何值初始化为任何值 )。 除了s1[0] = '\\0';
part, while(*s++);
可能没有做你期望的事情。
没有初始归零部分, while(*s++);
无法阻止read-before-write场景。
由于这是未定义的行为
在这种情况下,正如彼得先生在评论中指出的那样,第一点本身会导致UB,并且无法保证它将达到第二点。 但是,在某些其他情况下,即使内存已初始化但未终止,也会触及第二个点来调用UB。
在C中,每个字符串都以'\\ 0'字符终止。
malloc
只是分配内存,它不会为你写'\\ 0'。
如果您不添加它,程序将不知道字符串的结尾在哪里,并且可能会尝试在实际字符串之后读取一些未分配的内存,因此它将导致未定义的行为。
实际上, mystrcat
函数会使指针递增,直到它指向'\\ 0'字符或0
。
但是如果在分配的内存中找不到0,那么在指针的下一个增量之后,它将指向一些未分配的内存。
现在取消引用它将导致未定义的行为。
正如其他答案所说,你需要初始化那个内存。 你可以通过多种方式实现这一点,但一种方法是使用calloc而不是malloc。 如果你改变这两行:
s1 = (char *)malloc(size);
s2 = (char *)malloc(size);
至:
s1 = calloc(size,sizeof(*s1));
s2 = calloc(size,sizeof(*s2));
你的程序将运行。
当你调用malloc
,你会收到你的char*
到某些内存。 你拥有该内存的size
字节。 但是malloc
并没有以任何方式准备你现在拥有的内存。 它保留在先前拥有的进程留在其中的任何状态。因此,很可能是您收到的内存已包含长度超过size
的字符串。
因此,当您开始strcat
并运行到第一个字符串的末尾时,它将超过size
的长度,并尝试开始写入此内存。 这里出现了问题,因为你没有在那个位置拥有内存,因此程序会出现段错误。
另一方面,如果通过让第一个字节为"\\0"
来初始化字符串,则实际上将字符串的长度设置为0(因为在结束标记之前有0个字节: "\\0"
)。 因此,当你开始你的strcat
,它将再次运行到第一个字符串的末尾,但这次结束是在size
范围内。
请注意,如果组合字符串长度超过size
您可能仍会遇到问题。
该声明
while(*s++);
对mystrcat
前两次调用没有任何意义,并调用未定义的行为。 你不应该读取未初始化的内存。
您需要检查传递的第一个参数是否为空字符串
void mystrcat(char *s,char *t) {
if(strlen(s))
{
while(*s++);
s--;
}
while(*s++ = *t++);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.