fgets()在文件读取-C中获得了比它应该得到的更多的内容

fgets()在文件读取-C中获得了比它应该得到的更多的内容,c,file,fgets,C,File,Fgets,目前我正在做一个实际的工作来拼贴,我必须从文件中读取数据 文件数据结构为:“id名称性别” 例如: nm0025630 Vikas Anand M nm0418131 Victor Janson M nm0411451 Dick Israel M nm0757820 Leopoldo Salcedo M 问题是它把名字和性别一起读。 感谢您的帮助。fgets(姓名,100,fh)最多读取99个字符,当姓名少于98个字符时,如果之前只有一个空格,则还会读取性别 因为名字可

目前我正在做一个实际的工作来拼贴,我必须从文件中读取数据

文件数据结构为:“id名称性别”

例如:

nm0025630 Vikas Anand M nm0418131 Victor Janson M nm0411451 Dick Israel M nm0757820 Leopoldo Salcedo M 问题是它把名字和性别一起读。 感谢您的帮助。

fgets(姓名,100,fh)最多读取99个字符,当姓名少于98个字符时,如果之前只有一个空格,则还会读取性别

因为名字可能是由几个用空格隔开的单词组成的,一种方法是读取所有的行,然后提取性别

当(!feof(fh)){
之前未进行任何读取时,第一次执行
警告,因此
feof
无法知道文件是否为空,然后是否达到EOF。我鼓励您通过查看读取结果来检测EOF

另外,因为您仅在
if(!feof(fh)){
时保存读取的数据,所以您没有记住最后一行的信息

另请注意,
fgets
保存换行符如果有足够的位置,则使用
fscanf
更为实用

因此,一种方法可以是:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define ACTORS "/tmp/actors"

int main()
{
  FILE * fh = fopen(ACTORS, "r");

  if (!fh) {
    perror("cannot read " ACTORS);
    exit(1);
  }

  char name[100],id[10];

  while (fscanf(fh, "%9s %99[^\n]", id, name) == 2) {
    size_t sz = strlen(name);
    char sex = name[--sz];

    for (;;) {
      if (sz == 0) {
        puts("empty name");
        exit(2);
      }
      if (!isspace((unsigned char) name[--sz]))
        break;
    }

    name[sz+1] = 0;

    /*
    hash_update_node(hash, get_id_num(id) , name, sex);
    count++;
    */
    printf("id='%s', name='%s', sex=%c\n", id, name, sex);
  }

  fclose(fh);
  return 0;
}

文件中的字段似乎由制表符分隔。如果这是正确的,您可以使用
fscanf()
解析文件:

#包括
#包括
int本地_文件(无效){
字符性别,名称[100],id[10];
整数计数=0;
文件*fh=fopen(演员,“r”);
如果(!fh){
出口(1);
}
而(fscanf(“%9[^\t]%*1[\t]%99[^\t]%*1[\t]%c”,id、姓名和性别)==3){
hash_update_节点(hash,get_id_num(id),name,sex);
计数++;
}
返回计数;
}

但是请注意,如果任何字段为空,此代码将失败。

这是因为您给它100字节的空间,所以它在找到行尾时停止。由于名称可以是可变大小的,并且如果项目允许,请在每行的数据项之间使用分隔符,例如制表符、逗号或其他字符,因此每次读取一整行将时间输入到足够大的缓冲区中,然后使用
strtok
分隔行中的每个字段。您不必使用fgets()。您可以使用fscanf()和转换说明符来限制和确定正在读取的数据。我不能使用fscanf()因为单词的数量并不总是相同的。有些单词有一个单词,另一个有4。
fgetc(sex)
不正确。应该是:
sex=fgetc(fh)
。您应该注意编译器给您的警告。还请注意,.@Mabs2001所以使用
fgets
读取100,那么性别将是其中的最后一个字符(不单独读取),并从名称中删除Hi bruno之前的最后一个字符和空格。在文件中,字段似乎由制表符分隔。Hi@chqrlie,如果我们确信可以在
fscanf
格式中使用这种方式,就不必为性做任何事情。无论如何,即使使用制表符而不是
'
我的答案也有效,因为se
isspace
而不是与
'
@chqrlie进行比较。检查字符是否为空格时,减量没有问题。请注意,字符串不能为空,并且至少包含性别,因为
fscanf
返回了2一些C库尝试使用384个标志词的数组,因此允许-128和255(含)之间的参数,但C标准并没有强制要求这样做,并且可以做的事情也有限制:
char
value
-1
不能与
EOF
(通常定义为
(-1)
)区分开来。因此,没有办法同时使用
isalpha(“ÿ”)==1和
isalpha(EOF)==0
对于使用ISO8859-1编码和默认签名的
char
的法语区域设置。这些问题的根本不一致之处在于
char
在默认情况下不应签名。许多C库函数仅将字符处理为无符号字符:
中的所有函数仅处理
无符号字符的值
和特殊的负值
EOF
getchar()
返回字节值作为
unsigned char
值(不管名称!),
strcmp()
将字符串作为
unsigned char
的序列进行比较(就像
memcpy
),
ungect()
-1
上失败,但是任何其他
字符
int
值都被转换成
无符号字符
,那么
'\xFF'
的值可能是
-1
,这是多么令人困惑啊!所以只需在测试中添加
&*name&*id
(UV无论如何)@bruno:if
fscanf()
返回
3
,无论是
name
还是
id
都不能是空字符串。我的意思是
fscanf()
无法使用
%[^\t]
解析空字段,因为必须至少有一个字符与TAB和
'\0'
不同才能成功转换。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define ACTORS "/tmp/actors"

int main()
{
  FILE * fh = fopen(ACTORS, "r");

  if (!fh) {
    perror("cannot read " ACTORS);
    exit(1);
  }

  char name[100],id[10];

  while (fscanf(fh, "%9s %99[^\n]", id, name) == 2) {
    size_t sz = strlen(name);
    char sex = name[--sz];

    for (;;) {
      if (sz == 0) {
        puts("empty name");
        exit(2);
      }
      if (!isspace((unsigned char) name[--sz]))
        break;
    }

    name[sz+1] = 0;

    /*
    hash_update_node(hash, get_id_num(id) , name, sex);
    count++;
    */
    printf("id='%s', name='%s', sex=%c\n", id, name, sex);
  }

  fclose(fh);
  return 0;
}
pi@raspberrypi:/tmp $ gcc -Wall r.c
pi@raspberrypi:/tmp $ ./a.out
cannot read /tmp/actors: No such file or directory
pi@raspberrypi:/tmp $ cat > actors
nm0025630 Vikas Anand M
nm0418131 Victor Janson M
nm0411451 Dick Israel M
nm0757820 Leopoldo Salcedo M
pi@raspberrypi:/tmp $ ./a.out
id='nm0025630', name='Vikas Anand', sex=M
id='nm0418131', name='Victor Janson', sex=M
id='nm0411451', name='Dick Israel', sex=M
id='nm0757820', name='Leopoldo Salcedo', sex=M
pi@raspberrypi:/tmp $