c - 将这行文本读入结构的最简单方法?

标签 c text fgets

我有一个文本文件,其数据格式如下:

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?

最佳答案

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 ),其中一些(例如 hereherehere )包含我一直以来最喜欢的函数 getLine,以实现更安全的用户输入。

关于c - 将这行文本读入结构的最简单方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3878327/

相关文章:

C 编程。仅使用数组和指针生成随机字母字符串的函数

python - "Compiling" python 脚本

python - python中的正则表达式嵌套括号

c - 为什么以下代码不允许我使用fgets获得用户输入,但不能使用scanf?

c - 用户输入和 fgets

c - 将位插入 uint16_t

c++ - 获取系统的唯一标识符(不是 MAC 地址)?

c - 从文件扫描

css - p style=显示 :inline trouble

php - 套接字PHP卡在fgets上