C语言中如何让fscanf读取数字的循环在到达行尾时停止?
问题根源
你原来的逻辑跑不通核心是两个层面的问题:
fscanf使用%i格式读取整数时,会自动跳过所有前导空白字符,包括空格、换行符、制表符,换行符根本不会被当成整数内容读入,所以你写的new->data != '\n'终止条件永远触发不了,会直接跨到下一行继续读。- 你贴的原代码本身还有几个会直接崩溃的bug:
- 遍历找链表尾节点的循环会把
temp指针走到NULL,后续访问temp->next会直接触发段错误 new变量定义在do循环的内部块中,while判断条件的作用域访问不到这个变量- 没有检查
fscanf、malloc的返回值,一旦文件读结束或者内存分配失败会直接出现野指针。
- 遍历找链表尾节点的循环会把
推荐实现方式
最稳妥、逻辑最清晰的方案是先把整行内容一次性读入内存缓冲区,再在缓冲区内部解析当前行的所有数字,天然实现行级隔离,读完一行的所有数字就自动退出内层循环,外层循环直接处理下一行即可,完全不需要手动在文件流里判断换行位置。
具体实现代码参考:
#include <stdio.h> #include <stdlib.h> #define LINE_BUF_MAX 102400 // 根据单行最大数字长度调整,足够存下一行所有内容即可 // 链表节点结构定义 typedef struct node { int data; struct node *next; struct node *prev; } node; // 链表尾插辅助函数,避免每次插节点都从头遍历,提升大数量场景下的效率 void append_node(node **head, node **tail, int data) { node *new_node = (node*)malloc(sizeof(node)); new_node->data = data; new_node->next = NULL; new_node->prev = *tail; if (*head == NULL) { *head = new_node; *tail = new_node; return; } (*tail)->next = new_node; *tail = new_node; } int main() { FILE *fp = fopen("你的数字文件路径", "r"); if (!fp) { perror("文件打开失败"); return 1; } const int N = 100; // 按你实际需要读取的总行数修改 node *list_arr[N]; // 链表数组,每个索引对应一行的链表头节点 char line_buf[LINE_BUF_MAX]; for (int i = 0; i < N; i++) { node *head = NULL; node *tail = NULL; // 先把整行内容读入缓冲区 if (fgets(line_buf, LINE_BUF_MAX, fp) == NULL) break; // 文件提前读完直接退出 char *pos = line_buf; int num, offset; // 从缓冲区里逐个读取空格分隔的数字,直到行尾 while (sscanf(pos, "%i%n", &num, &offset) == 1) { append_node(&head, &tail, num); pos += offset; // 移动读取指针,跳过已经读完的内容 } list_arr[i] = head; // 当前行链表存入数组对应索引 } fclose(fp); // 后续你的业务处理逻辑 return 0; }
代码里用到的%n是sscanf的格式控制符,作用是返回本次格式匹配从缓冲区起始位置一共读取了多少个字符,靠这个值移动读取指针,就能依次把一行里所有空格分隔的数字读出来,整行读完后内层循环自然终止,不会跨行读取下一行的内容。
如果你非要直接在文件流上不读整行实现,需要每次读取整数前先逐个预读字符判断是不是换行,遇到换行就把字符回退到流里再退出内层循环,但这种实现需要处理很多边界情况(比如行尾多余空格、空行),出错概率远高于先读整行的方案,不推荐使用。
内容的提问来源于stack exchange,提问作者Snips
相关产品推荐
相关产品推荐

