将数据复制/扫描/读取到未初始化指针时发生崩溃或"分段错误"

Lun*_*din 42 c pointers segmentation-fault

这个问题可以作为所有常见问题的参考:

当我将数据复制/扫描到未初始化指针所指向的地址时,为什么会出现神秘崩溃或"分段错误"?

例如:

char* ptr;
strcpy(ptr, "hello world"); // crash here!
Run Code Online (Sandbox Code Playgroud)

要么

char* ptr;
scanf("%s", ptr); // crash here!
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 32

指针是一种特殊类型的变量,它只能包含另一个变量的地址.它不能包含任何数据.你不能"将数据复制/存储到指针" - 这没有任何意义.您只能设置指针指向其他位置分配的数据.

这意味着为了使指针有意义,它必须始终指向有效的内存位置.例如,它可以指向堆栈上分配的内存:

{
  int data = 0;
  int* ptr = &data;
  ...
}
Run Code Online (Sandbox Code Playgroud)

或者在堆上动态分配的内存:

int* ptr = malloc(sizeof(int));
Run Code Online (Sandbox Code Playgroud)

在初始化之前使用指针始终是一个错误.它还没有指向有效的内存.

这些示例都可能导致程序崩溃或其他类型的意外行为,例如"分段错误":

/*** examples of incorrect use of pointers ***/

// 1.
int* bad;
*bad = 42;

// 2.
char* bad;
strcpy(bad, "hello");
Run Code Online (Sandbox Code Playgroud)

相反,您必须确保指针指向(足够)分配的内存:

/*** examples of correct use of pointers ***/

// 1.
int var;
int* good = &var;
*good = 42;

// 2.
char* good = malloc(5 + 1); // allocates memory for 5 characters *and*  the null terminator
strcpy(good, "hello");
Run Code Online (Sandbox Code Playgroud)

请注意,您也可以将指针设置为指向明确定义的"无处",指向它NULL.这使它成为一个空指针,这是一个保证不指向任何有效内存的指针.这与将指针完全取消初始化不同.

int* p1 = NULL; // pointer to nowhere
int* p2;        // uninitialized pointer, pointer to "anywhere", cannot be used yet
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试访问空指针指向的内存,则可能会遇到与使用未初始化指针时类似的问题:崩溃或分段错误.在最好的情况下,您的系统会注意到您尝试访问地址null,然后抛出"空指针异常".

空指针异常错误的解决方案是相同的:在使用之前,必须将指针设置为指向有效内存.


进一步阅读:

指向无效数据的指针
如何使用指针从不同的函数访问局部变量?
可以在其范围之外访问局部变量的内存吗?

分段故障和原因
什么是分段故障?
为什么在写入用"char*s"而不是"char s []"初始化的字符串时会出现分段错误?
char s []和char*s有什么区别?
分段错误的常见原因的明确列表
什么是总线错误?

  • "它不能包含任何数据." - 嗯,实际上地址**是**的数据. (4认同)
  • 请注意最后一个示例:一个不需要取消引用指针以显示未定义的行为.与其他任何东西一样,不确定的内容("p2`的值的情况")就其性质而言,即使*评估*也会调用未定义的行为,更不用通过*解除引用*来进一步推动疯狂行为.是的,这是一个不同的问题,但紧密相关.总之,声明"在初始化之前使用指针始终是一个错误".是的,但"使用"并不仅限于解除引用. (4认同)

归档时间:

查看次数:

7046 次

最近记录:

6 年,7 月 前