为什么这个取消引用别名内存区域的C程序会导致分段错误?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么这个取消引用别名内存区域的C程序会导致分段错误?相关的知识,希望对你有一定的参考价值。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *myptr = calloc(500,1);
    char *myptr2 = myptr;

    *myptr++ = 'A';
    *myptr++ = 'B';
    *myptr = '\0';
    /* This should dereference the beginning of the memory and print until myptr[2] which is '\0' */
    printf("Myptr2 points to: %s\n", *myptr2);

    free(myptr);

    return(EXIT_SUCCESS);
}

为什么第13行(printf行)创建了一个SIGSEV?它应该指向内存的开头,然后printf应该打印,直到它到达'\ 0'。

答案

你能从概念上讲出问题是什么吗?如果取消引用指向内存的指针,这会导致什么?

当你在格式字符串中有一个%s插槽时,printf希望看到一个char*作为相应的参数。这就是为什么你应该传递myptr2(这是'A'的地址,并且可以从中推断出字符串字符的后续地址)。

如果你通过*myptr2代替,你基本上传递了字符'A'本身(没有任何信息,特别是'A'的位置 - 这将允许printf读取字符串的其余部分)。简单地说,printf期望指针在那里,所以它试图将相应的参数视为指针。

现在请注意,您传递的字符(通过解除引用char*,因此获得char值为'A')的大小为1字节,而指针的大小通常为4或8字节。这意味着printf很可能会读取由字符和堆栈中的一些随机数据组成的垃圾地址。在这种情况下,无法保证程序会发生什么,因此整个事件会调用未定义的行为。

另一答案

在你的代码中,你不应该在printf的第二个参数中取消引用myptr2,所以你必须替换:

printf("Myptr2 points to: %s\n", *myptr2);

有:

printf("Myptr2 points to: %s\n", myptr2);

将%s与printf一起使用时,必须在字符串的第一个字符上给出指针。

以上是关于为什么这个取消引用别名内存区域的C程序会导致分段错误?的主要内容,如果未能解决你的问题,请参考以下文章

C即使分配了内存,修改链表的程序也会导致分段错误

什么是分段错误?

C# 命名空间别名限定符 (::) 与取消引用运算符 (.)

C++ 构建警告:取消引用类型双关指针将破坏严格别名规则

为啥我的字符串分配会导致分段错误?

为啥这个字符串反转 C 代码会导致分段错误? [复制]