学生游戏项目:读取INI文件赋值变量时strtok及结构体赋值困惑
解决INI文件读取与
strtok使用问题 嘿,我来帮你搞定这个学校项目的INI读取问题!你当前的代码存在几个逻辑错误,而且对strtok的用法理解不到位,导致没法把INI里的值正确赋值给CONFIG结构体。咱们一步步来修复:
先梳理你代码里的核心问题
- 无意义的
for循环:for (int i = 0; i != '\0'; i++)这个循环完全没用,i是整数,和字符'\0'比较会导致逻辑混乱,甚至无限循环 - 只提取了键,没处理值:你用
strtok拿到了xdim这类键,但没继续提取后面的20这类值,更没把值赋值给结构体成员 - 结构体未初始化:你最后返回的
CONFIG config;是未赋值的,所以成员都是随机值或者0(取决于编译器) - 未处理注释和无效行:INI里的注释行(以
;开头)和空行应该跳过,不然会干扰解析 - 文件打开失败后未终止程序:如果
fopen失败,后续操作fp会导致未定义行为 - 非法访问
token:循环外的printf("%d", token[0]);可能在token为NULL时崩溃
搞懂strtok的工作原理
strtok是用来分割字符串的工具,规则很简单:
- 第一次调用:传入要分割的字符串和分隔符,它会找到第一个分隔符,把分隔符换成
'\0',返回分割后的第一个子串(键) - 后续调用:传入
NULL和分隔符,它会从上次分割的位置继续,返回下一个子串(值)
注意:
strtok会修改原字符串,所以如果需要保留原字符串,要先复制一份
修正后的完整代码
read_from_config.c
#include "read_from_config.h" #include <string.h> #include <stdlib.h> #include <stdio.h> CONFIG read_config(char *argv[]) { char str[MAXSTR]; FILE *fp = NULL; char *filename = argv[1]; char *token; char *value_str; CONFIG config = {0}; // 初始化结构体所有成员为0 // 打开配置文件 fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Não foi possível abrir ficheiro de configuração.\n"); fprintf(stderr, "Modo de uso: ./program_name config.ini\n"); exit(EXIT_FAILURE); // 打开失败直接退出,避免后续错误 } // 逐行读取文件 while (fgets(str, MAXSTR, fp) != NULL) { // 跳过空行和注释行(以;开头) if (str[0] == ';' || str[0] == '\n' || str[0] == '\r') { continue; } // 查找等号,找不到则跳过该行 char *equal_sign = strpbrk(str, "="); if (!equal_sign) { continue; } // 分割键:从开头到等号 token = strtok(str, "="); if (!token) { continue; } // 去掉键末尾的空格(比如如果有"xdim = 20"这种情况) token[strcspn(token, " \t")] = '\0'; // 分割值:从等号后面到换行/空格 value_str = strtok(NULL, "\n \t"); if (!value_str) { continue; } // 将值转换为unsigned int,赋值给对应结构体成员 unsigned int value = strtoul(value_str, NULL, 10); if (strcmp(token, "xdim") == 0) { config.xdim = value; } else if (strcmp(token, "ydim") == 0) { config.ydim = value; } else if (strcmp(token, "nzombies") == 0) { config.nzombies = value; } else if (strcmp(token, "nhumans") == 0) { config.nhumans = value; } else if (strcmp(token, "nzplayers") == 0) { config.nzplayers = value; } else if (strcmp(token, "nhplayers") == 0) { config.nhplayers = value; } else if (strcmp(token, "maxturns") == 0) { config.turns = value; // 注意INI里是maxturns,结构体里是turns,对应上 } } fclose(fp); // 记得关闭文件! return config; }
关键修复点解释
- 结构体初始化:
CONFIG config = {0};确保所有成员初始为0,避免随机值 - 跳过无效行:判断行首是否为
;或换行,直接跳过注释和空行 - 键值分割:先用
strtok拿键,再用strtok(NULL, "\n \t")拿值,同时去掉值的换行和空格 - 安全转换数值:用
strtoul把字符串转成unsigned int,比atoi更适合无符号类型 - 键值匹配:用
strcmp判断键名,把对应的值赋值给结构体成员(注意INI里的maxturns对应结构体的turns) - 关闭文件:读取完成后关闭文件,避免资源泄漏
测试代码(可选)
你可以在主函数里加一段测试,验证读取是否正确:
#include "read_from_config.h" #include <stdio.h> int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Modo de uso: ./program_name config.ini\n"); return 1; } CONFIG cfg = read_config(argv); printf("xdim: %u\n", cfg.xdim); printf("ydim: %u\n", cfg.ydim); printf("nzombies: %u\n", cfg.nzombies); printf("nhumans: %u\n", cfg.nhumans); printf("nzplayers: %u\n", cfg.nzplayers); printf("nhplayers: %u\n", cfg.nhplayers); printf("turns: %u\n", cfg.turns); return 0; }
这样运行后就能看到INI里的所有值都正确读取到结构体里啦!
内容的提问来源于stack exchange,提问作者Rui Martins
相关产品推荐
相关产品推荐

