You ask "But what's wrong with my code while handling input?" in the comments. A fair question. What you have received in answer to your question are the suggestions, from experience, of how to avoid the pitfalls of trying to do line-oriented input with scanf
. The bottom line is that unless you have a very certain and guaranteed input, then using scanf
for line oriented input is usually the wrong tool for the job. Why? Because any variation in your input can lead to matching failures with scanf
, where using other tools would have no problem.
Does that mean scanf
is bad an shouldn't be used? Of course not, it means that for line-oriented input, the better choice is usually a line-oriented libc function like fgets
or getline
. Even character-oriented functions like getchar()
or fgetc
can provide a great deal of flexible input handling. That said, scanf
does have its place, but like everything else, it has its pros and cons. Just weight them against what you need with your job.
On to your code. What's wrong? There are a lot of little things that have been pointed out in the comments. The biggest is char **a=(char**)malloc(n);
. You only allocate n
bytes of storage, NOT n
pointers. Each pointer is 4
or 8
bytes (32/64 bit boxes - in general). So your allocation needs at minimum:
char **a = malloc (n * sizeof *a); /* don't cast the return */
Next issue, you are attempting to fill the lines in a for
loop. While you may have received some number n
, there is no guarantee you will actually have that many lines of data to read. If you don't, then you are forcing the code to read and allocate for input that doesn't exist. A while
loop may fit a little better here.
When you allocate memory, you need to preserve a pointer to the start of each allocation so you can free it when it is no longer needed. Just get in the habit of tracking the memory you allocate and freeing it when you are done with it. While it is freed when you exit, when you begin writing functions that allocate memory, your code will leak like a sieve if you are not in the habit of managing it properly.
Now, with the caveat that we all understand that using fgets
or getline
is the preferred method, and that lines beginning with a newline
will be an issue, you can write your code to use scanf
and allocate storage manually for the strings, in a reasonable manner that has just a few additions to your original code. Take a look and let me know if you have questions.
#include <stdio.h>
#include <stdlib.h>
/* validate memory allocation succeeded */
void checkalloc (void *p)
{
if (!p) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
}
/* empty any characters remaining in input buffer */
void emptyinputbuffer (FILE *fp)
{
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF) {}
}
int main (void)
{
int n, m, i;
n = m = i = 0; /* always initialize your variables */
if (scanf ("%d%d",&n,&m) != 2) { /* scanf has a return -- use it */
fprintf (stderr, "error: failed to read 'm' & 'n'\n.");
exit (EXIT_FAILURE);
}
emptyinputbuffer (stdin); /* remove trailing newline from input buffer */
char **a = malloc (n * sizeof *a); /* you need sizeof to allocate 8 bytes */
checkalloc (a); /* always validate every allocation */
/* allocate storage for first string and validate */
a[i] = malloc (sizeof **a * (m + 1)); /* you could omit sizeof here, =1 */
checkalloc (a[i]);
while (scanf("%[^\n]%*c", a[i]) == 1) /* while instead, lines maybe less */
{
if (++i == n) break;
a[i] = malloc (sizeof **a * (m + 1));
checkalloc (a[i]);
}
if (i < n) n = i; /* save the number of lines actually read */
for (i = 0; i < n; i++) /* print them out */
printf (" line[%2d] : %s\n", i, a[i]);
for (i = 0; i < n; i++) /* free allocated memory */
free (a[i]);
free (a);
return 0;
}
Input
$ printf "4 4\n####\n#5 #\n## #\n#E #\n"
4 4
####
#5 #
## #
#E #
Compile
gcc -Wall -Wextra -o bin/scanf_loop scanf_loop.c
Output
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | ./bin/scanf_loop
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
Memory Use Check
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | valgrind ./bin/scanf_loop
==11065== Memcheck, a memory error detector
==11065== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==11065== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==11065== Command: ./bin/scanf_loop
==11065==
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
==11065==
==11065== HEAP SUMMARY:
==11065== in use at exit: 0 bytes in 0 blocks
==11065== total heap usage: 5 allocs, 5 frees, 52 bytes allocated
==11065==
==11065== All heap blocks were freed -- no leaks are possible
==11065==
==11065== For counts of detected and suppressed errors, rerun with: -v
==11065== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)