如何从 C 中的文件中获取使用“getline”获取缓冲区中的每个字符串

How to get each string within a buffer fetched with "getline" from a file in C

提问人:Educg550 提问时间:12/16/2022 更新时间:12/16/2022 访问量:62

问:

我正在尝试从文件中文本的每一行中读取用逗号、点或空格分隔的每个字符串(为了简单起见,我只是接收字母数字字符)。我正在使用库中的函数,它可以很好地读取该行。但是当我尝试“迭代”使用它获取的缓冲区时,它总是返回从文件中读取的第一个字符串。假设我有一个名为“entry.txt”的文件,其中包含以下内容:scanfgetline<stdio.h>

test1234 test hello
another test2

我的“main.c”包含以下内容:

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

#define MAX_WORD 500

int main()
{
    FILE *fp;
    int currentLine = 1;
    size_t characters, maxLine = MAX_WORD * 500;
    /* Buffer can keep up to 500 words of 500 characters each */
    char *word = (char *)malloc(MAX_WORD * sizeof(char)), *buffer = (char *)malloc((int)maxLine * sizeof(char));

    fp = fopen("entry.txt", "r");
    if (fp == NULL) {
        return 1;
    }

    for (currentLine = 1; (characters = getline(&buffer, &maxLine, fp)) != -1; currentLine++)
    {
        /* This line gets "test1234" onto "word" variable, as expected */
        sscanf(buffer, "%[a-zA-Z_0-9]", word);

        printf("%s", word); // As expected
        
        /* This line should get "test" string, but again it obtains "test1234" from the buffer */
        sscanf(buffer, "%[a-zA-Z_0-9]", word);

        printf("%s", word); // Not intended...

        // Do some stuff with the "word" and "currentLine" variables...
    }

    return 0;
}

发生的情况是,我试图从缓冲区中按顺序获取每个字母数字字符串(即从现在开始的单词),而该函数只是给我指定缓冲区字符串中第一个单词的出现。此外,条目文件上的每一行都可以包含未知数量的单词,这些单词由空格、逗号、点、特殊字符等分隔。sscanf

我使用“getline”单独获取文件中的每一行,因为我需要从每行中获取每个单词,并使用“currentLine”变量将其存储在其他地方,这样我就知道给定的单词会来自哪一行。关于如何做到这一点的任何想法?

C 字符串 文件 scanf std

评论

0赞 Andrew Henle 12/16/2022
/* This line should get "test" string, but again it obtains "test1234" from the buffer */?!?!??为什么你认为第二次会产生不同的结果?sscanf(buffer, "%[a-zA-Z_0-9]", word);
0赞 chux - Reinstate Monica 12/16/2022
Educg550,缺少宽度。最好是sscanf(buffer, "%[a-zA-Z_0-9]", word);sscanf(buffer, "%499[a-zA-Z_0-9]", word);
0赞 Fe2O3 12/16/2022
您想用于将缓冲区分解为“单词”...strtok()

答:

1赞 n. m. could be an AI 12/16/2022 #1

fscanf具有输入流参数。流可以更改其状态,以便第二次调用读取不同的内容。例如:fscanf

fscanf(stdin, "%s", str1);  // str1 contains some string; stdin advances
fscanf(stdin, "%s", str2);  // str2 contains some other sting

scanf没有 stream 参数,但它有一个全局流可以使用,因此它的工作方式与 .fscanf(stdin, ...)

sscanf没有 Stream 参数,也没有任何全局状态来跟踪读取的内容。有一个输入字符串。你扫描它,一些字符被转换,然后......其他什么都没有改变。字符串仍然是同一个字符串(否则怎么可能?),并且没有存储任何有关扫描进展程度的信息。

sscanf(buffer, "%s", str1);  // str1 contains some string; nothing else changes
sscanf(buffer, "%s", str2);  // str2 contains the same sting

那么一个可怜的程序员会做什么呢?

好吧,我撒谎了。只有在您不请求时,才会将有关扫描进展程度的信息存储在任何地方。

int nchars;
sscanf(buffer, "%s%n", str1, &nchars); // str1 contains some string;
                                       // nchars contains number of characters consumed
sscanf(buffer+nchars, "%s", str2);     // str2 contains some other string

为简洁起见,省略了错误处理和 %s 字段宽度。你永远不应该在实际代码中省略它们。