C 读取文本文件后,结果显示不正确
我编写了一个程序,从文本文件中每行读取四个变量(三个字符串和一个字符)。但是,当我显示变量时,每行末尾会弹出一个意外字符。(我已经确保变量的长度足够大) 为什么会这样?(还是缓冲区溢出?) 文本文件内容: M0001 Cool Name F 123-456789 M0002 Name Cool M 987-654321 M0001冷名称F 123-456789 M0002名称酷M 987-654321 代码:C 读取文本文件后,结果显示不正确,c,string,text-files,stdio,C,String,Text Files,Stdio,我编写了一个程序,从文本文件中每行读取四个变量(三个字符串和一个字符)。但是,当我显示变量时,每行末尾会弹出一个意外字符。(我已经确保变量的长度足够大) 为什么会这样?(还是缓冲区溢出?) 文本文件内容: M0001 Cool Name F 123-456789 M0002 Name Cool M 987-654321 M0001冷名称F 123-456789 M0002名称酷M 987-654321 代码: #包括 #包括 int main(){ 文件*文本; 字符id[6],姓名[101],
#包括
#包括
int main(){
文件*文本;
字符id[6],姓名[101],性别,联系人[13];
text=fopen(“test.txt”、“r”);
while(fscanf(文本,“%s%[^\n]s%c%s\n”、id、姓名和性别、联系人)!=EOF)
printf(“%s%s%c%s\n”,id、姓名、性别、联系人);
fclose(文本);
返回0;
}
我期望的结果是:
M0001 Cool Name F 123-456789
M0002 Name Cool M 987-654321
M0001冷名称F 123-456789
M0002名称酷M 987-654321
我得到的是:
M0001 Cool Name F 123-456789 1⁄4
M0002 Name Cool M 987-654321 1⁄4
M0001冷名称F 123-456789 1⁄4
M0002名称冷却M 987-654321 1⁄4
%[^\n]s
从这一点开始,会吃掉所有东西,并将其放入name
中。因此,仅填写id
和name
<代码>性别和联系人
具有来自程序堆栈的“随机”内容(因为它们未初始化)
意外地,您的堆栈在gender
+contact
中有1/4
在我的计算机上,程序崩溃。在调用
fscanf()
时,格式字符串“%s%[^\n]s%c%s\n”不正确
#include <stdio.h> // fopen(), fclose(), fscanf(), perror(), printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
enum{
MAX_ID_LEN = 6,
MAX_NAME_LEN = 20,
MAX_CONTACT_LEN = 13
};
int main( void )
{
char id[ MAX_ID_LEN ];
char firstname[ MAX_NAME_LEN ];
char lastname[ MAX_NAME_LEN ];
char gender;
char contact[ MAX_CONTACT_LEN ];
FILE *text = fopen("test.txt", "r");
if( !text )
{
perror( "fopen to read 'test.txt' failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while (5 == fscanf(text, "%5s %19s %19s %c %12s",
id, firstname, lastname, &gender, contact) )
{
printf("%s %s %s %c %s\n",
id, firstname, lastname, gender, contact);
}
fclose(text);
return 0;
}
fscanf()的返回值
fopen()
中的任何错误,如果返回错误,则正确输出错误消息和文本,说明系统认为函数无法执行的原因stderr
fscanf()
和printf()
enum
语句将“神奇”数字替换为有意义的名称#include <stdio.h> // fopen(), fclose(), fscanf(), perror(), printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
enum{
MAX_ID_LEN = 6,
MAX_NAME_LEN = 20,
MAX_CONTACT_LEN = 13
};
int main( void )
{
char id[ MAX_ID_LEN ];
char firstname[ MAX_NAME_LEN ];
char lastname[ MAX_NAME_LEN ];
char gender;
char contact[ MAX_CONTACT_LEN ];
FILE *text = fopen("test.txt", "r");
if( !text )
{
perror( "fopen to read 'test.txt' failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while (5 == fscanf(text, "%5s %19s %19s %c %12s",
id, firstname, lastname, &gender, contact) )
{
printf("%s %s %s %c %s\n",
id, firstname, lastname, gender, contact);
}
fclose(text);
return 0;
}
#包括//fopen()、fclose()、fscanf()、perror()、printf()
#包括//退出(),退出失败
枚举{
最大ID长度=6,
最大名称长度=20,
最大触点长度=13
};
内部主(空)
{
字符id[MAX_id_LEN];
char firstname[MAX_NAME_LEN];
char lastname[MAX_NAME_LEN];
性别;
字符触点[最大触点长度];
FILE*text=fopen(“test.txt”、“r”);
如果(!text)
{
perror(“fopen读取'test.txt'失败”);
退出(退出失败);
}
//否则,fopen成功了
而(5==fscanf(文本,“%5s%19s%19s%c%12s”,
id、名、姓和性别、联系人)
{
printf(“%s%s%s%c%s\n”,
身份证、名、姓、性别、联系人);
}
fclose(文本);
返回0;
}
由于您姓名中以空格分隔的单词的数量显然是可变的,因此您只能使用%[^\n]s
获取“尽可能多的”–但这也会消耗掉以下所有相关数据。一个快速的解决方案是重新设计输入格式并将名称放在末尾;然后,您的fscanf
参数将是:
"%s %c %s %s\n", id, &gender, contact, name
或者,重写代码以使用更少的fscanf和更多的“手动”解析:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
FILE *text;
char id[6], name[101], gender, contact[13];
char *lookback;
int result;
unsigned int line_number = 0;
text = fopen ("test.txt", "r");
if (text == NULL)
{
printf ("file not found!\n");
return EXIT_FAILURE;
}
do
{
result = fscanf(text, "%s %[^\n]s\n", id, name);
line_number++;
if (result == EOF)
break;
if (result != 2)
{
printf ("error in data file on line %u (expected at least 2 items)\n", line_number);
break;
}
/* at this point, 'name' also contains 'gender' and 'contact' */
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) > 12)
{
printf ("error in data file on line %u (expected 'contact')\n", line_number);
break;
}
/* lookback+1 because lookback itself points to the space */
strcpy (contact, lookback+1);
/* cut off at lookback */
*lookback = 0;
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) != 1)
{
printf ("error in data file on line %u (expected 'gender')\n", line_number);
break;
}
/* lookback now points to the space before the gender */
gender = toupper(lookback[1]);
if (gender != 'F' && gender != 'M')
{
printf ("error in data file on line %u (expected 'M' or 'F')\n", line_number);
break;
}
/* cut off again at lookback; now name is complete */
*lookback = 0;
printf ("%s %s %c %s\n", id, name, gender, contact);
} while (1);
fclose(text);
return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
内部主(空)
{
文件*文本;
字符id[6],姓名[101],性别,联系人[13];
字符*回望;
int结果;
无符号整数行数=0;
text=fopen(“test.txt”、“r”);
if(text==NULL)
{
printf(“未找到文件!\n”);
返回退出失败;
}
做
{
结果=fscanf(文本,“%s%[^\n]s\n”,id,名称);
行数++;
如果(结果==EOF)
打破
如果(结果!=2)
{
printf(“第%u行的数据文件中出现错误(至少需要2项)”,第\u行编号;
打破
}
/*此时,“姓名”还包含“性别”和“联系人”*/
lookback=strrchr(名称“”);
如果(回望==NULL | | strlen(回望+1)>12)
{
printf(“第%u行数据文件中的错误(应为“联系人”)\n”,第\u行编号);
打破
}
/*lookback+1,因为lookback本身指向空间*/
strcpy(联系人,回望+1);
/*向后看时被切断*/
*回望=0;
lookback=strrchr(名称“”);
如果(回望==NULL | | strlen(回望+1)!=1)
{
printf(“第%u行数据文件错误(应为“性别”)\n”,第\u行编号);
打破
}
/*现在回头看,指向性别之前的空间*/
性别=toupper(回顾[1]);
如果(性别!='F'和性别!='M')
{
printf(“第%u行数据文件错误(应为'M'或'F')\n”,第\u行编号);
打破
}
/*回望时再次切断;现在名称已完成*/
*回望=0;
printf(“%s%s%c%s\n”,id、姓名、性别、联系人);
}而(1),;
fclose(文本);
返回退出成功;
}
这种方法确实有几个优点