为何仅为char**变量临时赋值后程序才能正常运行?
问题
我尝试在一个函数中分配字符串,并通过char**类型的指针将其返回。如果仅创建char**类型的指针并传递给函数,让函数修改其指向字符串的指针值,程序可编译但返回Program returned: 139。但如果在调用函数前为该指针简单赋值,程序就能正常运行!
代码如下:
#include <stdio.h> #include <stdlib.h> #include<stdbool.h> // Include bool type void getString(char **str_ptr){ char * my_str = "String I passed." ; *str_ptr = my_str ; } void printMyStr(char **str_ptr){ int i = 0; char *str = *str_ptr; printf("Print starts \n\t" ); // looping till the null character is encountered while(str[i] != '\0') { printf("%c", str[i]); i++; } printf("\nPrint ends \n" ); } int main() { char *str = "My great String"; char **str_ptr; str_ptr = &str; // If this is commented, errors with 139 getString(str_ptr); printMyStr(str_ptr); return 0; };
正常运行时输出:
Print starts String I passed. Print ends
但如果注释掉str_ptr = &str;这一行,程序返回139且无任何输出。请问:
- 注释该行时程序为何失败?
- 为何添加该行后程序就能正常运行?
- 该行如何改变了运行结果(但输出仍为"String I passed.")?
原因分析
1. 注释str_ptr = &str;时程序失败的原因
char **str_ptr;仅声明了一个二级指针,但未初始化,此时str_ptr是野指针,存储的是随机的垃圾内存地址。
在getString函数中执行*str_ptr = my_str;时,相当于试图往这个随机地址写入数据——这属于非法内存访问,触发了操作系统的内存保护机制(即段错误,对应信号SIGSEGV),所以程序直接崩溃,返回码139。
2. 添加该行后程序正常运行的原因
str_ptr = &str;将二级指针str_ptr指向了main函数中char* str变量的内存地址,让str_ptr拥有了一个合法、可访问的指向目标。
此时在getString函数中执行*str_ptr = my_str;,本质是把字符串常量"String I passed."的地址赋值给main里的str变量,整个操作是对合法内存的修改,没有越界或非法访问,因此程序能正常执行。
3. 为何输出仍是"String I passed."
str变量初始值是"My great String"的地址,但getString函数通过*str_ptr = my_str;覆盖了str的值,将其改为"String I passed."的地址。后续printMyStr读取的是修改后的str指向的字符串,所以输出后者。str_ptr = &str;只是给二级指针一个合法的指向,并未影响最终被赋值的字符串内容。
内容的提问来源于stack exchange,提问作者user2506946

