The preferred way to take user input is to read an entire line of input at a time with fgets()
or POSIX getline()
. The reason for this is you consume an entire line of input with each read and what remains in stdin
does not depend on the scanf
conversion specifier used. It also eliminates having to remember which conversion specifiers consume leading whitespace and those that do not and eliminates characters left in stdin
on a matching failure.
It also provides the convenience of being able to check if the first character in the buffer used to hold the input is '\n'
telling you that Enter alone was pressed without any other input.
To incorporate the use of fgets()
and sscanf()
in your code, simply declare a buffer to hold a line of user input sufficient for whatever the user may enter (or what results if a cat steps on the keyboard) -- don't skimp on buffer size. Then read the input into the buffer with fgets()
and check if the first character is '\n'
to determine if Enter alone was pressed.
You can do that as follows:
int main()
{
char buf[256];
...
if (!fgets (buf, sizeof buf, stdin)) { /* read line of input/validate */
fputs ("(user canceled input)\n", stderr);
return 1;
}
if (buf[0] == '\n') /* break loop on [Enter] alone */
break;
if (sscanf (buf, "%d", &temp) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
...
(note: the check of sscanf (buf, "%d", &temp) != 1
will catch a manually generated EOF
if the user presses Ctrl+d (or Ctrl+z on windows) where !sscanf(buf, " %d", &temp)
won't)
Look things over and let me know if you have further questions.
Edit Per-Comment
Since in your question you indicate you have to allocate dynamically for each integer read, but you cannot use realloc
to resize your array, the only logical presumption for the dual pointers arr
and p
is that you are supposed to manually implement realloc
by allocating storage each time with p
, saving the pointer to the allocated block by assignment from arr = p;
at the end of each iteration so you can copy from arr
to the new p
you allocate on the next iteration and then freeing arr
before you assign arr = p;
again to prevent memory leaks.
Putting the above solution together with the code you posted, you can do something similar to the following:
#include<stdio.h>
#include<stdlib.h>
#define CHUNK 5
#define MAXC 256
int main (void)
{
char buf[MAXC] = ""; /* buffer to hold each line */
int *arr = NULL, /* pointer to block holding final array */
*p = NULL, /* temp pointer to allocate for each number */
allocate_size = 0, /* tracks length of array */
temp = 0; /* temp value for integer conversion */
printf ("Enter %d elements of array:\n\n arr[%d]: ", CHUNK, allocate_size);
while (fgets (buf, MAXC, stdin)) { /* read user input into buf */
int rtn; /* variable to hold sscanf return */
if (*buf == '\n') /* check if ENTER alone */
break; /* break loop if so */
/* use sscanf to convert to int, saving return */
if ((rtn = sscanf (buf, "%d", &temp)) == 1) {
/* allocate new storage for allocate_size + 1 integers */
if (!(p = malloc ((allocate_size + 1) * sizeof *p))) {
perror ("malloc-p");
break;
}
for (int i = 0; i < allocate_size; i++) /* copy arr to p */
p[i] = arr[i];
p[allocate_size++] = temp; /* add new element at end */
free (arr); /* free old block of memory */
arr = p; /* assign new block to arr */
}
else if (rtn == EOF) { /* manual EOF generated */
fputs ("(user canceled input)\n", stderr);
break;
}
else { /* not an integer value */
fputs ("error: invalid integer input.\n", stderr);
}
if (allocate_size < CHUNK) /* if arr not full, prompt for next */
printf (" arr[%d]: ", allocate_size);
else
break; /* done */
}
/* output results */
printf ("\nlength is %d\n", allocate_size);
for (int i = 0; i < allocate_size; i++)
printf (" %d", arr[i]);
putchar ('\n');
free (arr); /* don't forget to free what you allocate */
}
Example Use/Output
Without stopping or error:
$ ./bin/arrnorealloc
Enter 5 elements of array:
arr[0]: 10
arr[1]: 20
arr[2]: 30
arr[3]: 40
arr[4]: 50
length is 5
10 20 30 40 50
Stopping early:
$ ./bin/arrnorealloc
Enter 5 elements of array:
arr[0]: 10
arr[1]: 20
arr[2]:
length is 2
10 20
Handling user error:
$ ./bin/arrnorealloc
Enter 5 elements of array:
arr[0]: 10
arr[1]: 20
arr[2]: dogs
error: invalid integer input.
arr[2]: 30
arr[3]: fish
error: invalid integer input.
arr[3]: 40
arr[4]: 50
length is 5
10 20 30 40 50
Memory Use/Error Check
Most importantly when allocating memory dynamically, the error check:
$ valgrind ./bin/arrnorealloc
==5555== Memcheck, a memory error detector
==5555== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5555== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5555== Command: ./bin/arrnorealloc
==5555==
Enter 5 elements of array:
arr[0]: 10
arr[1]: 20
arr[2]: 30
arr[3]: 40
arr[4]: 50
length is 5
10 20 30 40 50
==5555==
==5555== HEAP SUMMARY:
==5555== in use at exit: 0 bytes in 0 blocks
==5555== total heap usage: 7 allocs, 7 frees, 2,108 bytes allocated
==5555==
==5555== All heap blocks were freed -- no leaks are possible
==5555==
==5555== For counts of detected and suppressed errors, rerun with: -v
==5555== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.