在没有明显内存违规的情况下中止而不是段错误

mck*_*mck 4 c memory-management

在处理C字符串时,我遇到了这种奇怪的行为.这是K&R书中的练习,我应该编写一个函数,将一个字符串附加到另一个字符串的末尾.这显然要求目标字符串分配足够的内存,以便源字符串适合.这是代码:

 /* strcat: Copies contents of source at the end of dest */
 char *strcat(char *dest, const char* source) {
  char *d = dest;
  // Move to the end of dest
  while (*dest != '\0') {
    dest++;
  } // *dest is now '\0'

  while (*source != '\0') {
    *dest++ = *source++;
  }
  *dest = '\0';
  return d;
}
Run Code Online (Sandbox Code Playgroud)

在测试期间,我编写了以下内容,期望在程序运行时发生段错误:

int main() {
  char s1[] = "hello";
  char s2[] = "eheheheheheh"; 
  printf("%s\n", strcat(s1, s2));
}
Run Code Online (Sandbox Code Playgroud)

据我所知,s1得到一个6 chars分配的数组,s2 得到一个13的数组chars.我认为当strcat尝试在高于6的索引处写入s1时,程序会出现段错误.相反,一切正常,但程序不会干净地退出,而是:

helloeheheheheheh
zsh: abort      ./a.out
Run Code Online (Sandbox Code Playgroud)

并退出代码134,我认为这只是意味着中止.

为什么我没有得到段错误(如果在堆栈上分配字符串,则覆盖s2)?内存中的这些字符串(堆栈或堆)在哪里?

谢谢你的帮助.

Tim*_*nes 7

我认为当strcat尝试写入s1高于6该程序的索引时会发生段错误.

在堆栈上分配的内存范围之外写入是未定义的行为.通常(但不总是)调用此未定义的行为会导致段错误.但是,您无法确定是否会发生段错误.

维基百科链接很好地解释了它:

当发生未定义行为的实例时,就语言规范而言,任何事情都可能发生,也许什么都没发生.

因此,在这种情况下,您可能会遇到段错误,程序可能会中止,或者有时可能会运行正常.或者,任何事情.没有办法保证结果.

内存中的这些字符串(堆栈或堆)在哪里?

由于您已将它们声明为char []内部main(),因此它们是具有自动存储的阵列,出于实际目的,它们意味着它们位于堆栈中.

  • +1表示'未定义的行为' - 这是关键因素.当您在数组的边界之外进行践踏时,任何事情都可能发生,并且它是对未定义行为的合理响应. (2认同)