C语言用fscanf读取JSON整数数组遇返回-1的问题排查与解决
问题分析与解决方案
咱们一步步拆解问题出在哪,然后搞定它。你遇到的fscanf返回-1的核心原因,是格式字符串太死板,和JSON数组的灵活格式不匹配。JSON数组的写法很灵活:[后面可能直接跟数字(比如[36,35]),逗号前后可能有0个或多个空格,甚至换行分隔,但你写的" [ %d , "要求必须严格匹配[ (空格)、整数、,(空格)——只要实际文本和这个格式有一点出入,fscanf就会匹配失败,返回EOF(也就是-1)。
正确的处理思路
我们只需要做两件核心事:
- 跳过开头的方括号
[以及任意数量的空白字符(空格、制表符、换行) - 循环读取整数,同时自动跳过整数后面的逗号和空白字符
完整实现代码
结合你的结构体定义,这里给出一个可运行的示例:
#include <stdio.h> #include <stdlib.h> typedef struct { int *data; unsigned int len; } IntArray; IntArray read_json_int_array(FILE *f) { IntArray arr = {NULL, 0}; int num; size_t capacity = 4; // 初始分配的容量,可根据需求调整 // 第一步:跳过开头的[和所有空白字符(空格、制表符、换行) // %*[xxx] 表示跳过所有属于xxx集合的字符,*代表不存储这些字符 if (fscanf(f, "%*[ \t\n[]]") == EOF) { return arr; // 文件开头没有找到数组标记,直接返回空数组 } // 初始化动态数组 arr.data = malloc(capacity * sizeof(int)); if (!arr.data) { perror("malloc failed"); return arr; } // 第二步:循环读取整数,同时跳过后面的逗号和空白 // %d 读取整数,%*[ \t\n,] 跳过整数后的空白和逗号 while (fscanf(f, "%d%*[ \t\n,]", &num) == 1) { // 数组容量不足时,自动扩容(每次翻倍) if (arr.len >= capacity) { capacity *= 2; int *temp = realloc(arr.data, capacity * sizeof(int)); if (!temp) { perror("realloc failed"); free(arr.data); arr.data = NULL; arr.len = 0; return arr; } arr.data = temp; } arr.data[arr.len++] = num; } // 最后跳过结尾的]和空白字符,确保文件指针位置正确 fscanf(f, "%*[ \t\n]]"); // 可选:将数组内存缩小到实际需要的大小,避免浪费 int *temp = realloc(arr.data, arr.len * sizeof(int)); if (temp) { arr.data = temp; } return arr; } // 测试用例 int main() { FILE *f = fopen("test.json", "r"); if (!f) { perror("无法打开文件"); return 1; } IntArray arr = read_json_int_array(f); fclose(f); printf("读取到 %u 个整数:\n", arr.len); for (unsigned int i = 0; i < arr.len; i++) { printf("%d ", arr.data[i]); } printf("\n"); // 记得释放内存 free(arr.data); return 0; }
关键细节解释
%*[ \t\n[]]:这个格式符会跳过所有空格、制表符、换行符以及[,不管这些字符的顺序和数量,完美适配JSON数组开头的各种格式。%d%*[ \t\n,]:先读取整数,然后自动跳过后面的空白(空格、制表符、换行)和逗号,不管逗号前后有没有空格,都能正确读取下一个整数。- 动态扩容:用
realloc实现数组的自动扩容,避免一开始分配过大内存,也不会因为数组长度不够导致溢出。 - 内存优化:最后用
realloc把数组缩小到实际长度,减少内存浪费。
为什么你的原格式会失败?
假设你的JSON数组是[36,35,...]([后面直接跟数字),你的格式字符串" [ %d , "要求[后面必须有一个空格,而实际没有,所以fscanf找不到匹配的内容,直接返回EOF(-1)。即使你的数组是[ 36,35,...],第一个整数后面是36,(没有空格),格式字符串要求36后面必须是,(空格+逗号+空格),同样会匹配失败。
内容的提问来源于stack exchange,提问作者tz35
相关产品推荐
相关产品推荐

