C语言停车场终端代码bug:带空格名称的停车场创建异常
终端停车场管理程序Bug排查与优化
异常现象
- 首次创建带空格名称的停车场(如
"park name")时,会抛出Error: invalid capacity错误; - 先创建单单词名称的停车场后,再创建带空格名称的停车场则能成功执行;
- 单独输入
p可正常列出已有停车场。
复现示例
p "park name" 20 1 2 3 Error: invalid capacity. p park 20 1 2 3 Parking lot park successfully created! p "park name" 20 1 2 3 Parking lot park name successfully created! p Existing parking lots: park 20 20 park name 20 20
程序代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 100 // 停车场结构体定义 typedef struct { char name[50]; int capacity; float cost15; float cost15_after1hour; float max_daily_cost; int available_spaces; } ParkingLot; // 存储已创建停车场的全局变量 ParkingLot parkingLots[10]; int num_parkingLots = 0; // 创建新停车场函数 void createParkingLot(char name[], int capacity, float cost15, float cost15_after1hour, float max_daily_cost) { if (num_parkingLots >= 10) { printf("Error: too many parking lots.\n"); return; } // 检查停车场名称是否已存在 for (int i = 0; i < num_parkingLots; i++) { if (strcmp(parkingLots[i].name, name) == 0) { printf("Error: %s already exists.\n", name); return; } } // 检查容量是否合法 if (capacity <= 0) { printf("Error: invalid capacity.\n"); return; } // 检查费用规则是否合法 if (cost15 <= 0 || cost15_after1hour <= cost15 || max_daily_cost <= cost15_after1hour) { printf("Error: invalid cost.\n"); return; } // 创建新停车场 strcpy(parkingLots[num_parkingLots].name, name); parkingLots[num_parkingLots].capacity = capacity; parkingLots[num_parkingLots].cost15 = cost15; parkingLots[num_parkingLots].cost15_after1hour = cost15_after1hour; parkingLots[num_parkingLots].max_daily_cost = max_daily_cost; parkingLots[num_parkingLots].available_spaces = capacity; num_parkingLots++; printf("Parking lot %s successfully created!\n", name); } // 列出已有停车场函数 void listParkingLots() { printf("Existing parking lots:\n"); for (int i = 0; i < num_parkingLots; i++) { printf("%s %d %d\n", parkingLots[i].name, parkingLots[i].capacity, parkingLots[i].available_spaces); } } int main() { char command[20]; char name[50]; int capacity; float cost15, cost15_after1hour, max_daily_cost; printf("p [ <park-name> <capacity> <cost-15> <cost-15-after-1hour> <max-daily-cost> ] - Create parking lot\n"); while (1) { scanf("%s", command); if (strcmp(command, "p") == 0) { char nextChar = getchar(); // 读取"p"后的下一个字符 if (nextChar == '\n') { listParkingLots(); } else { ungetc(nextChar, stdin); // 将未读取的字符放回缓冲区 char str[MAXSIZE]; fgets(str, MAXSIZE, stdin); char *p = strchr(str, '\"'); if (p){ char str_between_quotes[MAXSIZE]; int i = 0; p++; // 指针移动到第一个引号后的字符 while (*p != '\"' && *p != '\n' && *p != '\0') { str_between_quotes[i] = *p; i++; p++; } str_between_quotes[i] = '\0'; // 字符串结尾 strcpy(name,str_between_quotes); } else { sscanf(str, "%s %d %f %f %f", name, &capacity, &cost15, &cost15_after1hour, &max_daily_cost); } createParkingLot(name,capacity,cost15,cost15_after1hour,max_daily_cost); } } else if (strcmp(command, "q") == 0) { break; } else { printf("Invalid command.\n"); } } return 0; }
Bug原因分析
问题根源是未初始化的数值变量:
- 处理带引号名称的分支时,代码仅提取了
name变量,但capacity、cost15等数值变量未被赋值,此时这些变量的值是栈内存中的随机垃圾值; - 首次运行时,
capacity的随机值大概率≤0,触发"invalid capacity"错误; - 创建过单单词名称的停车场后,
sscanf已给这些变量赋值,后续处理带引号名称时,变量保留了之前的有效值,因此能通过校验。
修复方案
修改main函数中带引号名称的处理逻辑,提取名称后继续读取后续参数:
if (p){ char str_between_quotes[MAXSIZE]; int i = 0; p++; // 指针移动到第一个引号后的字符 while (*p != '\"' && *p != '\n' && *p != '\0') { str_between_quotes[i] = *p; i++; p++; } str_between_quotes[i] = '\0'; // 字符串结尾 strcpy(name,str_between_quotes); // 跳过引号后的空白字符,读取剩余参数 while (*p == ' ' || *p == '\t') p++; // 校验参数读取是否成功 if (sscanf(p, "%d %f %f %f", &capacity, &cost15, &cost15_after1hour, &max_daily_cost) != 4) { printf("Error: missing or invalid parameters.\n"); continue; } } else { // 校验单名称场景的参数读取 if (sscanf(str, "%s %d %f %f %f", name, &capacity, &cost15, &cost15_after1hour, &max_daily_cost) != 5) { printf("Error: missing or invalid parameters.\n"); continue; } }
同时在main函数开头初始化所有数值变量,避免垃圾值干扰:
int capacity = 0; float cost15 = 0.0f, cost15_after1hour = 0.0f, max_daily_cost = 0.0f;
代码优化建议
- 移除全局变量:将
parkingLots和num_parkingLots改为main局部变量,通过指针传递给函数,提升代码模块化程度; - 增强参数校验:通过
sscanf返回值判断是否成功读取足够参数,避免非法输入; - 提升输入健壮性:使用
strtok_r(线程安全分割函数)或逐字符解析替代现有逻辑,处理更复杂的输入场景; - 防止缓冲区溢出:用
strncpy替代strcpy,限制复制长度(如strncpy(name, str_between_quotes, sizeof(name)-1); name[sizeof(name)-1] = '\0';); - 标准化错误提示:定义统一的错误信息格式,帮助用户快速定位问题。
内容的提问来源于stack exchange,提问作者baptzera
相关产品推荐
相关产品推荐

