EOF handling on user input
I am writing a small program that allows the user to enter dimensions m
and n
matrices and then fill that matrix to their liking. To read in numbers, I use fgets()
to read user input as a string and then convert it through strtol()
. I also remove the newline fgets()
adds through strcspn()
and does some error handling when the user enters a
, 12a
or just a newline \n
. But the program is giving me a headache when entering EOF
through Ctrl + D
. I have read several stackoverflow threads about this and I know that in some cases it needs to be entered EOF
twice. But when I post EOF
to my first call fgets()
reading inm
-size, I will be redirected to the next call fgets()
that reads in n
-dimensions and from there it will go to the actual input of the array and there it seems to be stuck, or I go into an infinite loop. I currently don't know the reason, and I don't know how to handle EOF
in this scenario. I would be glad if someone could give some hints. Here is the code:
#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;
}
source to share
An incorrect allocation size: m_row
vs n_col
. This might not be a problem 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));
}
Suggest initialize m_row = 0; n_col = 0;
instead.
The code tries to print arr
even if arr
it was not completely filled out due to EOF
. This should be avoided.
If that doesn't fix the problem, suggest printing m_row
ands n_col
before reading the elements to check the matrix size as expected.
Minor: use integers of the same size
// 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++) {
Minor: use strtoul()
with unsigned long
, not strtol()
.
Minor: The largest integer that can fit into an unsigned long int is a 20-digit number "... char save[20];
mis-leads. 1) pow(2,64)
takes 20 char
, but must be taken into account for input '\n'
and '\0'
therefore should be used char save[20+2];
2) unsigned long int
can be greater than 64- bit - it should be at least 32 bit, but this is certainly not the main problem of this post.
source to share