I am fairly new to C and am getting stuck with arrays and pointers when they refer to strings. I can ask for input of 2 numbers (ints) and then return the one I want (first number or second number) without any issues. But when I request names and try to return them, the program crashes after I enter the first name and not sure why.
In theory I am looking to reserve memory for the first name, and then expand it to include a second name. Can anyone explain why this breaks?
Thanks!
#include <stdio.h>
#include <stdlib.h>
void main ()
{
int NumItems = 0;
NumItems += 1;
char* NameList = malloc(sizeof(char[10])*NumItems);
printf("Please enter name #1: \n");
scanf("%9s", NameList[0]);
fpurge(stdin);
NumItems += 1;
NameList = realloc(NameList,sizeof(char[10])*NumItems);
printf("Please enter name #2: \n");
scanf("%9s", NameList[1]);
fpurge(stdin);
printf("The first name is: %s",NameList[0]);
printf("The second name is: %s",NameList[1]);
return 0;
}
I think that your problem is in this code:
The problem here is that
scanfrequires that the argument you provide as a location to store the result must be a pointer. If you provide something that isn’t a pointer,scanfwill treat it as though it is and essentially write memory to a random location, crashing the program.Fixing this requires two steps. First, you’ll want to change your declaration of
NameListso that it’s no longer achar *. The reason is that achar *is a single string, whereas you want an array of strings. This would be defined as achar **, a pointer to an array ofchar *s. This might look like this:Next, you’ll need to allocate storage space for the strings. This is tricky and a bit subtle because you have to do two allocations. First, you need to allocate space for the array itself, which you could do like this:
This allocates an array of pointers to characters, but it doesn’t actually set up the pointers in those arrays to point to valid memory locations. To fix this, you’ll want to then iterate across this array and set all of its elements to be pointers to buffers large enough to hold your strings – in this case, buffers of length 10:
Now, you can call
Because
NameList[0]is achar *pointing to the buffer into which the characters should be written.One more comment on your code – rather than allocating an array of one element and then reallocating it to an array of two elements later on, consider just allocating all the space up-front. It’s a bit clearer. Also, since you’re now dealing with a buffer of
char *s, each of which needs to be initialized to point to its own buffer, if you do incremental allocations you’ll need to be sure to initialize all of the newchar *s you allocate to point to a buffer somewhere. If you do this one step at a time there’s a good chance you’ll forget to set up the pointers and cause a crash, whereas if you do it up front there’s no such risk.When it comes time to free the dynamically-allocated memory, you’ll need to run the allocation process in reverse, first freeing the dynamically-allocated buffers for the strings, then freeing the top-level buffer. For example:
This is necessary because
freedoesn’t work recursively. You need to explicitly deallocate all the memory that you allocate.Note that you do not write the code like this:
This will cause all sorts of Bad Things at runtime because if you free the top-level array first, then as you try iterating over its contents freeing the pointers, you’ll be reading memory that you no longer own.
Hope this helps!