2016-11-28 2 views
2

Я пытаюсь прочитать файл test.txt через fscanf и сохранить его в массиве struct. Это то, что я пробовал. Проблема здесь в том, что fscanf не работает так, как предполагается. После прочтения файла, я также пытаюсь распечатать его на экране, но это не сработает.C Программирование: чтение файла и сохранение в массиве struct

#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 

Ошибка: Программа компилируется с некоторыми предупреждениями, но я получаю ошибку сегментации, когда я выполняю код.

Любая идея, почему?

Ожидание выхода: OUTPUT должен быть прочитан из файла test.txt и должен отображаться на экране.

+3

Может быть, потому, что "Джон" является неправильным; это «Джон» Снег ... –

+0

@ ringø haha: D: D: D – John

+0

Вам нужно отладить программу, чтобы увидеть, где происходит ошибка (чтение или показ), а также посмотреть, получаете ли вы то, что, по вашему мнению, получите. – Phil1970

ответ

2

Несколько проблем в программе:

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.unit такая же, как item->unit, использовать item->unit, потому что он короче и чище:

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

В-третьих, %s совпадает с последовательностью не-пробельных символов, поэтому, когда fscanf читает «Джон», он остановится , и следующий вызов fscanf получит сообщение «Снег», ожидая целое число.

Чтобы ввести строку с пробелами, используйте вместо этого 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 |*** 
+0

Ty для быстрое объяснение. :) – John

+0

Я получаю черный выход. – John

+0

@John Вы использовали код, который я вставил? – fluter

0

Вы можете попробовать этот другой подход.

Он использует:

  • malloc, realloc выделить и перераспределить память для массива структур. Я предположил, что будут использоваться гораздо большие текстовые файлы с большим количеством строк, и это позволит массиву изменять размер, когда это необходимо, чтобы разместить больше информации.
  • 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); 
    } 
} 
Смежные вопросы