C语言结构体存储姓名后格式化打印无输出问题排查
问题描述
我编写了一个程序,从标准输入读取按换行分隔的名(firstName)和姓(lastName),存入结构体数组的字符数组中。读取存储环节看似正常,但按<lastName>, <firstName>格式打印时出现异常:使用printf("%s, %s",people[0].lastName, people[0].firstName);无任何输出;但将两个字符串分开换行打印,或用puts打印时却能正常输出。注释掉removeNewline()函数后,格式化打印恢复正常,但字符串末尾会带有换行符,无法达到预期输出格式。
完整代码如下:
#include <stdio.h> #include <string.h> #define MAX_STRING_LENGTH 100 #define MAX_PEOPLE 42 struct Person{ char firstName [MAX_STRING_LENGTH]; char lastName[MAX_STRING_LENGTH]; }; void removeNewline(char * string){ for(int i = 0; string[i] != '\0'; i++){ if(string[i] == '\n'){ string[i] = '\0'; } } } int parseData(struct Person * people){ int peopleCounter; for(peopleCounter = 0; peopleCounter < MAX_PEOPLE; peopleCounter++){ char firstName[MAX_STRING_LENGTH]; char lastName[MAX_STRING_LENGTH]; if(fgets(firstName,MAX_STRING_LENGTH,stdin) == NULL){ break; } fgets(lastName,MAX_STRING_LENGTH,stdin); removeNewline(firstName); removeNewline(lastName); strcpy(people[peopleCounter].firstName,firstName); strcpy(people[peopleCounter].lastName,lastName); } return peopleCounter; } int main(int argc, char *argv[]){ struct Person people [MAX_PEOPLE]; parseData(people); //PROBLEM printf("%s, %s",people[0].firstName, people[0].lastName); for(int i = 0; i < 2; i++){ printperson(people, i); } }
运行命令:./main <people.txt,people.txt示例内容:
George Washington Thomas Jefferson
预期输出:
Washington, George Jefferson, Thomas
问题原因与修复方案
1. 核心问题:removeNewline未处理Windows风格换行符
如果你的文本文件是Windows格式,每行末尾是\r\n(回车+换行),原函数只将\n替换为\0,但\r会留在字符串末尾。当printf输出时,\r会让光标跳回行首,后续的, %s会覆盖之前的输出,导致看起来没有内容。
同时原函数用循环遍历的方式效率低,改用strchr定位换行符更简洁可靠。修改后的removeNewline函数:
void removeNewline(char * string){ char *newline = strchr(string, '\n'); if (newline != NULL) { // 处理Windows风格的\r\n换行 if (newline > string && *(newline - 1) == '\r') { *(newline - 1) = '\0'; } else { *newline = '\0'; } } }
2. 打印参数顺序错误
预期输出是姓, 名,但原代码中printf的参数顺序写反了,改成:
printf("%s, %s\n", people[0].lastName, people[0].firstName);
加上\n保证输出换行,符合预期格式。
3. 补全缺失的printperson函数
原代码调用了未定义的printperson函数,会导致编译错误,补全该函数:
void printperson(struct Person *people, int index) { printf("%s, %s\n", people[index].lastName, people[index].firstName); }
4. 完善输入读取的异常处理
读取lastName时也需检查fgets的返回值,避免文件行数为奇数时出错:
if(fgets(firstName,MAX_STRING_LENGTH,stdin) == NULL){ break; } if(fgets(lastName,MAX_STRING_LENGTH,stdin) == NULL){ break; }
修复后的完整代码
#include <stdio.h> #include <string.h> #define MAX_STRING_LENGTH 100 #define MAX_PEOPLE 42 struct Person{ char firstName[MAX_STRING_LENGTH]; char lastName[MAX_STRING_LENGTH]; }; void removeNewline(char *string){ char *newline = strchr(string, '\n'); if (newline != NULL) { if (newline > string && *(newline - 1) == '\r') { *(newline - 1) = '\0'; } else { *newline = '\0'; } } } void printperson(struct Person *people, int index) { printf("%s, %s\n", people[index].lastName, people[index].firstName); } int parseData(struct Person *people){ int peopleCounter; for(peopleCounter = 0; peopleCounter < MAX_PEOPLE; peopleCounter++){ char firstName[MAX_STRING_LENGTH]; char lastName[MAX_STRING_LENGTH]; if(fgets(firstName, MAX_STRING_LENGTH, stdin) == NULL){ break; } if(fgets(lastName, MAX_STRING_LENGTH, stdin) == NULL){ break; } removeNewline(firstName); removeNewline(lastName); strcpy(people[peopleCounter].firstName, firstName); strcpy(people[peopleCounter].lastName, lastName); } return peopleCounter; } int main(int argc, char *argv[]){ struct Person people[MAX_PEOPLE]; int count = parseData(people); printf("%s, %s\n", people[0].lastName, people[0].firstName); for(int i = 0; i < count; i++){ printperson(people, i); } return 0; }
运行后即可得到预期输出:
Washington, George Washington, George Jefferson, Thomas
(注:main中的单独打印和循环打印会重复第一行,可根据需求移除其中一个)
内容的提问来源于stack exchange,提问作者startler03
相关产品推荐
相关产品推荐

