C program crashes after freeing the pointers in an array of char * - arrays

I'm a student learning C and I was puttering around with arrays of strings and malloc().
I have the following code that is supposed to load an array of strings (statically created) with dynamically created strings (please forgive / correct me if my terminology does not align with the code I have).
The problem is, once I go to free that memory, I get the following error: free(): invalid pointer
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define RAM_SIZE 5
char* ram [RAM_SIZE];
int next_free_cell = 0;
void freeAndNullRam(){
for (int i = 0 ; i < RAM_SIZE ; i++){
printf("%d\n", i);
free(ram[i]);
ram[i] = NULL;
}
}
int main(int argc, const char *argv[])
{
for (int i= 0; i < RAM_SIZE; i++){
ram[i] = (char*)malloc(sizeof(char*)*5);
ram[i] = "aaaa";
}
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
if(!empty){
printf("%s\n", ram[i]);
}
}
freeAndNullRam();
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
printf("%d\n", empty);
}
return 0;
}
I know the issue is definitely in the freeAndNullRam() function (obviously), but I don't understand why. My understanding is that at compile time, an array of 5 pointers to char arrays is created, but to actually fill the cells of the array, I need to malloc them some memory. Why does the program complain when I free the pointers in the array, but not when I give them memory?
Thanks!

ram[i] = "aaaa"; reassigns the pointers at a[i] to point to static memory, discarding the result of malloc. Later on you pass those pointers to free, which fails because they were not the result of an *alloc function.
Use strcpy to instead copy the string from static memory into your allocated destination.
strcpy(a[i], "aaaa")

Here's a reworked version of your code to be more idiomatic C:
#include <stdio.h>
#include <stdlib.h>
// Create an array of arbitrary size
char* alloc_array(size_t size) {
// calloc() will give you a pre-zeroed (NULL) allocation, malloc() may not
return calloc(size, sizeof(char*));
}
// Clears out all entries in the array, leaving only NULL
void clear_array(char* array, size_t size) {
for (size_t i = 0; i < size; ++i) {
// free(NULL) doesn't do anything, and is easier than a test
free(array[i]);
array[i] = NULL;
}
}
// Clears, then frees the array
void free_array(char* array, size_t size) {
clear_array(array, size);
free(array);
}
int main(int argc, const char *argv[])
{
// Whenever possible use local variables, not global variables
size_t size = 5;
char* entries = alloc_array(size);
for (size_t i = 0; i < size; ++i) {
// Make a copy with strdup() so this can be released with free()
// later on. A string like "..." is static, it was never allocated.
entries[i] = strdup("aaaa");
}
for (size_t i = 0; i < size; i++) {
// Express conditions in the if statment directly
if (entries[i] != NULL) {
printf("%s\n", ram[i]);
}
}
clear_array(entries);
for (size_t i = 0; i < size; i++) {
printf("%d\n", entries[i] != NULL);
}
// Don't forget to release any allocated memory.
free_array(entries);
return 0;
}
There's a lot of bad habits in your original code you should work to expunge as quickly as possible so these things don't take root. In particular, global variables are a huge problem that need to be avoided.
One thing to remember is unless something was explicitly allocated with malloc() or a variant like calloc(), or was given to your code with an understanding that it was allocated in such a fashion, you should not call free() on it.
Not every pointer was allocated dynamically, and not every dynamically allocated pointer was allocated with malloc(). Some C code can be very confusing as a result of this.

C's syntax strongly suggests that "aaaa" is a "string". People even talk of this syntax that way: they call it "strings". But "aaaa" is nothing such. It's the unfortunately named string literal, which is not a string - neither in C nor in C++. A char * is not a string either - it's a pointer-typed value. It's used to represent strings, but itself is not a string - not even close.
You have quite reasonably expected that "aaaa" might behave like any other rvalue of the "obvious" type. Alas, while 1 is an integer literal of type int, "aaaa" is a string literal of a pointer type const char * - its value is not a string, but a pointer!
It's as if when you wrote 42, C gave you a const int * pointing to 42. That's what "string" literals do. That's the awfully deplorable side of C :(
In C++, there actually is a string type (std::string), and you can even write literals of that type with a new syntax introduced in C++11: "aaaa"s is an rvalue* of type std::string, and you can assign them exactly as you would expect of any other value type like int.
Since you're already thinking a bit like in C++, perhaps you can investigate that language next. It takes much less effort to do plenty of basic things in C++ compared to C.
*technically rvalue reference

Related

Question about pointer to array used in malloc/free

I saw the following code:
#include <stdlib.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
free(vals);
}
int main(int argc, char **argv)
{
foo(*(argv[1]));
return 0;
}
This lines makes me very uncomfortable:
free(vals);
vals is a pointer pointing to an array. This looks right, but I just have a difficult time internalizing it, I do not know why.
I am more used to the following style:
int *p = (int*)malloc(n * sizeof(int));
......
free(p);
In this code, p is a pointer pointing to the start of a memory region for some integers, the malloc and free are symmetric in that they both work on a pointer type; yet the original code has malloc() working on a pointer to an array and free() a pointer.
Out of curiosity, I modified the original code:
free(vals); ==> free(*vals);
I was expecting this change will fail at compiler, the reason is *vals is an array now. But gcc is fine and valgrind does not complain memory leak.
I know C has a thing called array degenerates to pointer at function call. But I just cannot internalize this stuff. Sorry writing so long to describe a problem, wish you could see my struggle. Is there a definitive doc/stackoverflow/blog to clear this up - best C99 or later?
Thanks!
writing free(*vals); is same as writing free(vals);
edited your code to clear that a little bit
#include <stdlib.h>
#include <stdio.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
printf("*val is %p\n", *vals);
printf("val is %p\n", vals);
printf("&val is %p\n", &vals);
free(vals);
}
int main()
{
foo(10);
return 0;
}
and this is the output:
*val is 0000018190365d50
val is 0000018190365d50
&val is 0000005d9dbff7b8
note that vals is Array pointer which means that its base type is an array of n integers where the pointer val is created in that stack and points to the whole array, not the first element only and that array is created in the heap, to illustrate, look at the following graph:
so for example if you write:
printf("val is %p\n", vals);
printf("val+1 is %p\n", vals+1);
the output will be :
val is 00000207ef0c5d50
val+1 is 00000207ef0c5d78
note the difference between the 2 is about 40 bytes as val points to the whole array not only one element as in case of int *p = (int*)malloc(n * sizeof(int));
note that when I say it points to the whole array, I also mean it points to the base address of the array.
in case of *Vals, look at the next graph:
*Vals is just an address of the first element of the array which is by the way is same as the base address of the array.
refer to free() manual, they said:
The free() function frees the memory space pointed to by ptr, which
must have been returned by a previous call to malloc(), calloc() or
realloc(). Otherwise, or if free(ptr) has already been called before,
undefined behavior occurs. If ptr is NULL, no operation is performed.
and what does malloc() function return ?
it returns the base address of your reserved space in heap, so writing free(vals); is same as writing free(vals);
This codes uses dynamic VLA.
I think that it may be easier to understand if the code is reformulated with a typedef.
void foo(char n)
{
typedef int T[n];
T *vals = malloc(sizeof(T));
...
free(vals);
}
Now it looks like a tivial use of a single dynamic object.
To access elements of an array first the pointer has to be dereferenced *vals forming an array, which decays to int* pointer suitable for [] operator.

Array of pointers in C with easy iteration

Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.
If I create an array of string in C, it should look like this right?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.
That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
Now my question:
Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
Then I could use the NULL pointer to control the iterator:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.
Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.
In cases like this, it ok to do this? Or is it considered something bad?
Is this technique only used with char pointers because char type has a size of only 1 byte?
I miss having a foreach iterator in C...
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.
It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
In C this is quite a common pattern, and it has a name. You're simply using a sentinel value.
As long as your list can not contain null pointers normally this is fine. It is a bit error-prone in general however, then again, that's C for you.
It's ok, and is a commonly used pattern.
As an alternative you can use a struct, in there you can create a size variable where you can store the current size of the array, and pass the struct as argument. The advantage is that you don't need to iterate through the entire array to know its size.
Example:
Live demo
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
char **strArr;
int size;
} MyStruct;
void PrintValues(MyStruct arr) //pass the struct as an argument
{
for (int i = 0; i < arr.size; i++) //use the size passed in the struct
printf("%s\n", arr.strArr[i]);
}
int main()
{
// using the variable to extract the size, to avoid silent errors
// also removed the cast for the same reason
char **strArr = malloc(sizeof *strArr * 5);
if (strArr == NULL) return EXIT_FAILURE;
strArr[0] = "Car";
strArr[1] = "Car#1";
strArr[2] = "Car#2";
strArr[3] = "Tree";
strArr[4] = "Tree#1";
MyStruct strt = { strArr, 5 }; // initialize the struct
PrintValues(strt); //voila
free(strArr); // don't forget to free the allacated memory
return EXIT_SUCCESS;
}
This allows for direct access to an index with error checking:
// here if the array index exists, it will be printed
// otherwise no, allows for O(1) access error free
if(arr.size > 6){
printf("%s\n", arr.strArr[6]);
}

ERROR "realloc(): invalid next size" when allocating memory to const char*** variable

I have a function
populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter)
which take a pointer to an array of strings and the number of elements in the array as parameters.
I allocate initial memory to that array using malloc(0). Specs say that it will either return a null pointer or a unique pointer that can be passed to free().
int currentAvailableExtensionCount = gCounter;
This variable will store number of string in gAvailableExtensions.
Inside this for loop
for (int i = 0; i < availableExtensionCount; ++i)
I have this piece of code
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].name);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
&availableExtensionProperties[i].name,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
where
availableExtensionProperties[i].name
returns a string.
This is how that struct is defined
typedef struct Stuff {
char name[MAX_POSSIBLE_NAME];
...
...
} Stuff;
realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
should add memory of size sizeOfAvailableExtensionName to *gAvailableExtensions de-referenced array.
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
&availableExtensionProperties[i].name,
sizeOfAvailableExtensionName);
should copy the string (this sizeOfAvailableExtensionName much memory) from
&availableExtensionPropterties[i].name
address to
&(*gAvailableExtensions)[currentAvailableExtensionCount]
address.
But I don't think the code does what I think it should because I'm getting this error
realloc(): invalid next size
Aborted
(core dumped) ./Executable
EDIT: Full code
uint32_t populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter) {
int currentAvailableExtensionCount = gCounter;
void* reallocStatus;
uint32_t availableExtensionCount = 0;
vkEnumerateInstanceExtensionProperties(
VK_NULL_HANDLE, &availableExtensionCount, VK_NULL_HANDLE);
VkExtensionProperties availableExtensionProperties[availableExtensionCount];
vkEnumerateInstanceExtensionProperties(
VK_NULL_HANDLE, &availableExtensionCount, availableExtensionProperties);
for (int i = 0; i < availableExtensionCount; ++i) {
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].extensionName);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
availableExtensionProperties[i].extensionName,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
}
return currentAvailableExtensionCount;
}
This is how an external function calls on that one,
uint32_t availableExtensionCount = 0;
availableExtensions = malloc(0);
availableExtensionCount = populateAvailableExtensions(&availableExtensions);
and
const char** availableExtensions;
is declared in header file.
EDIT 2: Updated the code, now gCounter holds the number of elements in gAvailableExtensions
This loop is totally messy:
for (int i = 0; i < availableExtensionCount; ++i) {
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].extensionName);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
availableExtensionProperties[i].extensionName,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
}
I assume the only lines that does what you expect them to do, are the lines for (int i = 0; i < availableExtensionCount; ++i) and ++currentAvailableExtensionCount;
First, the typical way to use realloc is like this:
foo *new_p = realloc(p, new_size);
if (!new_p)
handle_error();
else
p = new_p;
The point is that realloc will not update the value of p if a reallocation happens. It is your duty to update 'p'. In your case you never update *gAvailableExtensions. I also suspect that you don't calculate sizeOfAvailableExtensionCount correctly. The operator sizeof always return a compile time constant, so the realloc doesn't actuall make any sense.
The memcpy doesn't actally make any sense either, since you are copying the string into the memory of a pointer array (probably with an additional buffer overflow).
You said that *gAvailableExtensions is a pointer to an array of pointers to strings.
That means that you have to realloc the buffer to hold the correct number of pointers, and malloc memory for each string you want to store.
For this example, I assume that .extensionName is of type char * or char[XXX]:
// Calculate new size of pointer array
// TODO: Check for overflow
size_t new_array_size =
(currentAvailableExtensionCount + availableExtensionCount) * sizeof(*gAvailableExtensions);
char **tmp_ptr = realloc(*gAvailableExtensions, new_array_size);
if (!tmp_ptr)
{
//TODO: Handle error;
return currentAvailableExtensionCount;
}
*gAvailableExtensions = tmp_ptr;
// Add strings to array
for (int i = 0; i < availableExtensionCount; ++i)
{
size_t length = strlen(availableExtensionProperties[i].extensionName);
// Allocate space for new string
char *new_s = malloc(length + 1);
if (!new_s)
{
//TODO: Handle error;
return currentAvailableExtensionCount;
}
// Copy string
memcpy (new_s, availableExtensionProperties[i].extensionName, length + 1);
// Insert string in array
(*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;
++currentAvailableExtensionCount;
}
If you can guarantee that the lifetime of availableExtensionProperties[i].extensionName is longer than *gAvailableExtensions, you can simplify this a little bit by dropping malloc and memcpy in the loop, and do:
char *new_s = availableExtensionProperties[i].extensionName;
(*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;
Some harsh words at the end: It seems like you have the "Infinite number of Monkeys" approach to programming, just hitting the keyboard until it works.
Such programs will just only give the illusion of working. They will break in spectacular ways sooner or later.
Programming is not a guessing game. You have to understand every piece of code you write before you move to the next one.
int currentAvailableExtensionCount =
sizeof(*gAvailableExtensions) / sizeof(**gAvailableExtensions) - 1;
is just a obfuscated way of saying
int currentAvailableExtensionCount = 0;
I stopped reading after that, because i assume that is not what you intend to write.
Pointers in c doesn't know how many elements there are in the sequence they are pointing at. They only know the size of a single element.
In your case *gAvailableExtensions is of type of char ** and **gAvailableExtensions is of type char *. Both are pointers and have the same size on a typical desktop system. So on a 64 bit desktop system the expression turns into
8/8 - 1, which equals zero.
Unless you fix this bug, or clarify that you actually want the value to always be zero, the rest of the code does not make any sense.

Calls to getChar and printf seem to modify unrelated data

I have written a function that allocates and initialises a 2D array, like this -
static state **symbols;
void initNFAStates()
{
int i,j;
numStates = 256;
symbols = (state**)malloc(numStates * sizeof(char));
for(i = 0;i < numStates;i++)
{
symbols[i] = (state*)malloc(NUMSYMBOLS * sizeof(state));
for(j = 0;j < NUMSYMBOLS;j++)
symbols[i][j] = 0;
}
}
and a function to print this array, like this -
void printNFAStateTable()
{
int i, j;
for(i = 0;i < numStates;i++)
{
printf("%d \t",i);
for(j = 0;j < NUMSYMBOLS;j++)
printf("%ld",symbols[i][j]);
printf("\n");
}
}
When called consecutively from the main() function, they both work fine. However, the code as follows results in a segfault after reading only the first 32 lines from the array.
int main(int argc, char **argv)
{
int i;
clock_t begin, end;
double timeTaken;
currNFAState = 0;
initNFAStates();
if(getChars(argc,argv) != NULL)
{
printNFAStateTable();
begin = clock();
regex();
...
Similarly, the printf() function causes the same issue, but only when printing a floating point number -
int main(int argc, char **argv)
{
int i;
clock_t begin, end;
double timeTaken;
currNFAState = 0;
initNFAStates();
printf("A floating point number - %f",0.0124f);
printNFAStateTable();
...
I am aware this has to do with the symbols array being static, as the issue does not appear when the array is global. Could anyone explain why this occurs?
Given this declaration:
static state **symbols;
This allocation is incorrect:
symbols = (state**)malloc(numStates * sizeof(char));
The type of *symbols is state *; this is the type of the elements of the array you are dynamically allocating, and I feel confident in asserting that pointers on your machine are larger than char is. This would be a more appropriate allocation:
symbols = malloc(numStates * sizeof(*symbols));
(Note that you do not need to cast the return value of malloc(), and there are good reasons not to do so.)
Having not allocated memory sufficient for all the pointers you want to use, your program exhibits undefined behavior when it tries to access elements at indices that would fall outside the bounds of the allocation. That UB very easily could manifest in the form of library functions modifying memory you did not expect them to modify.
This is not doing what you expect:
symbols[i][j] = 0;
The reason is that this assumes a singularly allocated block of memory organized as a 2D array. That's not what you've created.
Your code indicates the first dimension is sized at 256, which would look like this:
state symbols[256][NUMSYMBOLS];
If you allocated globally or on the stack. This would be a single block of RAM sized as 256 * NUMSYBOLS * sizeof( state ), where each row is advanced NUMSYMBOLS * sizeof( state ).
What you're doing, however, is create an a array of pointers in one block of RAM, and then allocating additional blocks of RAM for each row. They are unrelated such that access is not going to work using the 2D array syntax.
What you need is first to access the pointer to the row, conceptually:
state *state_row = symbols[ i ];
This gives you the row. Now, get the column;
stat * state_cell = state_row[ j ];
This is expanded to show how to think about it, you can easily choose other specific means of accessing the appropriate cells.

seg fault from 2d array allocation

i have a struct "cell" defined as
typedef struct{
int id;
terrainType terrain;
} cell;
i then make a 2d array of cells with
cell** makeCellGrid(int sizeX, int sizeY)
{
cell** theArray;
int i;
theArray = (cell**) malloc(sizeX*sizeof(cell*));
for ( i = 0; i < sizeX; i++)
{
theArray[i] = (cell*) malloc(sizeY*sizeof(cell));
}
return theArray;
}
at first i thought this was working fine but a few seg faults later i discovered that with some values (e.g. makeCellGrid(32, 87) ) it breaks.
im fairly fresh with C pointers and memory junk and was hoping some one could point me in the right direction here.
with lower number bounds i had no issue accessing it with
map[i][j].id = x;
and so on
EDIT: forgot to add, from testing, the seg fault originate from
theArray[i] = (cell*) malloc(sizeY*sizeof(cell));
The code lacks error checking for the malloc() system call.
So if the first call to malloc() failed the second one (in the loop) tries to assign memory to NULL which indeed leads to the segmentation violation your are witnessing.
You might consider modifing you code like so:
#include <stdlib.h>
typedef struct {
int id;
TerrainType terrain;
} CellType;
void freeCellGrid(CellType ** ppCells, size_t sizeX)
{
size_t i = 0;
for (; i < sizeX; ++i)
{
free(ppCells[i]);
}
free(ppCells);
}
CellType ** makeCellGrid(size_t sizeX, size_t sizeY)
{
CellType ** ppCells = malloc(sizeX * sizeof(*ppCells));
if (ppCells)
{
size_t i = 0;
for (; i < sizeX; ++i)
{
ppCells[i] = malloc(sizeY * sizeof(**ppCells));
if (NULL == ppCells[i])
{
freeCellGrid(ppCells, i);
ppCells = NULL;
break;
}
}
}
return ppCells;
}
Notes on my modifications:
Always check system calls for errors (in the case of malloc() on error NULL is returned)
Better use an unsigned type to access memory/array indicies; size_t is meant for this
In C there is no need to cast the value returned by a void * function like malloc()
Always try to initialise variables as soon as possible; un-initilaised variables very easily lead to "irrational" behaviour of the application
If working with pointers, it might be helpfull to 'code' the level of indirection into their names (I did this here by using the prefix pp to indicated that it's a 2-level indirection)
types are different from variables: One way to distinguish this is by starting type names using capitals (CellType) and variables using small letters (ppCells).
If allocating memory to a pointer and it matters that the size of the allocated memory some suits the pointer's type it's always more secure to use the (dereferenced) pointer itself as argument to the sizeof operator then some type. As the declaration of the pointer the memory is allocated to might be changed during develpment and the adjustment of the argument to malloc() will be forgotten. To cut it short: doing as I did is less error prone.
If encapsulating the dynamical creation of structures (including arrays) it is a could idea to also implement a method which de-allocates it (here: freeCellGrid()). Even better start of with coding this deallocator first, as then you have it by hand when coding the allocator's error handling (as shown for the second call to malloc()).

Resources