从两列读入变量

时间:2013-09-03 08:25:05

标签: c input

我正在编写一个带有输入文件并存储它的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 个答案:

答案 0 :(得分: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 

答案 1 :(得分:0)

使用:

fgets (name, 100, stdin);

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

使用:

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

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

答案 2 :(得分:0)

这里的问题似乎是你正在从文件中读取两次。首先是fgets,然后是scanf。在使用scanf时,您可能不会从编译器中获得错误,但是当您使用line作为格式字符串并且其他参数与格式不匹配时,应该收到警告。如果您检查scanf的返回值,也会很明显,因为它会返回成功扫描的项目数。你的电话很可能会返回零(或当你点击文件结尾时减去一个)。

您应该使用sscanf来解析您使用fgets读取的行。

参见例如this reference适用于不同的scanf变体。

答案 3 :(得分: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