12

代码:

int str_join(char *a,  const char *b) {
   int sz =0; 
   while(*a++) sz++;  
   char *st = a -1, c;  
   *st = (char) 32;
   while((c = *b++)) *++st = c;  
   *++st = 0;
   return sz;
}

....

char a[] = "StringA"; 
printf("string-1 length = %d, String a = %s\n", str_join(&a[0],"StringB"), a);

输出:

string-1 长度 = 7, char *a = StringA StringB

*** 检测到堆栈粉碎 **** : /T02 终止

中止(核心转储)

我不明白为什么它显示堆栈粉碎?什么是*堆栈粉碎?还是我的编译器的错误?

4

2 回答 2

12

好吧,堆栈粉碎堆栈缓冲区溢出是这里要讨论的一个相当详细的话题,您可以参考这篇 wiki 文章了解更多信息。

来到这里显示的代码,问题是,您的数组a不够大,无法容纳最终的连接结果。

因此,通过说

 while((c = *b++)) *++st = c;

您实际上是在访问调用未定义行为的超出范围的内存。这就是您遇到“堆栈粉碎”问题的原因,因为您试图访问不属于您的进程的内存。

为了解决这个问题,您需要确保数组a包含足够的空间来容纳连接在一起的第一个和第二个字符串。简而言之,您必须提供更大的目标数组。

于 2016-11-04T06:27:50.240 回答
6

堆栈粉碎意味着您已经在函数的局部变量存储空间(在大多数系统和编程语言中称为“堆栈”)之外(“粉碎”过去/通过)编写。您可能还会发现这种类型的错误称为“堆栈溢出”和/或“堆栈下溢”。

在您的代码中,C 可能将指向的字符串a放在堆栈上。在您的情况下,导致堆栈粉碎的地方是当您st超出原始a指针并写入它指向的位置时,您正在编写 C 编译器保证为分配给原始字符串保留的区域之外a

每当您在 C 中已经正确“保留”的内存区域之外进行编写时,这就是“未定义的行为”(这只是意味着 C 语言/标准没有说明会发生什么):通常,您最终会覆盖其他内容您的程序的内存(程序通常将其他信息放在堆栈上的变量旁边,例如返回地址和其他内部详细信息),或者您的程序尝试在操作系统“允许”它使用的内存之外写入。无论哪种方式,程序通常都会中断,有时会立即且明显(例如,出现“分段错误”错误),有时会以非常隐蔽的方式中断,直到很久以后才会变得明显。

在这种情况下,您的编译器正在构建具有特殊保护的程序以检测此问题,因此您的程序会以错误消息退出。如果编译器没有这样做,您的程序将尝试继续运行,除非它最终可能会做错事和/或崩溃。

解决方案归结为需要明确告诉您的代码为您的组合字符串提供足够的内存。您可以通过显式指定“a”数组的长度来做到这一点,使其对两个字符串都足够长,但这通常仅适用于您事先知道需要多少空间的简单用途。对于通用解决方案,您将使用一个函数,例如malloc从操作系统获取指向新内存块的指针,该内存块具有您需要/想要的大小,一旦您计算出完整大小将是多少(只需记住在完成后调用free您从中获得的指针malloc和类似的函数)。

于 2016-11-04T06:43:06.880 回答