为何C语言中两种char*指针读取字符串的方法一可行一失效?
问题根源:两个方法都存在未定义行为,只是“运气”不同
首先得明确:你的两个方法本质上都是错误的,方法1能“符合预期运行”纯粹是巧合,不是代码正确。核心问题出在你声明的char *str;是一个未初始化的野指针——它没有指向任何合法的、可写的内存区域。
为什么会出现这种诡异的差异?
不管是方法1还是方法2,你直接通过str+len往指针指向的地址写数据,都是在操作随机的非法内存:
- 方法1“正常”:只是刚好这个野指针指向的地址,在当前运行环境下是暂时可写的,而且后续的
printf没有破坏这块内存,所以看起来输出正常。但换个编译器、换个操作系统,或者稍微修改一下代码,它立刻就会崩溃或者输出乱码。 - 方法2“无法运行”:这次野指针指向的内存不可写,或者
readString函数执行完后,栈上的相关数据被覆盖了,导致printf找不到有效字符串。 - 加
int useless=-1;后又能运行:这改变了栈的布局,让未初始化的str刚好落在了一块暂时空闲的栈内存区域,又是一次随机的巧合,完全不代表问题被解决了。
正确的写法应该怎么做?
你需要给指针分配合法的内存空间,有两种常用方式:
方式1:使用固定大小的字符数组
#include <stdio.h> int readString(char *str, char delimiter, int maxLen) { int len = 0; // 限制读取的字符数,防止缓冲区溢出 while (len < maxLen - 1 && scanf("%c", &str[len]) == 1 && str[len] != delimiter) { len++; } // 处理分隔符(如果需要保留的话) if (str[len] == delimiter) { len++; } // 确保字符串以'\0'结尾 str[len] = '\0'; return len; } int main() { // 分配足够大的栈内存数组,比如100字节 char str[100]; int len = readString(str, '.', sizeof(str)); printf("%s", str); return 0; }
方式2:动态分配内存
如果需要不确定大小的字符串,可以用malloc动态分配(记得用完后释放):
#include <stdio.h> #include <stdlib.h> #define INIT_SIZE 32 int readString(char **str, char delimiter) { int len = 0; int capacity = INIT_SIZE; // 初始化动态内存 *str = malloc(capacity * sizeof(char)); if (*str == NULL) { perror("malloc failed"); return -1; } char c; while (scanf("%c", &c) == 1 && c != delimiter) { // 如果内存不够,扩容 if (len >= capacity - 1) { capacity *= 2; char *temp = realloc(*str, capacity * sizeof(char)); if (temp == NULL) { perror("realloc failed"); free(*str); return -1; } *str = temp; } (*str)[len++] = c; } // 处理分隔符(如果需要保留的话) if (c == delimiter) { (*str)[len++] = c; } (*str)[len] = '\0'; return len; } int main() { char *str = NULL; int len = readString(&str, '.'); if (len != -1) { printf("%s", str); free(str); // 记得释放动态内存 } return 0; }
额外提醒
- 直接使用
scanf("%c")时要注意输入缓冲区的换行符,可能需要先用getchar()清空。 - 永远不要使用未初始化的指针进行写操作,这是C语言中最常见的bug来源之一。
内容的提问来源于stack exchange,提问作者deadLock
相关产品推荐
相关产品推荐

