在循环中使用fgets()获取输入

时间:2017-05-05 20:54:20

标签: c arrays fgets

我正在尝试使用fgets()进行输入。我知道我会得到多少行,但它会改变,我会在变量var中存储行数。我还有另一个名为part的变量;它是我得到的线的长度,但由于值之间有空格我乘以2(我无法找到另一种解决方案;我可以使用一些建议)。

无论如何,我试着在下面的代码中获取输入,但当我进入第一行时,它会自动打开for循环并打印随机内容。我认为这与循环中的fgets()有关;我不知道是否有fgets()这样的使用。

char inp[var][(2*part)];
int k,l;
for(k=0;k<=var;k++);
    fgets(inp[k],(2*part),stdin);
printf("%c\n",inp[0]);
printf("%c\n",inp[1]);
printf("%c\n",inp[2]);
printf("%c\n",inp[3]);

2 个答案:

答案 0 :(得分:1)

  

...因为值之间有空格我乘以2 ...

如果不需要将所有内容存储在堆栈中,则可以将字符串存储在动态分配的内存中。例如:

char* inp[var];
char buf[400]; // just needs to be long
for (k = 0; k < var;  k++) {
    fgets(buf, 400, stdin);
    inp[k] = malloc(sizeof(char) * (strlen(buf) + 1));
    strcpy(inp[k], buf);
}

虽然从技术上讲不符合标准,strdup可以广泛使用,也可以使这更容易。

就实际问题而言,正如BLUEPIXY在上述评论中所说,你有一些错别字。

  1. 在for循环之后,分号使其意外动作。

    for(k=0;k<=var;k++);
        fgets(inp[k],(2*part),stdin);
    

    实际上与

    相同
    for(k=0;k<=var;k++) {
        ; // do nothing
    }
    fgets(...);
    

    在for循环语句后删除该分号。事实上,你实际上并没有正确阅读,这就是你看垃圾的原因。

  2. 要打印整个字符串,printf系列需要%s格式标记。

  3. 使用k上的边界,实际上会有var + 1次迭代循环。如果var3,则k = 0,1,2,3 - &gt;在k检查4后终止。

答案 1 :(得分:0)

通常,使用fgets的最安全和最简单的方法是分配一个足够大的行缓冲区。用它来读取该行,然后将其复制到正确大小的缓冲区中。

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

int main(void) {
    // Allocate just the space for the list, not the strings themselves.
    int num_input = 5;
    char *input[num_input];

    // Allocate our reusable line buffer.
    char line[1024];
    for( int i = 0; i < num_input; i++ ) {
        // Read into the line buffer.
        fgets(line, 1024,stdin);

        // Copy from the line buffer into correctly sized memory.
        input[i] = strdup(line);
    }

    for( int i = 0; i < num_input; i++ ) {
        printf("%s\n",input[i]);
    }
}

请注意,strdup()不是ISO C函数,而是POSIX。它很常见且足够标准。不使用它太方便了。如有必要,请自己写。

负责不了解线路长度。

如果您不知道要存储的行数,则必须增加阵列。通常,这是使用realloc来重新分配现有内存。从小的列表大小开始,然后根据需要增长。加倍是一个很好的粗略近似,它是速度(重新分配可能很慢)和内存效率之间非常有效的平衡。

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

int main(void) {
    // How big the input list is.
    size_t input_max = 64;

    // How many elements are in it.
    size_t input_size = 0;

    // Allocate initial memory for the input list.
    // Again, not for the strings, just for the list.
    char **input = malloc( sizeof(char*) * input_max );

    char line[1024];
    while( fgets(line, 1024,stdin) != NULL ) {
        // Check if we need to make the input list bigger.
        if( input_size >= input_max ) {
            // Double the max length.
            input_max *= 2;

            // Reallocate.
            // Note: this is only safe because we're
            // going to exit on error, otherwise we'd leak
            // input's memory.
            input = realloc( input, sizeof(char*) * input_max );

            // Check for error.
            if( input == NULL ) {
                fprintf(stderr, "Could not reallocate input list to %zu: %s", input_max, strerror(errno) );
                exit(1);
            }
        }

        input[input_size] = strdup(line);
        input_size++;
    }

    for( size_t i = 0; i < input_size; i++ ) {
        printf("%s\n",input[i]);
    }
}

正如您所看到的,这有点复杂。现在,您需要跟踪数组,最大大小和当前大小。使用该阵列的任何人都必须记住检查它的大小并增长它,并记得错误检查它。你的下一个冲动将是创建一个结构来收集所有这些,并用于管理列表。

这是动态内存管理的一个很好的练习,我鼓励你这样做。但是对于生产代码,请使用预先存在的库。 GLib是个不错的选择。它包含C中缺少的各种方便的数据结构和函数,包括pointer arrays that automatically grow。在生产代码中使用它们或类似的东西。