使用 fgets 读取标准输入,将每一行填充到数组中并打印每一行

Read stdin with fgets, fill each line in an array and print each line

我想用 fgets 阅读 stdin

然后,我想读每一行。我的行是用 ' ' 分隔的字符串。 例如,这可能是一行:1 2 ab

我认为我应该使用 malloc 来计算我行中的参数数量,因为这个数字可能因行而异。 1 2 3 4 有 4 个,但 a b 2 有 3 个。

我用 strtok 截断了这一行,然后我用 标记 填充了我的 malloc 并打印了它们。

最后的结果就是只打印每一行。

例如,这是一个file.txt:

1 2 33 4
a b1 c
4 b l 11

我也是:

$ cat file.txt | ./a.out

它应该打印:

1 2 33 4
a b1 c
4 b l 11

但事实并非如此!

你们能帮我解决一下吗:O

此外,我想使用数组来计算令牌并在以后使用它们。例如,我需要单独处理每一行的所有第二个参数,所以 array[1].

这是我的代码:

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

int main(int argc, char *argv) {
 
    while (fgets(argv, sizeof(argv), stdin) != NULL) {
        char *array = (char *)malloc(sizeof(argv));
        char *token = strtok(argv, " ");
        strtok(token, "\n");
        int i = 0;

        while (token != NULL) {
            array[i] = token;
            token = strtok(NULL, " ");
            printf("%d\n", array[i]);
            ++i;
        }
    }
    return 0;
}

如果你只想计算token并输出,那么你可以简单地使用一个指向token的指针,而不需要分配存储空间。使用 strtok() 是个不错的选择。 (注意:如果您有空字段,则需要使用另一种方法进行解析,因为 strtok() 会将顺序分隔符视为单个分隔符)。传递给 strtok() 的字符串必须是可变的,因为 strtok() 会修改字符串(如果需要保留原始字符串,请复制一份)

你的方法是将带有 fgets() 的每一行读入一个足够大的缓冲区(字符数组),将你的计数器归零,然后标记该行,增加每个标记的计数并输出由一个分隔的标记space.

您可以按如下方式进行:

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

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {
    
    char line[MAXC];    /* storage for line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    while (fgets (line, MAXC, fp)) {
        size_t  toks = 0,
                len;
        line[(len = strcspn (line, "\n"))] = 0;     /* trim \n, save length */
        for (char *p = strtok (line, " \t"); p; p = strtok (NULL, " \t"))
            printf (toks++ ? " %s" : "%s", p);
        printf ("%*s\t(%zu tokens)\n", (int)len % 8, " ", toks);
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

上面一个三进制用来控制space-分隔符的输出(第一个token之前什么都没有——当计数为零时,然后是一个在每个后续标记之前单个 space)。标记的计数附加到每行的末尾。

(每行的 strlen() 仅用于通过添加制表符的小数部分来整理每个输出行的末尾与附加计数之间的间距,如果需要的话)

例子Use/Output

使用文件 dat/tokfile.txt 中的示例数据,您将收到:

$ ./bin/fgets_tok_count dat/tokfile.txt
1 2 33 4        (4 tokens)
a b1 c          (3 tokens)
4 b l 11        (4 tokens)

通过将文件名作为程序的第一个参数,或者如果没有给出参数则默认从 stdin 读取,您也可以将信息重定向到您的程序,例如

$ ./bin/fgets_tok_count < dat/tokfile.txt

否则你的 UUOc 表格也行:

$ cat dat/tokfile.txt | ./bin/fgets_tok_count

每行动态存储未知数量的令牌

要动态存储每个标记并在标记化循环期间保留每个标记,那么您只需要一个指向指针的指针 char 和一个跟踪指针和字符串数量的计数器分配。您可以这样做类似于:

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

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {
    
    char line[MAXC];            /* storage for line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    while (fgets (line, MAXC, fp)) {
        char **tokens = NULL;
        size_t  len = 0,
                toks = 0;
        line[(len = strcspn (line, "\n"))] = 0;     /* trim \n, save length */
        /* loop over each token */
        for (char *p = strtok (line, " \t"); p; p = strtok (NULL, " \t")) {
            size_t toklen = strlen (p);
            /* allocate/validate 1 additional pointer for tokens */
            void *tmp = realloc (tokens, (toks + 1) * sizeof *tokens);
            if (!tmp) {
                perror ("realloc-tokens");
                break;
            }
            tokens = tmp;
            /* allocate/validate storage for token of len + 1 */
            if (!(tokens[toks] = malloc (toklen + 1))) {
                perror ("malloc-tokens[toks]");
                break;
            }
            /* copy token to allocated block */
            memcpy (tokens[toks], p, toklen + 1);
            toks++;     /* increment no. of tokens in line */
        }
        /* output all stored line tokens and no. of tokens */
        for (size_t i = 0; i < toks; i++) {
            printf (i ? " %s" : "%s", tokens[i]);
            free (tokens[i]);   /* done with stored token, free token */
        }
        free (tokens);          /* free pointers */
        
        printf ("%*s\t(%zu tokens)\n", (int)len % 8, " ", toks);
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

(程序输出相同)

基本上,上面,realloc用于每次找到token时为1-additional pointer分配存储空间,然后malloc用于分配token的长度(+1 ),然后将令牌复制到分配的块中。完成对行的标记后,tokens 指针指向一个包含 toks 指针的内存块,依次分配一个包含每个标记的内存块。在所有标记化和存储完成后,通过遍历指针产生相同的输出,输出标记(和标记数)。然后释放所有内存。

检查一下,如果您还有其他问题,请告诉我。