So I was trying to pormpt the user to type in a number, and then store that value in a dynamic array. Here is the code first:
#include <stdio.h>
#include <stdlib.h>
//dynamically grow the array
void growArray(int *arr, int *size){
//double the size of the array
printf("Resizing array\n");
int *temp = malloc( *size * 2 * sizeof(int));
printf("Malloc was succesfuly\n");
int i;
for (i = 0; i < *size; i++)
temp[i] = arr[i];
printf("About to free arr\n");
printf("arr: %p", arr);
printf("temp: %p", temp);
free(arr);
arr = malloc( *size * 2 * sizeof(int));
printf("About to change value to arr\n");
arr = temp;
free(temp);
printf("About to change the value of size\n");
*size *= 2;
printf("New size: %d\n", *size);
}
int main(){
int *dynamicArr;
int *size;
*size = 1;
dynamicArr = (int*) malloc(sizeof(int));
int value, i;
i = 0;
do{
printf("\nPlease enter in a int value: ");
scanf("%d", &value);
//check if the array needs to be resizesd;
printf("Checking if size if sufficient\n");
if (i >= *size)
growArray(dynamicArr, size);
if (value != -999){
printf("Adding value to the array\n");
dynamicArr[i] = value;
i ++;
}
}while(value != -999);
for (i = 0; i < *size; i++){
printf("Value of dynamicArr[%d]: %d\n", i, dynamicArr[i]);
}
return 0;
}
As you can see, I have a bunch of print statements, that I so I can see at what point my program is at, and what it is current doing. So, the program initially works. I am able to add in 8 values successfully (and resize the array 3 times, going from size 1 to size 8). But when I add in my 9 value, it has to resize the array, in which the method growArray() is called. But, for some reason I get the following error:
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000000e69010 ***
Segmentation fault (core dumped)
Before the error, the printf("About to free arr") works, but printf("arr: %p", arr); isn't called.
I have no idea why this is happening, some help would be much appreciated.
2 Answers 2
You code should probably look more like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int size = 1;
int *dynamicArr = malloc(size * sizeof(*dynamicArr));
int idx = 0;
while (1) {
int value;
printf("\nPlease enter in a int value: ");
scanf("%d", &value);
if (value == -999) {
break;
}
//check if the array needs to be resizesd
printf("Checking if size if sufficient\n");
if (idx >= size) {
size *= 2;
dynamicArr = realloc(dynamicArr, size * sizeof(*dynamicArr));
}
printf("Adding value to the array\n");
dynamicArr[idx++] = value;
}
int i;
for (i = 0; i < idx; i++) {
printf("Value of dynamicArr[%d]: %d\n", i, dynamicArr[i]);
}
free(dynamicArr);
return 0;
}
Or if you want to stick with your implementation:
#include <stdio.h>
#include <stdlib.h>
//dynamically grow the array
void growArray(int **arr, int *size){
//double the size of the array
printf("Resizing array\n");
int *temp = malloc( *size * 2 * sizeof(int));
printf("Malloc was succesfuly\n");
int i;
for (i = 0; i < *size; i++)
temp[i] = (*arr)[i];
printf("About to free arr\n");
printf("arr: %p\n", *arr);
printf("temp: %p\n", temp);
free(*arr);
printf("About to change value to arr\n");
*arr = temp;
printf("About to change the value of size\n");
*size *= 2;
printf("New size: %d\n", *size);
}
int main() {
int size = 1;
int *dynamicArr = malloc(size * sizeof(*dynamicArr));
int idx = 0;
while (1) {
int value;
printf("\nPlease enter in a int value: ");
scanf("%d", &value);
if (value == -999) {
break;
}
//check if the array needs to be resizesd;
printf("Checking if size if sufficient\n");
if (idx >= size) {
growArray(&dynamicArr, &size);
}
printf("Adding value to the array\n");
dynamicArr[idx++] = value;
}
int i;
for (i = 0; i < idx; i++){
printf("Value of dynamicArr[%d]: %d\n", i, dynamicArr[i]);
}
free(dynamicArr);
return 0;
}
BTW, you can use memcpy to copy the whole existing array to the temp array.
5 Comments
size. You want to changes to be visible to the calling function. You allocate new space in temp, which means you get a new address. You then want the calling function to know that the new larger "array" starts there, so you must pass a pointer to the variable which stored the last address, a.k.a dynamicArr, so you should pass &dynamicArr. only that way you could make changes to the value stored in it (the value, in this case, is the address where the array starts)realloc() directly to the target variable. Because if realloc() fails, then the original pointer is lost, resulting in a memory leak. always use a 'temp' variable for the initial assignment, then check (!=NULL) and only if not NULL then assign tot he target variable. AND if that pointer is dereferenced when realloc() failed, then the program will be trying to access address 0 (from the NULL returned from realloc()) which will result in a seg fault event.There are a couple of problems in your original code.
(a) The parameter arr is passed to growArray by value, so your assignments arr = malloc(...) and arr = temp are not updating the variable referenced in main() only the copy that is local to growArray. On the other hand, when you call free(arr) you are freeing the buffer pointed to by the variable dynamicArr in main(). This is the immediate cause of your segfault.
(b) When you assign arr = temp then free(temp); you leak the buffer you malloc()ed just above, then free the buffer you assigned arr to point to (leaving it dangling).
void growArray(int *arr, int *size){
When entering growArray, arr points to a buffer, A
...
int *temp = malloc( *size * 2 * sizeof(int));
temp is initialized to point to a new buffer, B
...
free(arr);
the original buffer, A, is freed. The local variable arr is now a dangling pointer, as is whatever pointer the caller holds that was passed into this routine by value.
arr = malloc( *size * 2 * sizeof(int));
arr is set to a freshly allocated buffer, C.
...
arr = temp;
arr is set to alias temp, pointing to the buffer B. The buffer C is leaked.
free(temp);
Buffer B, pointed to by both temp and arr is freed. They are both now dangling pointers. When arr is later
...
}
Both tmp and arr go out of scope. The buffers B and C are leaked.
int main(){
int *dynamicArr;
int *size;
*size = 1;
dynamicArr = (int*) malloc(sizeof(int));
dynamicArr points to a malloced buffer ... do{ ... if(...){ growArray(dynamicArr, size); ... }
The first time this if condition passes, the value of dynamicArr is passed as the argument arr to growArray. growArray frees the buffer it points to and then allocs and leaks some memory without affecting the local value of dynamicArr. dynamicArr is now a dangling pointer.
if (value != -999){
...
dynamicArr[i] = value;
And then this accesses the dangling pointer and segfaults.
int *size; *size = 1;-->int size = 1;..growArray(dynamicArr, size);-->growArray(dynamicArr, &size);void growArray(int *arr, int *size)-->void growArray(int **arr, int *size)orint *growArray(int *arr, int *size)(return new array) You can also usereallocinstead.arr = malloc( *size * 2 * sizeof(int));occurs memory leak.arr = temp; free(temp);Do notfreehere.-->arr = temp;reallocto double you array.