3

我正在编写一个 C 程序,它接受一个输入文件并存储它。输入文件有两列,第一列是整数,第二列是字符串,如下所示:

    12  apple
    17  frog
    20  grass

我尝试使用 fgets 将整行作为字符串,然后使用 scanf 将其分开,但我遇到了很多问题。我已经搜索了很多,但没有找到任何可以回答我的问题的东西,但是如果我错过了一些明显的东西,我很抱歉。这是我一直在尝试的代码:

    while(fgets(line, sizeof(line), fp))
    {
        scanf(line, "%d\t%s", &key, value);
        insert(key, value, newdict);
    }
4

4 回答 4

2

strtok既然有人提到了,让我们快速做一下。假设您的文件被调用file.txt并具有以下内容:

10 aaa 
20 bbb 
30 ccc 

我们可以这样解析它:

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

#define MAX_NUMBER_OF_LINES 10 // parse a maximum of 10 lines
#define MAX_LINE_SIZE 50       // parse a maximum of 50 chars per line

int main ()
{
    FILE* fh = fopen("file.txt", "r"); // open the file

    char temp[MAX_LINE_SIZE]; // some buffer storage for each line

    // storage for MAX_NUMBER_OF_LINES integers
    int  d_out[MAX_NUMBER_OF_LINES];

    // storage for MAX_NUMBER_OF_LINES strings each MAX_LINE_SIZE chars long
    char s_out[MAX_NUMBER_OF_LINES][MAX_LINE_SIZE];

    // i is a special variable that tells us if we're parsing a number or a string (0 for num, 1 for string)
    // di and si are indices to keep track of which line we're currently handling
    int i = 0, di = 0, si = 0;

    while (fgets(temp, MAX_LINE_SIZE, fh) && di < MAX_NUMBER_OF_LINES) // read the input file and parse the string
    {
        temp[strlen(temp) -1] = '\0'; // get rid of the newline in the buffer

        char* c = strtok(temp, " ");  // set the delimiters

        while(c != NULL)
        {
            if (i == 0) // i equal to 0 means we're parsing a number
            {
                i = 1; // next we'll parse a string, let's indicate that
                sscanf(c, "%d", &d_out[di++]);
            }
            else // i must be 1 parsing a string
            {
                i = 0; // next we'll parse a number
                sprintf(s_out[si++], "%s", c);
            }
            c = strtok(NULL, " ");
        }
        printf("%d %s\n", d_out[di -1], s_out[si - 1]); // print what we've extracted
    }

    fclose(fh);

    return 0;
}

这将从文件中提取内容并将它们存储在相应的数组中,然后我们打印它们并取回我们的原始内容:

$ ./a.out 
10 aaa 
20 bbb 
30 ccc 
于 2013-09-03T08:51:39.607 回答
0

这里的问题似乎是您从文件中读取了两次。先用fgets再用scanf。在使用 时,您可能不会从编译器中收到错误scanf,但在使用格式字符串时应该会收到警告,line并且其他参数与格式不匹配。如果您检查 from 的返回值也很明显scanf,因为它返回成功扫描项目的数量。您的调用很可能会返回零(或者当您到达文件末尾时会返回负一)。

您应该使用它sscanf来解析您阅读的行fgets

例如,请参阅此参考以了解不同的scanf变体。

于 2013-09-03T08:37:01.193 回答
0

您的问题可以通过使用sscanf (在getline的支持下)来解决,如下所示:

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

int main(void)
{
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    /* tokens bags */
    char tok_str[255];
    int tok_int;

    fp = fopen("./file.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    /* Reads the line from the stream. */
    while ((read = getline(&line, &len, fp)) != -1) {
        /* Scans the character string pointed by line, according to given format. */
        sscanf(line, "%d\t%s", &tok_int, tok_str);
        printf("%d-%s\n", tok_int, tok_str);
    }

    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}

或者,甚至更简单。您可以使用fscanf (在feof的支持下)并将上面显示的 while 循环(以及其他一些冗余代码清理)替换为以下循环:

    /* Tests the end-of-file indicator for the stream. */
    while (!feof(fp)) {
        /* Scans input from the file stream pointer. */
        fscanf(fp,"%d\t%s\n",&tok_int, tok_str);
        printf("%d-%s\n", tok_int, tok_str);
    }

假设您的文件包含以下行(其中单行格式为number[tab]string[newline]):

12  apple
17  frog
20  grass

输出将是:

12-apple
17-frog
20-grass
于 2013-09-03T09:16:04.207 回答
0

利用:

fgets (name, 100, stdin);

100是缓冲区的最大长度。您应该根据需要进行调整。

利用:

scanf ("%[^\n]%*c", name);

[]扫描集字符。[^\n]告诉当输入不是换行符 ( '\n') 时接受输入。然后%*c它从输入缓冲区中读取换行符(未读取),并且*表示该输入中的读取被丢弃(分配抑制),因为您不需要它,并且缓冲区中的这个换行符不会创建您可能采取的下一个输入的任何问题。

于 2013-09-03T08:28:30.887 回答