Function to resize array not working [C] - c

This is a program for studying purposes.
I'm trying to increment an array size while the program is running, until its size is equal to 12. But i'm getting an error and i don't know why. Will appreciate your help.
#include <stdlib.h>
#include <stdio.h>
void incrementSize(int **arr, int *currentSize);
void swap(int **a, int **b);
void main() {
int i = 0,
size = 3;
int *array = (int*)malloc(size * sizeof(int));
while (size < 12) {
if (i == size) //If the logical size is equal to the physical size increment the size of the array.
incrementSize(&array, &size);
array[i] = i + 1;
i++;
}
for (int j = 0; j < size; j++) //Prints the array
printf("%d ", array[j]);
printf("\n");
}
I wrote this function to increment the size of a given array and returns the new size.
void incrementSize(int **arr, int *currentSize)
{
int newSize = 2 * (*currentSize);
int *tmpArr = realloc(*arr, newSize * sizeof(int));
if (!tmpArr)
//If the allocation didn't work
{
printf("ERROR. Memory reallocation failed!");
free(tmpArr);
}
else
//If it worked swap the addresses of "tmpArr" and "arr" and then free "tmpArr"
{
swap(arr, &tmpArr);
free(tmpArr);
*currentSize *= 2;
}
}
and also wrote this function to swap the addresses of two given arrays
void swap(int **a, int **b)
{
int* tmp;
tmp = *a;
*a = *b;
*b = tmp;
}

realloc actually frees storage pointed by given pointer.
If there is not enough memory, the old memory block is not freed and
null pointer is returned.
If argument is NULL, the behavior is the same as calling malloc(new_size).
Code you wrote would free already freed memory.

Related

C SegFault fixed by print?

I have the task to write a program in C. The program should be able to check for parameters and create arrays that are as big as the parameter I gave. I have to fill the array with random numbers. Works fine so far. Later on my task is to sort the array using pointers. First thing is I did not quite understand how pointers work but I made the sorting work so far. The only problem is, that I can only sort to a size of 4. If my parameter is bigger than 4 I get the first 4 numbers sorted and then a Segmentation fault. I cannot find the issue but the fun part is, that if I add a printf just to print my parameter again it works fine for any parameter I want! I do not know what is happening!
Here is the exact task again, because I think I didn't describe it that well:
To do this, create a dynamic pointer field of the same size and initialize it with pointers to the elements of the int field. When sorting, the pointers should now be sorted so that the first pointer points to the smallest int value, the second to the next largest value, and so on.
int main(int argc, char *argv[]) {
int *array;
int **arrpointer;
int size = atoi(argv[1]);
if (size == 0) {
fprintf(stderr, "Wrong parameter!\n");
return EXIT_FAILURE;
}
//printf("Array-Size : "); //First I had it with scanf, which works perfectly fine without a print
//scanf("%d", &size);
printf("Input%d", size); //This is the print I need somehow!
// allocate memory
array = (int *)malloc(size * sizeof(int)); // Init Array
arrpointer = (int **)malloc(size * sizeof(int)); // Init Pointer Array
//Check Pointer array
if (arrpointer != NULL) {
printf("Memory allocated\n\n");
} else {
fprintf(stderr, "\nNo free memory.\n");
return EXIT_FAILURE;
}
if (array != NULL) {
printf("Memory is allocated\n\n");
//Fill Array
for (int i = 0; i < size; i++) {
array[i] = rand() % 1000; //I know it is not random right now, will add later
int *temp = &array[i];
arrpointer[i] = temp; //Pointer fill
}
} else {
fprintf(stderr, "\nNo free memory to allocate.\n");
return EXIT_FAILURE;
}
shakersort(arrpointer, size); //Function to sort pointers
zeigeFeld(arrpointer, size); //Function to Print
free(array);
free(arrpointer);
return EXIT_SUCCESS;
}
I know its a bit confusing, I am sorry.
I will also add the code where I sort it below.
void swap(int **a, int **b) {
int ram;
ram = **a;
**a = **b;
**b = ram;
}
void shakersort(int **a, int n) {
int p, i;
for (p = 1; p <= n / 2; p++) {
for (i = p - 1; i < n - p; i++)
if (*a[i] > *a[i+1]) {
swap(&a[i], &a[i + 1]);
}
for (i = n - p - 1; i >= p; i--)
if (*a[i] < *a[i-1]) {
swap(&a[i], &a[i - 1]);
}
}
}
This is the code I tried to build for the pointers and it works fine so far.
I hope someone can help or give some input to why my print fixes the problem. I really dont understand!
Thank you for your time and help, let me know if I should add anything!
The program has undefined behavior because the allocation size is incorrect for the array:
arrpointer = (int **)malloc(size * sizeof(int));
allocates space for size integers, but it should allocate space for size pointers to int, which on 64-bit systems are larger than int. Use this instead:
arrpointer = (int **)malloc(size * sizeof(int *));
Or use the type of the destination pointer:
arrpointer = malloc(sizeof(*arrpointer) * size);
This latter syntax is much safer as it works for any non void pointer type.
Note however that this array of pointers is overkill for your purpose. You should just implement the sorting functions on arrays of int:
void swap(int *a, int *b) {
int ram = *a;
*a = *b;
*b = ram;
}
void shakersort(int *a, int n) {
int p, i;
for (p = 1; p <= n / 2; p++) {
for (i = p - 1; i < n - p; i++) {
if (a[i] > a[i + 1]) {
swap(&a[i], &a[i + 1]);
}
}
for (i = n - p - 1; i >= p; i--) {
if (a[i] < a[i - 1]) {
swap(&a[i], &a[i - 1]);
}
}
}
}
Whether the above code actually sorts the array is unclear to me, I never use shakersort.
why do you use pointers before printf??
first you need to know what the pointer is:
the pointer is some kind of variable that contains address of some another variable.
for example:
int b = 2;
int * a = &b;
a variable include the address of variable b. then if you print ((a)) it will give you hex number which is the address of b. if you print ((*a)), compiler will print what in the address that int the variable a and print the amount of number in address of cell b(that means 2).
now i guess you understand what the pointer is, look again at your code and correct the mistakes.
I updated my code from
arrpointer = (int **) malloc(size * sizeof(int));
to
arrpointer = malloc(sizeof *arrpointer * size);
And it works fine!
Thank you all for your help!

Passing array of structs with reference - segmentation fault

#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X** a, int size){
for (int i = 0;i < size; i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container = (struct X*)malloc(sizeof(struct X) * n);
read_record(&container, n);
}
I created a 1D array of size n, then I passed it by reference to the function read_record. However, when I execute the program, there is a segmentation fault. What is the problem?
EDIT:
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. That's why I want to send the array as a reference. If I did it in main then I would write:
container = realloc(container, (n + 10) * sizeof(Struct X));
How can I do this in the function?
container is already a pointer, you don't need to pass the address-of the pointer, instead:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X *a, size_t size)
{
for (size_t i = 0; i < size; i++) {
a[i].deg = 0;
}
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
read_record(container, n);
}
also, prefer size_t to store the number of allocated objects.
Nitpick: read_record doesn't seem a good name for a function that modifies the contents of the records.
EDIT: As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
Same approach but returning a reallocated container:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
struct X *read_record(struct X *a, size_t size)
{
struct X *new = realloc(a, sizeof(struct X) * size);
if (new != NULL)
{
for (size_t i = 0; i < size; i++) {
new[i].deg = 0;
}
}
return new;
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
container = read_record(container, n * 2);
if (container == NULL)
{
fprintf(stderr, "Can't read record\n");
exit(EXIT_FAILURE);
}
}
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
The pointer is passed by value, so to save the changes and have them usable outside the function scope, after the function ends, i.e. in main, a pointer to pointer must be the argument, and the address of the pointer must be passed, your overall assessment is correct.
Your implementation, however, is not correct, here's how you shoud do it:
Live demo
void read_record(struct X **a, int size) //double pointer
{
*a = realloc(*a, sizeof **a * (size + 10)); //reallocate memory for 20 ints
if (*a == NULL)
{
perror("malloc");
}
for (int i = 0; i < size + 10; i++) //assing new values
{
(*a)[i].deg = 1;
}
}
int main()
{
int n = 10;
struct X *container = malloc(sizeof *container * n); //original allocation
//the pointer now has space for 10 ints
if (container == NULL)
{ //check allocation errors
perror("malloc");
}
for (int i = 0; i < n; i++) //assign values
{
container[i].deg = 0;
}
read_record(&container, n); //pass by reference
//the pointer now has space for 20 ints
}
Alternatively you can return the pointer instead, refering to David Ranieri's answer.
The first function parameter has the pointer to pointer type struct X**. So dereferencing the parameter a you will get a pointer of the type struct X*. Now you may apply the subscript operator that yields lvalue of the type struct X..
That is the function definition will look like
void read_record(struct X** a,int size){
for (int i=0;i<size;i++){
( *a )[i].deg = 0;
}
}
Or this statement
( *a )[i].deg = 0;
may be substituted for this statement
a[0][i].deg = 0;
On the other hand, there is no great sense to declare the first parameter as having the type struct X**. The function can look simpler as for example
void read_record(struct X* a,int size){
for (int i=0;i<size;i++){
a[i].deg = 0;
}
}
and be called like
read_record( container, n );
When you call read_record you pass a pointer to a pointer to the first element of an array of X structures.
But inside the read_record you treat it as a pointer to the first element of an array of pointers to X structures (i.e. as an array of pointers to X). There's a subtle but very important difference here.
If you want to emulate pass-by-reference for the pointer variable, you need to dereference it inside the read_record to get the original pointer (and remember that then you have an array of objects, not pointers):
(*a)[i].deg = 0;
Double pointer is the problem. The code should be:
void read_record(struct X* a,int size){ // Check the change
for (int i=0;i<size;i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container=(struct X*)malloc(sizeof(struct X)*n);
read_record(container,n); // Check the change
}

Expand a C array inside a function

This works in a main, but breaks when put into a function. I'm not sure how to reassign the pointer after passing into a function.
void expandArray(int** arr[], int* size) {
int *temp;
*temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
arr[i] = temp[i];
printf("to arr: %d \n", arr[i]);
}
*size = *size * 2;
free(temp);
}
main(){
int *arr;
arr = (int*) malloc(maxSize * sizeof(int));
if ....
expandArray(arr, &arrSize);
// use bigger arr for other stuff
}
In main, arr is declared as int *arr. When main calls expandArray, it should pass a pointer to arr, which is written &arr and has type int **a.
However, you declared the parameter to expandArray as int **arr[], adding additional brackets. Those are unnecessary and change the type, and your compiler should have warned you about that. Pay attention to compiler warnings. Be sure you understand them, and resolve them before proceeding.
In expandArray, you use both arr[i] and temp[i] to access the array. However, arr[i] is not a correct way to access array elements. When the declaration of the arr parameter is corrected, it will be int **arr, and it will not be proper to refer to an element of the array as arr[i]. It will be (*arr)[i].
Commonly, to make this a little less confusion, authors will use a temporary variable to hold the pointer, so they do not need the extra asterisk:
int *NewArray = malloc(...); // Get new space.
*arr = NewArray; // Send new address to caller.
...
NewArray[i] = temp[i]; // Use temporary variable for access.
Some other points:
When calling malloc, use sizeof *p, where p is the pointer being assigned to, rather than sizeof(int). This is better because, if you later want to change the type for p, it only has to be changed in its declaration, not also in the sizeof. Then there is less likely to be a mistake where it is changed in one place and not another.
Do not cast the result of malloc. This is unnecessary in C, although it is required in C++.
main should be declared as int main(void) or int main(int argc, char *argv[]), not as main(). (C implementations may also provide for other forms.)
Use size_t for sizes of arrays, not int, and either size_t or ptrdiff_t for indices of arrays.
Overall, the code could be:
#include <stdio.h>
#include <stdlib.h>
void expandArray(int **arr, int *size)
{
// Record old pointer and size in temporary variables for convenience.
int *OldArray = arr;
size_t OldSize = *size;
// Prepare new size and pointer.
size_t NewSize = 2 * OldSize;
int *NewArray = malloc(NewSize * sizeof *NewArray);
// Handle allocation failure.
if (!NewArray)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
// Copy data from old array to new array.
for (size_t i = 0; i < OldSize; ++i)
NewArray[i] = OldArray[i];
// Send new size and pointer to caller.
*size = NewSize;
*arr = NewArray;
// Release old memory.
free(OldArray);
}
int main(void)
{
int *arr;
arr = malloc(InitialSize * sizeof *arr);
if (...)
expandArray(&arr, &arrSize);
// use bigger arr for other stuff
}
I think the arr sould be int ** type.
void expandArray(int** arr, int* size) {
int *temp;
temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
(*arr)[i] = temp[i];
printf("to arr: %d \n", (*arr)[i]);
}
*size = *size * 2;
free(temp);
}
If you just want to expand the array size, you can use realloc.
And the extended area should be initialized using memset.
void expandArray(int** arr, int* size) {
*arr = (int*) realloc(*arr, *size * 2 * sizeof(int));
memset(*arr+*size, 0, *size * sizeof(int));
*size = *size * 2;
}

Re allocating C array for more space

Im writing a program with a function add(a , i, n) which will add 'i' as an element to 'a', but if the array 'a' runs out of space, then I need to realloc more memory to the array. Im stuck here:
#include <stdlib.h>
#include <stdio.h>
int add(int* a, int i, int n);
int main(){
int n = 20;
int *a = (int*) malloc(n*sizeof(int));
int i;
for (i = 0; i < 100000; i++){
n = add(a, i, n);
printf("a[%d]=%d\n",i,(int)a[i]);
}
return 0;
}
int add(int *a, int i, int n){
if (i >= n){
n++;
int* b = (int*) realloc(a, n*sizeof(int));
a[i]=i;
return n;
}else{
}
}
Im not very experienced so please be gentle...
realloc tries to reallocate the given memory, but sometimes, it can't and gives you a new memory pointer.
It must be used like:
int *b;
b = realloc(a, <newsize>);
if (b) {
/* realloc succeded, `a` must no longer be used */
a = b;
/* now a can be used */
printf("ok\n");
} else {
/* realloc failed, `a` is still available, but it's size did not changed */
perror("realloc");
}
Now, you still have some trouble in your code:
The idea of function add() is to reallocate a when needed, but a is given by copy, so its value won't be changed in main.
#include <stdlib.h>
#include <stdio.h>
int add(int** a, int i, int n);
int main(){
int n = 20;
int *a = malloc(n*sizeof(int));
int i;
for (i = 0; i < 100000; i++) {
/* note how `a` is passed to `add` */
n = add(&a, i, n);
printf("a[%d]=%d\n",i,a[i]);
}
/* and finally free `a`*/
free(a);
return 0;
}
/* changed `a` type to make its new value visible in `main` */
int add(int **a, int i, int n){
if (i >= n){
/* want to write a[i], so size must be at least i+1*/
n = i+1;
/* realloc memory */
int *b = realloc(*a, n*sizeof(int));
/* check that `realloc` succeded */
if (!b) {
/* it failed!*/
perror("realloc");
exit(1);
}
/* store new memory address */
*a = b;
}
/* update memory */
(*a)[i]=i;
/* return new size */
return n;
}
Note: I removed malloc/realloc cast, see: Do I cast the result of malloc?
To have an automatically growing array in C you would normally need a helper function ensure_capacity to take care of the array reallocation.
The helper function would preferrably reallocate using 2x grow policy, so you have an amortized constant time of the append operation.
The code would look somewhatlike the below.
Note that the code is using the first 2 elements of the array to keep its capacity/size. You can use a struct of pointer + size instead, but you need to keep the two close two each other as otherwise the code won't be easy to read.
int* ensure_capacity(int* vec, int new_cap) {
if (vec == 0) {
vec = (int*) malloc(18 * sizeof(int));
vec [0] = 16;
vec [1] = 0;
} else {
int cap = vec[0];
if (cap < new_cap) {
do {
cap *= 2;
} while (cap < new_sz);
int* new_vec = (int*) realloc(vec, cap * sizeof(int));
if (new_vec != null) {
vec = new_vec;
vec[0] = cap;
} else {
// reallocation failed, handle the error
}
}
}
return vec;
}
And you would use it in your add() function like:
int* push_back(int* vec, int val) {
vec = ensure_capacity(vec, vec[1] + 1);
vec[vec[1]++] = val;
return vec;
}

Dynamic Array: error free(): invalid next size (fast), Segmentation fault (core dumped)

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.
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.
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.

Resources