【问题标题】:Handling EOF in user input在用户输入中处理 EOF
【发布时间】:2015-07-25 02:01:32
【问题描述】:

我正在编写一个小程序,允许用户输入矩阵的维度m 和n,然后根据自己的喜好填充该矩阵。要读取数字,我使用fgets() 将用户输入读取为字符串,然后通过strtol() 将其转换。我还删除了通过strcspn() 附加的换行符fgets(),并在用户输入a、12a 或只是换行符\n 时进行一些错误处理。但是这个程序让我对通过Ctrl + D 输入的EOF 感到头疼。我阅读了几个关于此的 stackoverflow 线程,我知道在某些情况下需要输入两次EOF。但是,当我将EOF 发送给我第一次调用fgets() 在m-dimension 中读取时,我将被转发到fgets() 的下一个调用中,它读取n-dimensions 并从那里开始跳转到实际的数组输入,它似乎卡住了,或者我进入了一个无限循环。我目前不知道原因,也不知道在这种情况下如何处理EOF。如果有人可以提供一些提示,我会很高兴。代码如下:

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

int main(int argc, char *argv[]) {

    /* We use "m_row" and "n_col" to keep track of the matrix dimensions and "m"
     * and "n" to keep track of the size of dynamically allocated memory.  */
    unsigned long int m_row;
    unsigned long int n_col;
    unsigned long int element;

    /* Initializing at dummy value to silence compiler. */
    m_row = 1;
    n_col = 1;

    /* The largest integer that can fit into unsigned long int is a 20-digit 
     * number. */
    char save[20];
    char *ptr_save;
    printf("Enter number of rows:\n");
    if (fgets(save, sizeof(save), stdin) != NULL) {
        save[strcspn(save, "\n")] = 0;
        if (save[0] == '\0') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }

        m_row = strtol(save, &ptr_save, 10);

        if (*ptr_save != '\0') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }
    }

    printf("Enter number of columns:\n");
    if (fgets(save, sizeof(save), stdin) != NULL) {
        save[strcspn(save, "\n")] = 0;
        if (save[0] == '\0') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }

        n_col = strtol(save, &ptr_save, 10);

        if (*ptr_save != '\0') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }
    }

    errno = 0;
    unsigned long int **arr = calloc(m_row, sizeof(unsigned long int *));
    if (arr == NULL) {
            fprintf(stderr, "%s", strerror(errno));
            exit(EXIT_FAILURE);
    }


    int i;
    errno = 0;
    for(i = 0; i < m_row; i++) {
        arr[i] = calloc(m_row, sizeof(unsigned long int));
        if (arr[i] == NULL) {
                fprintf(stderr, "%s", strerror(errno));
                exit(EXIT_FAILURE);
        }

    }

    int j;
    for(i = 0; i < m_row; i++) {
        for(j = 0; j < n_col; j++) {
            if (fgets(save, sizeof(save), stdin) != NULL) {
                save[strcspn(save, "\n")] = 0;
                if (save[0] == '\0') {
                    fprintf(stderr, "Wrong input\n");
                    exit(EXIT_FAILURE);
                }

                element = strtol(save, &ptr_save, 10);

                if (*ptr_save != '\0') {
                    fprintf(stderr, "Wrong input\n");
                    exit(EXIT_FAILURE);
                }
                arr[i][j] = element;
            }
            printf("\n");
        }
    }

    for (i = 0; i < m_row; i++) {
        for(j = 0; j < n_col; j++) {
            printf("%lu\t", arr[i][j]);
        }
        printf("\n");
    }

    free(arr);
    return 0;
}

【问题讨论】:

    标签: c arrays error-handling


    【解决方案1】:

    分配大小错误:m_row 与 n_col。这可能不是EOF 问题。

    for (i = 0; i < m_row; i++) {
      // arr[i] = calloc(m_row, sizeof(unsigned long int));
      arr[i] = calloc(n_col, sizeof(unsigned long int));
    }
    

    建议改为初始化m_row = 0; n_col = 0;。

    即使arr 由于EOF 而没有完全填充,代码也会尝试打印出arr。应该避免这种情况。

    如果这些不能解决问题,建议在读取元素之前打印m_row 和n_col,以验证矩阵大小是否符合预期。


    次要:使用相同大小的整数

     // Rather than 
     unsigned long int m_row;
     ...
     int i;
     for(i = 0; i < m_row; i++) {
    
     // Use same type: recommend `size_t`
     size_t m_row;
     ...
     size_t i;
     for(i = 0; i < m_row; i++) {
    

    次要:使用strtoul() 和unsigned long,而不是strtol()。

    次要:“可以放入 unsigned long int 的最大整数是 20 位数字” ...char save[20]; 误导。 1)pow(2,64)取20个char,但输入需要考虑'\n'和'\0',所以应该使用char save[20+2]; 2)unsigned long int可以大于64-位 - 它必须至少为 32 位。但这肯定不是本文的主要问题。

    【讨论】:

    • 感谢您的所有提示!真的很有帮助!你用n_col 代替m_row 是对的。但是初始化m_row = 0;n_col = 0;会导致calloc()分配0字节。这会在 gcc 和 clang 设置正确的参数时发出警告。
    • 出于学习目的:您是否不同意一般的编码,因为您说这肯定不是本文的主要问题?
    • @brauner calloc(0, some_size) 是一件好事。结果可能是NULL - 这不表示内存不足。
    • @brauner “不是主要问题”评论是指使用int 作为索引和unsigned long 作为限制。当索引试图超出INT_MAX 时,这将是一个问题。 INT_MAX 可能远小于 ULONG_MAX。
    猜你喜欢
    • 1970-01-01
    • 2022-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2019-09-21
    • 2020-02-21
    相关资源
    最近更新 更多