C `Abort trap: 6` 仅在某些条件下

标签 c arrays string pointers char

我知道当您写入不属于您的内存部分时,会发生中止陷阱 6,但我在进行 K&R 练习时发现了一些有趣的事情。

/* strcat:  copies t to the end of s */
void _strcat(char *s, char *t) {
    while (*s != '\0') { 
        s++;
    }
    while ((*s++ = *t++) != '\0') { }
}

#include <stdio.h>
int main() {
    char s[7] = "hello, ";
    char *t = "world";

    _strcat(s, t);
    printf("%s\n", s);
    return 0;
}

感兴趣的部分是char s[7] = "hello, "

当数组大小为 7 时,"hello, ", Abort trap 6 的确切长度不会被打印,即使_strcat 添加超出内存初始化部分的字符。

8 - 12(含)之间的任何数字都会产生中止陷阱 6,而 >= 13 的数字都可以。

因此出现两个问题:

  1. 为什么 char s[12] = "hello, " 不行,而 7 可以?似乎尾部的 '\0' 需要一个大小为 13 的数组,但为什么 7 可以呢?不应该是8吗?
  2. 为什么 7 可以呢?大小 8-12 包含 "hello, " 就像大小为 7 的字符数组一样,并且写入超出了其原始数组大小,但 7 却逃脱了它,而其他人则没有't。

最佳答案

您必须阅读机器代码才能弄清楚这一点。正如 Jonathan Leffler 所说,这是未定义的行为。

这可能取决于编译器以及它如何在内存中布局。不要求大小为 7 的数组获得实际的 7 个字节。它可能决定将其填充到 16,以获得更好的堆栈布局。或者它可能会将其放置在不同的位置,因此后面有一个零和一些额外的空间,而较大的数组会获得不同的位置。

或者,如果您在优化的情况下进行编译,编译器可能会将大小为 7 的循环展开为“正确”代码,从而简化为简单的 puts("hello, world"); 但无法内联一个更大的循环。

出于好奇,我做了一个小实验,在 Linux 上使用 GCC 时,答案是在 64 位模式下它总是可以工作,因为 8 字节 char *t 指针中有足够的空间来存储“世界”

在 32 位模式下,正如您所描述的那样,它会失败,因为它会覆盖返回堆栈。但是 7 可以处理垃圾数据,因为它在超过返回值之前找不到零,然后它“附加”到开放堆栈空间中。打印结果类似于 hello, ��#m�?��world

关于C `Abort trap: 6` 仅在某些条件下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45602754/

相关文章:

c - 在c中的无限循环中输入

c - 如何在 C 中划分愚蠢的大数

javascript - setValues 不适用于 Google Apps 脚本中的数组

python : selecting row where y==1 and column is 0 in a matrix

java - 字符串不转换为 int

Java Applet - 将文件转换为字符串

c - 为什么它会改变变量的值?

c++ - 无法在 Linux 上找到 SDL2_gfx 库

java - 在 JNI 中获取一个 int 数组

javascript - 生成不含 O 和 0 的大写字母和数字的随机字符串