处理用户输入中的 EOF

Handling EOF in user input

我正在编写一个小程序,允许用户输入矩阵的维度 mn,然后根据自己的喜好填充该矩阵。为了读取数字,我使用 fgets() 将用户输入读取为字符串,然后通过 strtol() 将其转换。我还删除了通过 strcspn() 附加的换行符 fgets(),并在用户输入 a12a 或只是换行符 \n 时进行了一些错误处理。但是程序通过 Ctrl + D 输入 EOF 让我很头疼。我阅读了几个关于此的 Whosebug 线程,我知道在某些情况下需要输入 EOF 两次。但是当我发送 EOF 到我第一次调用 fgets() 读取 m 维度时,我将被转发到下一次调用 fgets() 读取 [=12] =]-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] == '[=10=]') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }

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

        if (*ptr_save != '[=10=]') {
            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] == '[=10=]') {
            fprintf(stderr, "Wrong input\n");
            exit(EXIT_FAILURE);
        }

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

        if (*ptr_save != '[=10=]') {
            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] == '[=10=]') {
                    fprintf(stderr, "Wrong input\n");
                    exit(EXIT_FAILURE);
                }

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

                if (*ptr_save != '[=10=]') {
                    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;
}

错误的分配大小: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_rown_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()

轻微:"largest integer that can fit into unsigned long int is a 20-digit number" ... char save[20]; 误导。 1) pow(2,64)需要20个char,但是输入需要考虑'\n''[=28=]',所以应该使用char save[20+2]; 2) unsigned long int 可以 大于 64 位 - 它必须至少是 32 位。但这肯定不是本次post.

的主要问题