C语言中从STDIN读取字符串存入char*数组为何仅保留最后一行?
问题:C语言getline读取行存入数组后,所有元素显示为最后一行内容
场景重现
输入文件内容:
T4 T2 T1 T1 S9 T5 S1 T1 T1 T1
使用的代码:
char *line = NULL; size_t len = 0; ssize_t lineSize = 0; char* transactions[250]; int i = 0; while((lineSize = getline(&line, &len, stdin)) != -1) { printf("You entered %s, which has %zu chars.\n", line, lineSize - 1); transactions[i] = line; printf("Added in %s\n", transactions[i]); i++; } printf("\n\n"); for (int j = 0; j < i; j++) { printf("transaction[%d] = %s\n", j, transactions[j]); } free(line);
程序输出:
my_shell>./prod 12 2 < inputexample.txt nthreads: 12 id: 2 You entered T4 , which has 3 chars. Added in T4 You entered T2 , which has 3 chars. Added in T2 You entered T1 , which has 3 chars. Added in T1 You entered T1 , which has 3 chars. Added in T1 You entered S9 , which has 3 chars. Added in S9 You entered T5 , which has 3 chars. Added in T5 You entered S1 , which has 3 chars. Added in S1 You entered T1 , which has 3 chars. Added in T1 You entered T1 , which has 3 chars. Added in T1 You entered T1, which has 1 chars. Added in T1 transaction[0] = T1 transaction[1] = T1 transaction[2] = T1 transaction[3] = T1 transaction[4] = T1 transaction[5] = T1 transaction[6] = T1 transaction[7] = T1 transaction[8] = T1 transaction[9] = T1
问题点:while循环中能正确显示每行内容,但后续for循环里所有数组元素都变成了最后一行的内容。
原因分析
核心问题是所有数组元素都指向了同一块内存地址。
getline函数的工作逻辑是:当传入的line指针为NULL时,它会自动分配一块内存存储读取到的行;如果后续读取的行长度不超过已分配的内存大小(len变量记录),它会复用这块内存,直接把新行的内容覆盖进去。
你的代码中,每次循环都把line指针赋值给transactions[i],相当于让数组里的每个元素都指向同一块内存空间。当getline读取下一行时,会覆盖这块内存里的旧内容,最后所有元素自然都指向最后一行的内容。
while循环里能正确显示,是因为每次赋值后立刻打印,此时内存里的内容还没被下一次的getline覆盖。
解决方案
需要为每行内容单独分配内存,把getline读取到的内容复制一份存起来,而不是直接复用line指针。以下两种方法均可实现:
方法1:使用strdup
修改while循环内的赋值语句:
transactions[i] = strdup(line);
strdup会自动分配足够的内存,复制line里的内容并返回新指针。注意最后要逐个释放数组里的每个元素,再释放line。
方法2:手动内存分配
如果环境不支持strdup,可以手动实现内存分配与复制:
// 分配对应大小的内存,lineSize包含换行符和终止符的长度 transactions[i] = malloc(lineSize); if (transactions[i] != NULL) { strcpy(transactions[i], line); }
修改后的完整代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *line = NULL; size_t len = 0; ssize_t lineSize = 0; char* transactions[250]; int i = 0; while((lineSize = getline(&line, &len, stdin)) != -1) { printf("You entered %s, which has %zu chars.\n", line, lineSize - 1); // 复制内容到新分配的内存 transactions[i] = strdup(line); printf("Added in %s\n", transactions[i]); i++; } printf("\n\n"); for (int j = 0; j < i; j++) { printf("transaction[%d] = %s\n", j, transactions[j]); } // 释放数组里的每个元素 for (int j = 0; j < i; j++) { free(transactions[j]); } free(line); return 0; }
修改后,数组里的每个元素都指向独立的内存块,存储各自的行内容,后续遍历就不会出现全部显示最后一行的问题。
内容的提问来源于stack exchange,提问作者Infiniteon
相关产品推荐
相关产品推荐

