Following on from the comments, there are a number of issues you have in your code. First gets
, don't use it, it is a 'hanging' offense -- enough said.
Next, validate all user input. For all you know, a cat could be stepping on the keyboard. Make sure you test what you receive as input, and that it matches what you expect.
Mixing scanf
with line-oriented input (e.g. fgets
or getline
can cause problems for new users. Why? The scanf
family of functions do not remove the '\n'
and instead leaves it in the input buffer (e.g. stdin
). When you then attempt to read with fgets
the first character it sees in stdin
is what? A '\n'
, which it reads and considers a whole line. If you are going to use scanf
to read the number of strings, it is up to you to remove the '\n'
that scanf
left in stdin
.
It's not hard, you can actually just use the assignment suppression operator provided by scanf
in your format string. E.g.:
scanf ("%d%*c", &n);
The *
is the assignment suppression operator, which when used with %*c
simply tells scanf
to read and discard the next character without adding to the match count
(e.g. what scanf
returns).
You will want to use a while
loop instead of a for
loop, (or use an independent index) when filling your array. Why? What if the users cancels input with a ctrl + d (or ctrl + z on windoze). If you are iterating up to n
regardless of what the user does, you can easily attempt to index an array element that you haven't allocated, or allocate for a string that was not entered.
Putting it altogether, you can do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXA = 20, MAXS = 40 }; /* max ptrs and str */
int main (void) {
char *arr[MAXA] = {NULL}, str[MAXS] = "";
int i = 0, n = 0, ndx = 0; /* initialize all variables */
printf ("enter the number of strings: ");
/* use assignment suppression %*c to discard the \n */
if (scanf ("%d%*c", &n) != 1) { /* always validate input */
fprintf (stderr, "error: invalid integer input.\n");
return 1;
}
if (n > MAXA) { /* validate the value of n */
fprintf (stderr, "warning: n > %d, using %d as limit.\n",
MAXA, MAXA);
n = MAXA;
}
printf("Enter the strings\n");
while (ndx < n && fgets (str, sizeof str, stdin)) { /* validate input */
size_t len = strlen (str); /* get the length */
if (str[len - 1] == '\n') /* check for '\n' */
str[--len] = 0; /* overwrite with nul-terminator */
if (!(arr[ndx] = malloc (len + 1))) { /* validate allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
break;
}
strcpy (arr[ndx], str); /* copy to array */
ndx++; /* increment index */
}
printf("\nThe Strings are:\n");
for (i = 0; i < ndx; i++) { /* you have ndx strings not n */
printf (" arr[%2d] : %s\n", i, arr[i]);
free (arr[i]); /* free memory when no longer needed */
}
return 0;
}
Example Use/Output
$ ./bin/nogets
enter the number of strings: 3
Enter the strings
My dog
has a lot
of fleas.
The Strings are:
arr[ 0] : My dog
arr[ 1] : has a lot
arr[ 2] : of fleas.
Now try the same thing and press ctrl + d instead of entering "of fleas."
(you are covered).
Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. Get in the habit of tracking the memory you allocate, and free
it rather than relying on it being done on exit
. That will serve you well as your programs grow more complex.
Look over the code, and make sure you understand what is going on. Let me know if you have any questions.