C语言字符串解析程序故障:仅重复输出最后一条输入数据问题排查
C语言数据存储与输出问题排查解决
需求说明
- 接收用户输入的多条格式一致的字符串,示例:
String 1 : Voltage 230,Current 3.14,PF 0.91,KW 1889.91
String 2 : Voltage 240,Current 2.98,PF 0.84,KW 1889.92 - 按逗号拆分字符串,再将子串按空格拆分,提取对应参数值并整理为表格形式
- 过滤规则:若Voltage<230 且 PF<0.85,则不记录该条数据
问题描述
现有C语言代码运行后,仅重复输出最后一条输入的数据,无法正确展示所有符合条件的输入数据,需排查并解决该问题。
现有代码及输入输出情况
现有代码
#include <stdio.h> #include <string.h> void main() { char str[55]; char *vol[5], *cur[5], *pf[5], *kw[5]; int i, k = 0, m; char delim1[] = ","; for (i = 0; i < 5; i++) { printf("Enter value : "); gets(str); char *tk1 = strtok(str, delim1); while (tk1 != NULL) { if (tk1[0] == 'v') { vol[k] = strchr(tk1, ' ') + 1; } else if (tk1[0] == 'c') { cur[k] = strchr(tk1, ' ') + 1; } else if (tk1[0] == 'p') { pf[k] = strchr(tk1, ' ') + 1; } else if (tk1[0] == 'k') { kw[k] = strchr(tk1, ' ') + 1; } tk1 = strtok(NULL, delim1); } k++; } printf("Voltage \tCurrent \t PF\t\t\t kW\n"); for (m = 0; m < 5; m++) { printf("%s\t\t\t%s\t\t%s\t\t%s\n", vol[m], cur[m], pf[m], kw[m]); } return 0; }
预期输出
Enter value : Voltage 230,Current 7.89,PF 0.91,KW 1289.33 (第1次输入) Enter value : Voltage 230,Current 3.20,PF 0.84,KW 1100.32 (第2次输入) Enter value : Voltage 240,Current 4.78,PF 0.91,KW 1278.87 (第3次输入) Enter value : Voltage 230,Current 7.45,PF 0.91,KW 1945.34 (第4次输入) Enter value : Voltage 210,Current 5.13,PF 0.81,KW 998.33 (第5次输入) Voltage Current PF kW 210 5.13 0.81 998.33 (最新输入的第5条数据) 230 7.45 0.91 1945.34 240 4.78 0.91 1278.87 230 3.20 0.84 1100.32 230 7.89 0.91 1289.33 (最早输入的第1条数据)
实际输出
Enter value : Voltage 230,Current 7.89,PF 0.91,KW 1289.33 Enter value : Voltage 230,Current 3.20,PF 0.84,KW 1289.32 Enter value : Voltage 240,Current 4.78,PF 0.91,KW 1278.87 Enter value : Voltage 230,Current 7.45,PF 0.91,KW 1945.34 Enter value : Voltage 210,Current 5.13,PF 0.81,KW 998.33 Voltage Current PF kW 210 5.13 0.81 998.33 210 5.13 0.81 998.33 210 5.13 0.81 998.33 210 5.13 0.81 998.33 210 5.13 0.81 998.33
问题分析
- 指针指向复用内存:代码中
vol、cur、pf、kw都是指针数组,存储的是指向局部数组str内部的地址。每次循环输入时,str的内容会被新输入覆盖,所有指针始终指向同一块内存空间,最终全部指向最后一次输入的内容。 - 函数安全性问题:使用已废弃的
gets函数,存在缓冲区溢出风险。 - 未实现过滤规则:完全忽略了需求中“Voltage<230且PF<0.85时不记录”的要求。
- 输出顺序不符预期:当前代码按输入顺序输出,而预期是从最新到最旧逆序输出。
解决方法
- 存储数值而非指针:用结构体存储每条数据的数值,避免指针指向被覆盖的内存。
- 替换不安全函数:用
fgets替代gets,并处理换行符。 - 实现过滤逻辑:提取数据后判断是否符合过滤条件,仅保留有效数据。
- 调整输出顺序:逆序遍历有效数据,实现从最新到最旧的输出。
修正后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> // 定义结构体存储每条电力数据 typedef struct { float voltage; float current; float pf; float kw; } PowerData; int main() { char str[55]; PowerData data[5]; int valid_count = 0; // 记录符合条件的数据条数 char delim1[] = ","; for (int i = 0; i < 5; i++) { printf("Enter value : "); // 使用fgets读取输入,处理异常情况 if (fgets(str, sizeof(str), stdin) == NULL) { break; } // 去掉输入末尾的换行符 str[strcspn(str, "\n")] = '\0'; char *tk1 = strtok(str, delim1); PowerData temp_data = {0}; while (tk1 != NULL) { // 忽略大小写匹配参数类型 switch(tolower(tk1[0])) { case 'v': temp_data.voltage = atof(strchr(tk1, ' ') + 1); break; case 'c': temp_data.current = atof(strchr(tk1, ' ') + 1); break; case 'p': temp_data.pf = atof(strchr(tk1, ' ') + 1); break; case 'k': temp_data.kw = atof(strchr(tk1, ' ') + 1); break; default: break; } tk1 = strtok(NULL, delim1); } // 应用过滤规则:仅保留不符合Voltage<230且PF<0.85的数据 if (!(temp_data.voltage < 230 && temp_data.pf < 0.85)) { data[valid_count++] = temp_data; } } // 逆序输出有效数据(最新输入在前) printf("\nVoltage\t\tCurrent\t\tPF\t\tkW\n"); for (int m = valid_count - 1; m >= 0; m--) { printf("%.2f\t\t%.2f\t\t%.2f\t\t%.2f\n", data[m].voltage, data[m].current, data[m].pf, data[m].kw); } return 0; }
代码说明
- 用结构体
PowerData存储每条数据的数值,彻底解决指针指向复用内存的问题。 - 替换
gets为fgets,并通过strcspn去除换行符,提升输入安全性。 - 实现过滤规则,自动跳过不符合条件的数据。
- 逆序遍历有效数据,满足从最新到最旧的输出要求。
- 使用
atof将字符串转为浮点型,便于数值判断和格式化输出。
内容的提问来源于stack exchange,提问作者Yatharth Sharma
相关产品推荐
相关产品推荐

