使用strtok分割字符串并存入union时,前序货币名称被异常覆盖的问题
问题:使用Union存储货币数据时,后续输入覆盖之前的名称
我写了一个程序,每行输入货币名称和数值,想把数据存入coin联合数组里。但运行时发现,第一行输入能正确存入,但输入第二行后,之前存的货币名称会被错误修改。
原代码
#include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <math.h> int main() { int number_coin, index; union coin { char name[20]; float value; float amount; }; union coin coins[1000]; scanf("%d", &number_coin); getchar(); for (index = 0; index < number_coin; index++) { char input[40]; fgets(input, 40, stdin); input[strcspn(input, "\n")] = 0; // delete \n in end of input string char *token = strtok(input, " "); while (token != NULL) { strcpy(coins[index].name, token); token = strtok(NULL, " "); coins[index].value = atof(token); token = strtok(NULL, " "); } } return 0; }
输入示例
2 jibcoin 2 bitcoin 5
问题原因
核心问题是Union的内存共享特性:Union中的所有成员共用同一块内存空间,同一时间只有一个成员的数据是有效的。你在循环中先给name赋值,紧接着又给value赋值,这会直接覆盖name所在的内存区域,导致第一次存储的货币名称被破坏。
比如第一次循环中,coins[0].name存入jibcoin后,马上给coins[0].value赋值2,此时name的内存已经被value的二进制数据覆盖;第二次循环操作coins[1]时,coins[0]的名称已经因为内存共享被破坏,看起来像是被第二行输入修改了。
解决方案
你需要同时存储名称和数值,这种场景应该用**结构体(struct)**替代联合(union)——结构体的每个成员拥有独立的内存空间,不会互相覆盖。
修改后的代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { int number_coin, index; // 将union改为struct,成员独立分配内存 struct coin { char name[20]; float value; float amount; }; struct coin coins[1000]; scanf("%d", &number_coin); getchar(); for (index = 0; index < number_coin; index++) { char input[40]; fgets(input, 40, stdin); input[strcspn(input, "\n")] = 0; // 去除换行符 char *token = strtok(input, " "); if (token != NULL) { strcpy(coins[index].name, token); token = strtok(NULL, " "); if (token != NULL) { coins[index].value = atof(token); } } } // 验证存储结果 for (index = 0; index < number_coin; index++) { printf("货币名称:%s,数值:%.1f\n", coins[index].name, coins[index].value); } return 0; }
额外优化说明
- 移除了无意义的头文件(
ctype.h、math.h) - 把原代码的
while循环改为if判断,避免strtok返回NULL时访问非法内存 - 添加了打印验证逻辑,方便确认数据是否正确存储
内容的提问来源于stack exchange,提问作者Aghmehdi
相关产品推荐
相关产品推荐

