为什么这个动态字符串创建会在固定数字后抛出 exc_bad_access 错误?

Why does this dynamic string creation throw exc_bad_access error after a fixed number?

好的,所以我正在尝试将文件中的文本存储在一个字符串中,并且一切正常,直到我发现我没有正确地重新分配内存,它不应该工作。

这是我的 main 修正前的函数:

FILE * file;
char * quijote, thisChar;
unsigned int writingAt = 0;

file = fopen("quijote.txt", "r");
quijote = malloc(1);

if (file != NULL) {
    while (1) {
        thisChar = (char)fgetc(file);
        if (thisChar == EOF) {
            break;
        } else {
            printf("strlen(quijote) = %lu; writingAt = %i\n", strlen(quijote), writingAt);
            quijote = (char *) realloc(quijote, (sizeof(quijote) + 1));
            quijote[writingAt] = thisChar;
            quijote[writingAt + 1] = '[=11=]';
            writingAt++;
        }
    }
} else {
    perror("fopen");
}
fclose(file);

它工作得很好,并且正确地将所有文件存储在字符串中。请注意,内存重新分配是不正确的,因为 sizeof(quijote) 始终具有相同的值 (8),因此理论上它不应该工作。

现在,当我更正重新分配时,它在 writingAt=135167 时随机抛出 EXC_BAD_ACCESS 错误。这是 "corrected" main 函数:

FILE * file;
char * quijote, thisChar;
unsigned int writingAt = 0;

file = fopen("quijote.txt", "r");
quijote = malloc(1);

if (file != NULL) {
    while (1) {
        thisChar = (char)fgetc(file);
        if (thisChar == EOF) {
            break;
        } else {
            printf("strlen(quijote) = %lu; writingAt = %i\n", strlen(quijote), writingAt);
            quijote = (char *) realloc(quijote, (writingAt + 1));
            quijote[writingAt] = thisChar;
            quijote[writingAt + 1] = '[=12=]';
            writingAt++;
        }
    }
} else {
    perror("fopen");
}
fclose(file);

这些是错误发生前程序打印的最后几行:

strlen(quijote) = 135162; writingAt = 135162
strlen(quijote) = 135163; writingAt = 135163
strlen(quijote) = 135164; writingAt = 135164
strlen(quijote) = 135165; writingAt = 135165
strlen(quijote) = 135166; writingAt = 135166
strlen(quijote) = 135167; writingAt = 135167
Exception: EXC_BAD_ACCESS (code=1, address=0x10fc20000)

我不明白为什么以前的代码可以工作而这个不行,或者为什么程序会在那个特定的数字中抛出错误。另外,我试过像这样重新分配到大小 1:quijote = (char *) realloc(quijote, 1); 并且出于某种原因它也有效...

您分配 writingAt + 1 个字符,然后访问 quijote[writingAt + 1],这是未定义的行为 - 它是第 (writingAt + 2) 个字符,比实际分配的字符数多一个。