Самый простой способ прочитать эту строку текста в структуре? - PullRequest
2 голосов
/ 07 октября 2010

У меня есть текстовый файл с данными в форме:

Lee AUS 2 103 2 62 TRUE
Check AUS 4 48 0 23 FALSE
Mills AUS 8 236 0 69 FALSE

Мне нужно каждую строку в структуре, как, однако я хотел бы избежать использования массивов фиксированной длины (проблема с fgets какнасколько я могу судить):

struct Data
{
    char *sname;
    char *country;
    int *a;
    int *b;
    int *c;
    int *d;
    char *hsisno;
};

Я очень плохо знаком с C. Должен ли я использовать fscanf или fgets?

1 Ответ

4 голосов
/ 07 октября 2010

fscanf означает «сканирование файлов отформатировано », а пользовательские данные примерно как неотформатированные , как вы можете получить.

Вы никогда не должны использовать голые "%s" форматирование строк данных, когда вы не имеете абсолютного контроля над тем, что можно прочитать.

Лучшее решение - использовать fgets для чтения строки, поскольку это позволяет предотвратить переполнение буфера.

Затем, когда вы знаете размер вашей строки, это максимальный размер каждой строки, который вам потребуется.Используйте sscanf для вашего сердца, чтобы получить действительные поля.

И последнее.Вероятно, немного расточительно иметь int* типы для целых чисел, поскольку вы знаете, что у них уже есть определенный максимальный размер.Я бы использовал вариант без указателя, что-то вроде:

struct Data {
    char *sname; char *country;
    int a; int b; int c; int d;
    char *hsisno;
};

В качестве примера приведу некоторый безопасный код:

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

// Here's all the stuff for a linked list of your nodes.

typedef struct sData {
    char *sname; char *country; char *hsisno;
    int a; int b; int c; int d;
    struct sData *next;
} Data;
Data *first = NULL; Data *last = NULL;

#define MAXSZ 100
int main (void) {
    char line[MAXSZ], sname[MAXSZ], country[MAXSZ], hsisno[MAXSZ];
    int a, b, c, d;
    FILE *fIn;
    Data *node;

    // Open the input file.

    fIn = fopen ("file.in", "r");
    if (fIn == NULL) {
        printf ("Cannot open file\n");
        return 1;
    }

    // Process every line.

    while (fgets (line, sizeof(line), fIn) != NULL) {
        // Check line for various problems (too short, too long).

        if (line[0] == '\0') {
            printf ("Line too short\n");
            return 1;
        }

        if (line[strlen (line)-1] != '\n') {
            printf ("Line starting with '%s' is too long\n", line);
            return 1;
        }

        line[strlen (line)-1] = '\0';

        // Scan the individual fields.

        if (sscanf (line, "%s %s %d %d %d %d %s",
            sname, country, &a, &b, &c, &d, hsisno) != 7)
        {
            printf ("Line '%s' didn't scan properly\n", line);
            return 1;
        }

        // Allocate a new node to hold data.

        node = malloc (sizeof (Data));
        if (node == NULL) {
            printf ("Ran out of memory\n");
            return 1;
        }

        node->sname = strdup (sname);
        node->country = strdup (country);
        node->a = a;
        node->b = b;
        node->c = c;
        node->d = d;
        node->hsisno = strdup (hsisno);
        node->next = NULL;
        if (first != NULL) {
            last->next = node;
            last = node;
        } else {
            first = node;
            last = node;
        }
    }

    fclose (fIn);

    // Output the list for debugging.

    node = first;
    while (node != NULL) {
        printf ("'%s' '%s' %d %d %d %d '%s'\n",
            node->sname, node->country, node->a, node->b,
            node->c, node->d, node->hsisno);
        node = node->next;
    }

    return 0;
}

, который читает ваш файл исохраняет его в связанном списке.Он выводит:

'Lee' 'AUS' 2 103 2 62 'TRUE'
'Check' 'AUS' 4 48 0 23 'FALSE'
'Mills' 'AUS' 8 236 0 69 'FALSE'

в конце, как и ожидалось.


Я сделал целый ряд ответов о ловушках использования *scanf функций на неуправляемыхданные (введите user:14860 fgets в поле поиска выше), некоторые из которых (например, здесь , здесь и здесь ) включают в себя постоянную любимую функциюмой, getLine, для более безопасного ввода пользователя.

...