C编程:读取文件并存储在struct数组中

时间:2016-11-28 00:42:11

标签: c struct structure scanf

我试图通过fscanf读取文件test.txt并将其存储在struct数组中。这是我试过的。这里的问题是fscanf没有按预期工作。阅读完文件后,我也试图在屏幕上打印,但它不会工作。

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

struct Item {
   double value;
   int unit;
   char name[50];
};

int load(struct Item* item, FILE* data);
void display(struct Item item, int variableA);

int main()
{
  struct Item I;
  int i;
  char ck;
  ck =  fopen("test.txt", "r");
  if (ck)
  {
    for (i = 0; i < 3; i++)
    {
        load(&I, ck);
        display(I, 0); //DISPLAY FUNCTION THAT READS test.txt and DISPLAYS
    }
    fclose(ck);
  }
return 0;
}


int load(struct Item* item, FILE* data)
{
    fscanf(data, "%d,%.2lf,%s\n", &(*item).unit,&(*item).value,&(*item).name);
    return 0;
}

void display(struct Item item, int variableA)
{
printf("|%3d |%12.2lf| %20s |***\n", item.unit, item.value, item.name);
return;
}

这是我在 test.txt文件中的内容:

205,11.20,John Snow
336,23.40,Winter is coming
220,34.20,You know nothing

错误:程序编译时会出现一些警告,但在执行代码时出现分段错误。

知道为什么吗?

输出期望:应从test.txt文件中读取OUTPUT,并将其显示在屏幕上。

2 个答案:

答案 0 :(得分:3)

该计划存在多个问题:

1

char ck;
ck =  fopen("test.txt", "r");

fopen返回FILE*,而不是char,请使用

FILE* ck = fopen(...);

2

fscanf(data, "%d,%.2lf,%s\n", &(*item).unit,&(*item).value,&(*item).name);

始终检查fscanf的返回值,如果它小于您请求的字段数,则对fscanf的以下调用不太可能达到预期效果。此外,*item.unititem->unit相同,请使用item->unit因为它更短更清洁:

int ret = fscanf(data, "%d,%lf,", &item->unit, &item->value);
if (ret != 3) { // error }

第三,%s匹配一系列非空白字符,因此当fscanf读取&#34; John&#34;时,它将停止,下一个fscanf电话将会阅读&#34; Snow&#34;期待一个整数。

因此,要输入带有空格的字符串,请改用fgets,并记住最后删除换行符。

请尝试以下操作:

int main(void)
{
    struct Item I;
    int i;
    FILE* ck;
    int ret;
    ck =  fopen("test.txt", "r");
    if (ck)
    {
            for (i = 0; i < 3; i++)
            {
                    ret = load(&I, ck);
                    if (ret < 0)
                            break;
                    display(I, 0); //DISPLAY FUNCTION THAT READS test.txt and DISPLAYS
            }
            fclose(ck);
    }
    return 0;
}

int load(struct Item* item, FILE* data)
{
    int ret = fscanf(data, "%d,%lf,", &item->unit, &item->value);
    if (ret != 2) {
            return -1;
    }
    fgets(item->name, sizeof item->name, data);
    item->name[strlen(item->name)-1] = '\0';
    return 0;
}

void display(struct Item item, int variableA)
{
    printf("|%3d |%12.2lf| %20s |***\n", item.unit, item.value, item.name);
    return;
}

输出:

$ ./a.out
|205 |       11.20|            John Snow |***
|336 |       23.40|     Winter is coming |***
|220 |       34.20|     You know nothing |***

答案 1 :(得分:0)

您可以尝试这种不同的方法。

它使用:

  • mallocrealloc为结构数组分配和重新分配内存。我假设将使用更多更大行的文本文件,这允许数组在需要时调整大小以容纳更多信息。
  • strtok解析,分隔符之间的每个数据片段,然后将它们存储到结构数组中。
  • 检查指针的返回值以避免分段错误。
  • 使用fgets将文件的每一行读入一个字符串,然后我们可以从中解析自己。

这是建议的代码:

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

#define NAMESTRLEN 50
#define INITSIZE 3
#define MAXSIZE 100

typedef struct {
    int unit;
    double value;
    char name[NAMESTRLEN+1];
} item_t;

typedef struct {
    item_t *items;
    int numlines;
} allitems_t;

allitems_t *initialize_arraystructs(void);
void print_arraystructs(allitems_t *allitems);
void read_insert_items(FILE *filestream, allitems_t *allitems);
void check_ptr(void *ptr, const char *msg);

int 
main(void) {
    allitems_t *allitems;
    FILE *fp;

    fp = fopen("test.txt", "r");
    if (fp == NULL) {
        fprintf(stderr, "%s\n", "Error reading file!\n");
        exit(EXIT_FAILURE);
    }

    allitems = initialize_arraystructs();

    read_insert_items(fp, allitems);

    print_arraystructs(allitems);

    return 0;
}

void
read_insert_items(FILE *filestream, allitems_t *allitems) {
    int count = 0;
    char line[MAXSIZE];
    char *unit, *value, *name;
    size_t numitems = INITSIZE;

    allitems->items = malloc(numitems * sizeof(item_t));
    check_ptr(allitems->items, "Initial Allocation");

    while (fgets(line, MAXSIZE, filestream) != NULL) {
        unit = strtok(line, ",");
        value = strtok(NULL, ",");
        name = strtok(NULL, "\n");

        if (count == numitems) {
            numitems *= 2;
            allitems->items = realloc(allitems->items, numitems * sizeof(item_t));
            check_ptr(allitems->items, "Reallocation");

        }

        allitems->items[count].unit = atoi(unit);
        allitems->items[count].value = atof(value);
        strcpy(allitems->items[count].name, name);

        count++;
        allitems->numlines++;
    }
}

allitems_t
*initialize_arraystructs(void) {
    allitems_t *allitems;

    allitems = malloc(sizeof(allitems_t));
    check_ptr(allitems, "Initial Allocation");

    allitems->items = NULL;
    allitems->numlines = 0;

    return allitems;
}

void
print_arraystructs(allitems_t *allitems) {
    int i;

    for (i = 0; i < allitems->numlines; i++) {
        printf("%d,%.2f,%s\n", 
               allitems->items[i].unit, 
               allitems->items[i].value, 
               allitems->items[i].name);
    }
}

void
check_ptr(void *ptr, const char *msg) {
    if (!ptr) {
        printf("Unexpected null pointer: %s\n", msg);
        exit(EXIT_FAILURE);
    }
}