【问题标题】:How to use fgets and sscanf to store data into structure, from text file如何使用 fgets 和 sscanf 将数据从文本文件存储到结构中
【发布时间】:2018-04-20 15:54:14
【问题描述】:

我想要做的是获取一个文本文件并将 4 行存储到我的结构中,使用带有 fgets 和 sscanf 的循环来检索数据。

结构是这样的:

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #define SIZE 16
 #define N 4

struct Prova
{
    char nome[SIZE];
    int num;
};

现在我的函数看起来像这样:

void get_str(struct Prova * ptr){

FILE *f;
int i = 0;

 if(!(f = fopen(PATH,"r+")))
  {
    perror("Errore in apertura");
    exit(0);
  }

void * buffer = malloc(sizeof(struct Prova ));

  while(fgets(buffer,sizeof(struct Prova), f))
   {
    if(sscanf(buffer, "%s %d", (ptr+i)->nome, &(ptr+i)->num) > 0)
      {i++;}
   }

   free(buffer);
   fclose(f);
  }

更新:现在该功能可以工作了,谢谢大家。

主要功能是这样的:

  int main()
  {
    struct Prova * ptr = malloc(N*sizeof(struct Prova));

    get_str(ptr);

    for(int i = 0; i< N; i++)
    {
      printf("\n%s %d", (ptr+i)->nome, (ptr+i)->num);
    }
   return 0;
  }

我要读取的文本文件是这样的:

Pippo 4
Paperino 1
Topolino 3
Zio_paperone 2

【问题讨论】:

  • 您确定Paperino1 之间以及Topolino3 之间的字符是实际上 空格(代码0x20)而不是不间断空格(代码 0xa0)?在大多数文本编辑器中,它们看起来都一样,您无法分辨出区别
  • fgets(buffer,sizeof(struct Prova), f) 不是很正确,因为你真的想要[at most SIZE - 1 characters][space][1 digit][maybe a newline],而不是[at most SIZE - 1 characters][space][sizeof(int) digits],这甚至没有考虑填充等的可能性。在实践中它可能“足够接近”但是在语义上似乎不合适。
  • 还需要查看sscanf的返回值。你没有,这就是打印最后一个0 的原因
  • @underscore_d "[at most SIZE - 1 characters][space][1 digit]" 也需要'\n''\0' 的空间。 OTOH 只需使用 2 倍预期大小的缓冲区。缓冲区稍大一点也不成问题。
  • @chux 好点:已编辑。是的,在这种情况下,稍微过度分配也很有意义——如果不是更多的话,因为这样可以减少意外过长的行导致任何爆炸的风险。但是,代码反而暗示它试图非常具体地确定大小,但使用了错误的基础;这是我的抱怨。

标签: c pointers data-structures


【解决方案1】:

根据 cmets 中其他人的建议,检查 sscanf() 的返回值。另外我不确定你传递给get_str()的参数是什么。

同样在void * buffer = malloc(N*sizeof(struct Prova )); 中,您无需为N structure 分配内存,因为使用fgets() 您每次都会覆盖数据。应该是void * buffer = malloc(2*sizeof(struct Prova ));

对于您提到的特定情况,这可能是解决方案

while(fgets(buffer,sizeof(struct Prova), f)) {
       int ret = sscanf(buffer, "%s %d", (ptr+i)->nome, &(ptr+i)->num);
       printf("ret = %d\n",ret);
       printf("\n%s %d", (ptr+i)->nome, (ptr+i)->num);
       i++;
}

这是完整的代码

#define N 4
struct Prova {
        char nome[SIZE];
        int num;
};
void get_str(struct Prova * ptr) {
        FILE *f;
        if(!(f = fopen("data","r+"))) {
                perror("Error");
                exit(0);
        }
        void * buffer = malloc(2*sizeof(struct Prova ));/* Allocate 2* size, by considering Newline char & possible padding */ 
        int i =0;
        while(fgets(buffer,sizeof(struct Prova), f)) {
                int ret = sscanf(buffer, "%s %d", (ptr+i)->nome, &(ptr+i)->num);
                printf("ret = %d\n",ret);
                i++;
        }
        free(buffer);
        fclose(f);
}
int main() {
        struct Prova *v = malloc(N*sizeof(struct Prova));/* here you need to allocate 
                                for N structure, amke sure file have N lines of same format */
        get_str(v);
        for(int i =0;i<N;i++) {
                printf("\n%s %d\n",(v+i)->nome,(v+i)->num);
        }
        return 0;
}

【讨论】:

  • 正如hereherehere 所评论的那样,分配给buffer 的大小几乎不足。建议更大的,也许是 2x sizeof(struct Prova )?
  • 我试图增加缓冲区,但问题仍然存在,我仍然打印了那个 0:\
  • St3veR0nix 您是否应用了@Michael Walz 建议的修复?
  • 是的,我放了一个if语句来检查sscanf的返回值
  • @St3veR0nix 您提到的示例输入包含4 行,但您将#define N 5 定义为N4
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-09
  • 2021-11-09
  • 2019-07-25
  • 1970-01-01
  • 2021-06-10
相关资源
最近更新 更多