崩溃或“分段错误”;当数据被复制/扫描/读取到未初始化的指针时

发布于 2025-01-12 16:00:31 字数 419 浏览 3 评论 0原文

这个问题旨在用作所有常见问题的参考:

当我将数据分配/复制/扫描到未初始化指针所在的地址时,为什么会出现意外行为,通常是神秘的崩溃或“分段错误”指向?

示例:

int *ptr;
*ptr = 10; // Crash here!
char *ptr;
strcpy(ptr, "Hello, World!"); // Crash here!
char *ptr;
scanf("%s", ptr); // Crash here!

This question is meant to be used as reference for all frequently asked questions of the nature:

Why do I get unexpected behavior, usually a mysterious crash or 'segmentation fault,' when I assign/copy/scan data to the address where an uninitialized pointer points to?

Examples:

int *ptr;
*ptr = 10; // Crash here!
char *ptr;
strcpy(ptr, "Hello, World!"); // Crash here!
char *ptr;
scanf("%s", ptr); // Crash here!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

蔚蓝源自深海 2025-01-19 16:00:31

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

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

{
  int data = 0;
  int* ptr = &data;
  ...
}

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

int* ptr = malloc(sizeof(int));

在初始化之前使用指针始终是一个错误。它尚未指向有效的内存。

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

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

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

// 2.
char* bad;
strcpy(bad, "hello");

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

/*** 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");

请注意,您还可以将指针设置为指向明确定义的“无处”,通过让它指向NULL。这使得它成为一个空指针,这是一个保证不指向任何有效内存的指针。这与使指针完全未初始化不同。

int* p1 = NULL; // pointer to nowhere
int* p2;        // uninitialized pointer, pointer to "anywhere", cannot be used yet

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

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


进一步阅读:

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

分段错误及原因
什么是分段错误?
为什么当写入用“char *s”而不是“char s[]”初始化的字符串时,我遇到分段错误?
char s[ 之间有什么区别] 和 char *s?
分段错误常见原因的明确列表
什么是总线错误?

A pointer is a special type of variable, which can only contain an address of another variable. It cannot contain any data. You cannot "copy/store data into a pointer" - that doesn't make any sense. You can only set a pointer to point at data allocated elsewhere.

This means that in order for a pointer to be meaningful, it must always point at a valid memory location. For example it could point at memory allocated on the stack:

{
  int data = 0;
  int* ptr = &data;
  ...
}

Or memory allocated dynamically on the heap:

int* ptr = malloc(sizeof(int));

It is always a bug to use a pointer before it has been initialized. It does not yet point at valid memory.

These examples could all lead to program crashes or other kinds of unexpected behavior, such as "segmentation faults":

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

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

// 2.
char* bad;
strcpy(bad, "hello");

Instead, you must ensure that the pointer points at (enough) allocated memory:

/*** 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");

Note that you can also set a pointer to point at a well-defined "nowhere", by letting it point to NULL. This makes it a null pointer, which is a pointer that is guaranteed not to point at any valid memory. This is different from leaving the pointer completely uninitialized.

int* p1 = NULL; // pointer to nowhere
int* p2;        // uninitialized pointer, pointer to "anywhere", cannot be used yet

Yet, should you attempt to access the memory pointed at by a null pointer, you can get similar problems as when using an uninitialized pointer: crashes or segmentation faults. In the best case, your system notices that you are trying to access the address null and then throws a "null pointer exception".

The solution for null pointer exception bugs is the same: you must set the pointer to point at valid memory before using it.


Further reading:

Pointers pointing at invalid data
How to access a local variable from a different function using pointers?
Can a local variable's memory be accessed outside its scope?

Segmentation fault and causes
What is a segmentation fault?
Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?
What is the difference between char s[] and char *s?
Definitive List of Common Reasons for Segmentation Faults
What is a bus error?

爱的那么颓废 2025-01-19 16:00:31
  1. 指针仅指向内存位置。您创建了一个指针,但尚未绑定到内存位置。 strcpy 希望您传递两个指向两个字符数组的指针(第一个不能是常量),如下签名:

    char * strcpy ( char * 目标,const char * 源 );
    

    示例用法:

    char* ptr = malloc(32);  
    strcpy(ptr, "你好世界");
    
    char str[32];  
    strcpy(str, "你好世界");
    
  2. 您可以尝试下面的代码片段读取字符串直到到达换行符(*您还可以添加其他空白字符,例如 "%[^\t\n]s"(制表符、换行符)或<代码>"%[^ \t\n]s"(空格、制表符、换行符))。

    char *ptr = malloc(32);
    scanf("%31[^\n]", ptr);
    

    (在现实生活中,不要忘记检查 scanf() 的返回值!)

  1. Pointers only point to a memory location. You created a pointer but you did not bind to a memory location yet. strcpy wants you to pass two pointers (first one mustn't be constant) that point to two character arrays like this signature:

    char * strcpy ( char * destination, const char * source );
    

    sample usage:

    char* ptr = malloc(32);  
    strcpy(ptr, "hello world");
    
    char str[32];  
    strcpy(str, "hello world");
    
  2. You can try the following code snippet to read string until reaching newline character (*you can also add other whitespace characters like "%[^\t\n]s"(tab, newline) or "%[^ \t\n]s" (space, tab, newline)).

    char *ptr = malloc(32);
    scanf("%31[^\n]", ptr);
    

    (In real life, don't forget to check the return value from scanf()!)

岁月打碎记忆 2025-01-19 16:00:31

学习 C 时经常出现的一种情况是尝试使用单引号来表示字符串文字:

char ptr[5];
strcpy(ptr, 'hello'); // crash here!
//            ^     ^   because of ' instead of "

在 C 中,'h' 是单字符文字,而 "h"是一个字符串文字,包含 'h' 和空终止符 \0(即 2 字符数组)。另外,在 C 中,字符文字的类型是 int,即 sizeof('h') 相当于 sizeof(int) >,而 sizeof(char)1

char h = 'h';
printf("Size: %zu\n", sizeof(h));     // Size: 1
printf("Size: %zu\n", sizeof('h'));   // likely output: Size: 4

One situation that frequently occurs while learning C is trying to use single quotes to denote a string literal:

char ptr[5];
strcpy(ptr, 'hello'); // crash here!
//            ^     ^   because of ' instead of "

In C, 'h' is a single character literal, while "h" is a string literal containing an 'h' and a null terminator \0 (that is, a 2 char array). Also, in C, the type of a character literal is int, that is, sizeof('h') is equivalent to sizeof(int), while sizeof(char) is 1.

char h = 'h';
printf("Size: %zu\n", sizeof(h));     // Size: 1
printf("Size: %zu\n", sizeof('h'));   // likely output: Size: 4
萌化 2025-01-19 16:00:31

为了制作字符串的可修改副本,POSIX C 库有一个名为 的便捷函数,而不是使用 mallocstrlenstrcpy 中的 >strdup 将返回传入的以 null 结尾的字符串的副本,并分配存储持续时间。使用后,应使用free释放指针:

char* ptr;
ptr = strdup("hello world");
ptr[0] = 'H';
puts(ptr);
free(ptr);

For making a modifiable copy of a string, instead of using malloc, strlen and strcpy, the POSIX C library has a handy function called strdup in <string.h> that will return a copy of the passed-in null-terminated string with allocated storage duration. After use the pointer should be released with free:

char* ptr;
ptr = strdup("hello world");
ptr[0] = 'H';
puts(ptr);
free(ptr);
十级心震 2025-01-19 16:00:31

发生这种情况是因为您没有为指针char* ptr分配内存。
在这种情况下,您必须为指针分配内存。实现此目的的一种方法是使用函数 malloc()calloc() 动态分配内存:

char* ptr;
ptr = malloc(50); // Allocate space for 50 characters
strcpy(ptr, "hello world");

当使用 * 时ptr 结束后,不要忘记释放为*ptr 分配的内存。这可以使用free()函数来完成。

free(ptr); // Deallocating memory
// Size of dynamically allocated memory can be changed by using realloc()

char *tmp = realloc(ptr, 100); // Allocate space for 100 characters
if (!tmp) {
    // Reallocation failed, ptr not freed
    perror("Resize failed");
    exit(1);       
}
else {
    // Reallocation succeeded, old ptr freed
    ptr = tmp;
}

在大多数情况下,分段错误是由于内存分配错误或数组越界情况而发生的。

This happens because you have not allocated memory for the pointer char* ptr.
In this case you have to allocate memory for the pointer. One way to do this is to dynamically allocate memory using the functions malloc() and calloc():

char* ptr;
ptr = malloc(50); // Allocate space for 50 characters
strcpy(ptr, "hello world");

When the use of *ptr over don't forget to deallocate memory allocated for *ptr. This can be done using free() function.

free(ptr); // Deallocating memory
// Size of dynamically allocated memory can be changed by using realloc()

char *tmp = realloc(ptr, 100); // Allocate space for 100 characters
if (!tmp) {
    // Reallocation failed, ptr not freed
    perror("Resize failed");
    exit(1);       
}
else {
    // Reallocation succeeded, old ptr freed
    ptr = tmp;
}

In most cases segmentation fault happens due to error in memory allocation or array out of bound cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文