CS50替换问题集未分配内存引发段错误的原因咨询
嘿,我来给你把这个问题讲明白!首先得先搞懂CS50里的string到底是什么——它其实就是C语言里char*的一个别名而已,可不是那种自带内存管理的高级字符串类(比如C++的std::string)。说白了,string就是个指针,它本身不存储字符,只是指向一块内存区域的起始地址。
那如果不给output分配内存会咋样?要是你直接写string output;而不调用malloc,这个指针就是个野指针——它指向的内存地址完全是随机的,可能是程序里其他变量的内存,也可能是操作系统不让你碰的保护内存。这时候你去给output[i]赋值,就相当于在乱改不属于你的内存空间,操作系统一检测到这种非法访问,直接就给你抛出segmentation fault(段错误)了,这可不就崩了嘛!
再看你的需求:你要把输入字符串的每个字符替换后存到output里,那output必须要有一块足够大的、完全属于你的内存空间来存这些字符。malloc(strlen(input)+1)就是干这个的——它向操作系统申请了一块能容纳整个输入字符串(包括字符串末尾必须的'\0'终止符,所以要+1)的内存,然后把这块内存的起始地址赋值给output指针。这样你后续对output[i]的所有赋值操作,都是在你合法拥有的内存里进行,自然不会触发段错误了。
另外还要给你提个小bug:你代码里return output;之后写的free(output);完全是白写!因为函数执行到return就直接退出了,后面的代码根本不会运行,这就导致你申请的内存永远没被释放,会造成内存泄漏。正确的做法是:在调用cipher函数的地方,等你用完返回的output字符串之后,再调用free(output)来释放内存。
还有个小细节别忘了:malloc出来的内存是未初始化的,不会自动添加字符串终止符'\0',所以你在循环结束后得手动加一句output[strlen(input)] = '\0';,不然后续用字符串处理函数(比如printf)的时候,会因为找不到终止符而读越界,输出一堆乱码。
附上修正后的代码片段供你参考:
#include <cs50.h> #include <string.h> #include <ctype.h> // 假设这是你实现的字符替换函数 char substitute(char c, string key); string cipher(string input, string key) { // 申请足够容纳输入字符串+终止符的内存 string output = malloc(strlen(input) + 1); if (output == NULL) { // 最好加个内存申请失败的判断,更严谨 return NULL; } int len = strlen(input); for (int i = 0; i < len; i++) { if (isalpha(input[i])) { output[i] = substitute(input[i], key); } else { output[i] = input[i]; } } // 手动添加字符串终止符 output[len] = '\0'; return output; // 这里的free永远执行不到,移到调用处去做 }
内容的提问来源于stack exchange,提问作者A.SALEH

