如何将文件逐行读取到C语言struct中?解决姓名含空格的读取问题
哈哈,这个坑我刚踩过不久!普通的scanf/fscanf默认把空格、制表符这些空白符当作变量分隔符,所以会直接把Marco塞进name,Beno塞进surname,完全不符合你要把前两个词合并成name的需求。下面给你两个靠谱的解决思路,亲测好用:
方法1:先读整行再拆分(更稳妥)
这种方法先把文件的整行内容读到缓冲区,再用sscanf拆分出需要的字段,能避免因文件换行格式不一致导致的问题:
#include <stdio.h> #include <string.h> struct person { char name[15]; char surname[15]; int age; }; int main() { FILE *fp = fopen("file.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } struct person p; char line_buf[100]; // 定义足够大的缓冲区容纳整行内容 // 逐行读取文件 while (fgets(line_buf, sizeof(line_buf), fp) != NULL) { char first_name[15], middle_name[15]; // 拆分出前两个名字、姓氏、年龄 if (sscanf(line_buf, "%14s %14s %14s %d", first_name, middle_name, p.surname, &p.age) == 4) { // 把前两个名字拼接成完整的name,用snprintf避免缓冲区溢出 snprintf(p.name, sizeof(p.name), "%s %s", first_name, middle_name); // 这里可以添加处理逻辑,比如打印或存储结构体 printf("Name: %s | Surname: %s | Age: %d\n", p.name, p.surname, p.age); } } fclose(fp); return 0; }
关键说明:
fgets保证读取完整的一行内容,不会被中间的空格打断;sscanf的%14s限制了每个字符串最多读取14个字符(留1个位置给字符串终止符\0),避免缓冲区溢出;snprintf安全地拼接两个名字到person.name,如果拼接后的长度超过name的上限,会自动截断,不会导致内存越界。
方法2:直接用格式化读取(更简洁)
如果你的文件格式非常规整(每组固定是「名+中间名+姓+年龄」的四元素结构),可以直接用fscanf一次性读取四个字段,再拼接前两个:
#include <stdio.h> #include <string.h> struct person { char name[15]; char surname[15]; int age; }; int main() { FILE *fp = fopen("file.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } struct person p; char first_name[15], middle_name[15]; // 循环读取每组四元素 while (fscanf(fp, "%14s %14s %14s %d", first_name, middle_name, p.surname, &p.age) == 4) { snprintf(p.name, sizeof(p.name), "%s %s", first_name, middle_name); printf("Name: %s | Surname: %s | Age: %d\n", p.name, p.surname, p.age); } fclose(fp); return 0; }
关键说明:
- 这种方法跳过了整行读取的步骤,直接从文件流中按格式提取字段,代码更简洁;
- 同样用
%14s和snprintf保证内存安全,避免溢出问题; - 注意如果文件中有空行或格式不规整的内容,
fscanf可能会读取失败,所以适合格式严格固定的场景。
额外提醒:
如果你的需求中「名字部分」可能有更多空格(比如三个词的名字),可以调整拆分逻辑,比如用strtok按空格分割后,把前N个词合并成name,最后一个词作为surname,不过你的场景里是固定前两个词,所以上面的方法完全够用。
内容的提问来源于stack exchange,提问作者Wojciech Sowiński




