Array of pointers not changing after getting modified inside another function [duplicate] - arrays

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 2 years ago.
An array of pointers of chars is not getting changed in main.
Here's the situation: Inside main, an array of pointers of chars is declared and memory is allocated for it. main calls another function called AddItems which adds items to the list and that function calls doubleSize to double the size of the list. Everything is working as expected in terms of adding new items inside AddItems and doubling the size of the array. However, the problem is that when AddItems returns, main still has an older copy of the list, even though we're passing a pointer to the list.
Here's a MWE:
#define INITIAL_SIZE (4)
int main(void)
{
char **list = (char **) malloc(INITIAL_SIZE * sizeof(char *));
int list_size = INITIAL_SIZE;
for (int i = 0; i < list_size; i++) {
list[i] = (char *) malloc(5 * sizeof(char));
strcpy(list[i], "jane");
}
printf("main--> address of list: %p\n", list);
/* output = 0x7fc15e402b90 */
addItems(list, &list_size);
/* After adding items: */
printf("main--> address of list: %p\n", list);
/* output = 0x7fc15e402b90 (no change) */
return 0;
}
Here are the other two example functions:
void doubleSize(char ***list, int *current_size)
{
char **newList = (char**) malloc(*current_size * 2 * sizeof(char*));
for (int i = 0; i < *current_size; i++)
newList[i] = (*list)[i];
free(*list);
*list = newList;
*current_size = (*current_size) * 2;
}
void addItems(char **list, int * size)
{
printf("Before doubling: %p\n", list);
/* Output: 0x7fc15e402b90 */
/* Double the size */
doubleSize(&list, size);
printf("After doubling: %p\n", list);
/* Output: 0x7fc15e402be0 */
}
The address of list is getting changed to the newly created array inside doubleSize and also inside addItems but not inside the main function, even though we're passing a pointer to the array. What am I missing here?

you could also try as below by modifying addItems
char** addItems(char **list, int * size)
{
printf("Before doubling: %p\n", list);
/* Output: 0x7fc15e402b90 */
/* Double the size */
doubleSize(&list, size);
printf("After doubling: %p\n", list);
/* Output: 0x7fc15e402be0 */
return list;
}
And the call from main should be:
list = addItems(list, &list_size);

If you want a function to change something, you need to pass its address (or use a global).
You didn't, so it couldn't. Simple as that.
At no point after the first line of main do you modify main's list. Remember that C only passes the value of variables to functions (pass by copy), and that the value of the variable is the address of the allocated block.
If you want addList to be able to change main's list, you will need to pass the address of the variable list itself (&list).
You're apparently aware of the concept since you did exactly that in addList. You wanted doubleSize to change addList's list, so you passed its address to doubleSize.
Tip: It would be best to use realloc in doubleSize.
void doubleSize(char ***list, size_t *size) {
size_t new_size = *size * 2;
char **new_list = realloc(*list, new_size);
if (!new_list) [
// Ignoring out-of-memory errors.
}
*list = new_list;
*size = new_size;
}
Since we're ignoring out-of-memory errors, the above simplifies to
void doubleSize(char ***list, size_t *size) {
*list = realloc(*list, ( *size *= 2 ));
}

Related

Creating Dynamic array as part of struct vs dynamic int array

I am working with dynamic arrays, consider two scenarios -
Scenario 1:
typedef struct
{
int *array;
int dataPtr;
} A;
static A dynaArray;
//Call the function as
dynaAdd(&dynaArray, <pointer to data block>, <length> );
static bool dynaAdd(A *data, int *dataCopy, int len)
{
int newlen = (data->dataPtr + len);
data->array = (int *) realloc(data->array, newlen * sizeof(int));
if (!data->array)
{
return FALSE;
}
memcpy(&data->array[data->dataPtr], dataCopy, len* sizeof(int));
data->dataPtr += len; // update data ptr
return TRUE;
}
I create a static struct A data (say) and pass to a function as pointer which reallocates length for A->array everytime and adds data to it, maintaining a dataPtr for index. This works perfectly fine where I can create an A->array of say length 100, use the data and free the pointer and null.
On the other scenario 2 -
static int *dynArray;
//Call the function as
dynaAdd(dynaArray, <pointer to data block>, <len>, <dataIdx> );
static bool dynaAdd(int *data, int *dataCopy, int len, int dataIdx)
{
int newlen = (dataIdx + len);
data = (int *) realloc(data, newlen * sizeof(int));
if (!data)
{
return FALSE;
}
memcpy(&data[dataIdx], dataCopy, len* sizeof(int));
dataIdx += len ;
return TRUE;
}
I just use int *array instead of struct, maintaining a static int dataPtr(say) to keep track of the next index, pass the array pointer to the function and dynamically grow the array and add contents to it. However, the program crashes after creating some x length array (which keeps varying).
Can someone help understand the difference between the two approaches ? In both scenarios, the goal is to create a dynamic array and keep adding contents to it until the certain data index and then free the array.
Thank you.
In the second example, you're modifying data which is local to the function. Such a change is not reflected in the calling function, so dynArray doesn't change. And since you reallocated memory, if the memory moved then this pointer is now invalid and attempting to dereference it triggers undefined behavior.
You need to change the function to accept the address of a int *, i.e. an int **, for the first argument and make the corresponding changes. You'll also want to make dataIdx a int * so changes to that are also propagated back
So your function would now look like this:
static bool dynaAdd(int **data, int *dataCopy, int len, int *dataIdx)
{
int newlen = (*dataIdx + len);
*data = realloc(*data, newlen * sizeof(int));
if (!*data)
{
return FALSE;
}
memcpy(&(*data)[*dataIdx], dataCopy, len* sizeof(int));
*dataIdx += len ;
return TRUE;
}

wrong output when assigning a number to a struct pointer [duplicate]

This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 2 years ago.
My struct is
typedef struct {
unsigned int size ;
int * arr ;
} array_t ;
The function should initialize a struct with the length of a given number.
void init ( array_t * A, unsigned int size){
A = malloc(sizeof(array_t));
A->arr = calloc(size+1,sizeof(int));
A->size = size;
return;
}
But when I print the size of the struct in my main function I always get the wrong number.
How do I assign the right value to size or what did I do wrong?
As #Robert mentioned, once you
...
A = malloc(sizeof(array_t));
...
You assign a new address to A, so all the initialization done afterwards is done on a memory address that you don't have any access to in your main function.
You actually don't need this line, you pass a pointer to an already allocated memory to the init functio.
Just drop this line and it'll be fine.
Your code is incorrect because it does not return the reference to the newly allocated memory:
void init ( array_t * A, unsigned int size){
A = malloc(sizeof(array_t)); // <===== the allocated memory reference is lost
A->arr = calloc(size+1,sizeof(int));
A->size = size;
return;
}
One way to fix it is to return the new array to the caller:
array_t * CreateArray (unsigned int size){
array_t * A = malloc(sizeof(array_t));
A->arr = calloc(size+1,sizeof(int));
A->size = size;
return A; /* return the new array */
}
Another way is to use a pointer but the caller need to do the malloc:
void init ( array_t * A, unsigned int size){
A->arr = calloc(size+1,sizeof(int));
A->size = size;
}
void main ()
{
array_t Array;
init(&Array);
}

Why doesn't my function work to adjust my pointer's content, unless i return one to assign it

My question is what is the difference between these two? one is a void, and another one returns a 2d array, they however do the same but the functionality doesn't seem to do the same? i must be misunderstanding pointers here.
I thought pointers stored nothing but an adress to point to, so if i pass one as a parameter, and change the contents and to where it points, don't i do the same as re-assigning it to the functions return value.
on the end of both functions we print the first line, they did so on both. but whilst printing the adjusted grid by the void function in my Main i get a segfault.
char **ft_grid_gen(int size)
{
char **map;
int index;
int elem_index;
int sq_root;
index = 0;
elem_index = 0;
sq_root = ft_sqrt(size * 4);
map = (char**)malloc(sq_root * sizeof(char *));
while (index < sq_root)
{
map[index] = (char*)malloc(sq_root * sizeof(char));
while (elem_index < sq_root)
{
map[index][elem_index] = '.';
elem_index++;
}
index++;
elem_index = 0;
}
printf("GENERATED NEW GRID of size %s!\n", map[0]);
return (map);
}
void ft_grid_gen(char **map, int size)
{
int index;
int elem_index;
int sq_root;
index = 0;
elem_index = 0;
sq_root = ft_sqrt(size * 4);
map = (char**)malloc(sq_root * sizeof(char *));
while (index < sq_root)
{
map[index] = (char*)malloc(sq_root * sizeof(char));
while (elem_index < sq_root)
{
map[index][elem_index] = '.';
elem_index++;
}
index++;
elem_index = 0;
}
printf("GENERATED NEW GRID of size %s!\n", map[0]);
}
The difference is that the first function returns something you can use later on. In the second function, you pass in a char** by value, and then with:
map = (char**)malloc(sq_root * sizeof(char *));
You assign a new value to the local variable map, which was assigned its first value through the function parameter. However this does not affect the original char** variable in main() -- because it was passed in by value like everything else in C. If you wanted to change the main() variable, you would have passed a pointer to it (i.e. char***) and de-referenced it in this function, like:
*map = (char**)malloc(sq_root * sizeof(char *));
Note that ft_grid_gen don't just change that to which map points; it also change map itself.
Changing map has no more effect on the caller than changing size. Whatever variable you used as a parameter in the caller still point to "nowhere useful" after ft_grid_gen.
If you want to return a value via a parameter, you need to pass a pointer to the variable that will receive the value.
void f(int *i_ptr) {
*i_ptr = 123;
}
int i;
f(&i);
In your case, this would be
void ft_grid_gen(char ***map_ptr, int size) {
...
*map_ptr = map;
}
char **map;
f(&map);
Alternatively, you could allocate the memory on the outside. Since the function no longer has a need to change map, the value of map can be passed directly.
void ft_grid_gen(char **map, int size) {
...
}
char **map = malloc(ft_sqrt(size * 4) * sizeof(char*));
ft_grid_gen(map, size);
(Obviously, this approach is far from ideal in this specific situation.)

Malloc returns the same pointer twice [duplicate]

This question already has answers here:
How to change value of variable passed as argument?
(4 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 5 months ago and left it closed:
Original close reason(s) were not resolved
I allocate dynamic array in main like this:
char *arr = malloc(sizeof(char));
then in a random function I reallocate that array to n elements like:
arr = realloc(arr, n * sizeof(char));
then I do a random stuff with the array, and in another function I want to allocate one more array with n elements like this:
char *arr2 = malloc(n * sizeof(char));
but this malloc returns the same adress as arr. I tried everything, but still returns the same adress, so arr2 is pointing to arr. What am I doing wrong?
If i allocate new array again lets say arr3 with the same method, now it works and it gives me new adress.
Edit:
void reallocate(char *arr, int newLength) {
arr = realloc(arr, newLength * sizeof(char));
}
void fc1 (char *arr, int *length) {
char *temp = malloc(*length * sizeof(char));
strcpy(temp, arr);
int d;
scanf("%d", &d);
char *arr2 = malloc(d * sizeof(char)); //there it gives me the same adress
scanf("%s", arr2);
}
int main(void) {
char arr = malloc(sizeof(char));
int *length = malloc(sizeof(int));
*length = 10;
reallocate(arr, 10);
fc1(arr, length);
return 0;
}
We'd need to see the code to be sure, but here's two ways it can happen:
void func2(char *s)
{
do_something(s);
free(s); // we are done with it
}
void func1(void)
{
char * array = some_func();
func2(array); // Oops, func2 frees it
char * array2= malloc (...); // could get the same pointer
}
Here, func1 passes the pointer to func2 which frees it. It is an error for func1 to do anything with array after that point as it can be re-assigned.
And the second way:
void get_data(char *s)
{
char *data = // code to get some data from somewhere
s = realloc (s, strlen(data) + 1);
strcpy(s, data);
}
void func1(void)
{
char *ptr = malloc(12);
get_data(ptr);
// oops, ptr has the old value
char *ptr2 = malloc(12); // could get the same pointer
}
Here, get_data calls realloc but the caller still has the old pointer which realloc might free.
But we'd need to see the code to be sure.
Update:
I guessed right. This is the second way in my example above:
void reallocate(char *arr, int newLength) {
arr = realloc(arr, newLength * sizeof(char));
}
This looks exactly like my get_data function above. This function does not pass the new value of arr back to the caller, so the caller still has the old value which may be freed.
reallocate(arr, 10);
fc1(arr, length);
This looks exactly like my second func1 above. You pass arr to reallocate which may invalidate it, but then you pass the old value of arr to fc1. But reallocate may have freed it. There's a reason realloc returns the new value, but your reallocate function doesn't.

dynamic array and pointer in C

I'm a beginner in C and programming. I would like to ask some questions on dynamic array and pointer in C.
I am trying to create a dynamic array and increase its capacity, but I can't get my code working. I believe something is wrong in my setCapacityDynArr function.
Can someone give me some help?
Thanks!
struct DynArr {
TYPE *data; /* pointer to the data array */
int size; /* Number of elements in the array */
int capacity; /* capacity ofthe array */
};
void initDynArr(struct DynArr *v, int capacity) {
v->data = malloc(sizeof(TYPE) * capacity);
assert(v->data != 0);
v->size = 0;
v->capacity = capacity;
}
void freeDynArr(struct DynArr *v) {
if (v->data != 0) {
free(v->data); /* free the space on the heap */
v->data = 0; /* make it point to null */
}
v->size = 0;
v->capacity = 0;
}
int sizeDynArr(struct DynArr *v) {
return v->size;
}
void addDynArr(struct DynArr *v, TYPE val) {
/* Check to see if a resize is necessary */
if (v->size >= v->capacity) {
_setCapacityDynArr(v, 2 * v->capacity);
}
v->data[v->size] = val;
v->size++;
}
void _setCapacityDynArr(struct DynArr *v, int newCap) {
//create a new array
struct DynArr *new_v;
assert(newCap > 0);
new_v = malloc(newCap * sizeof(struct DynArr));
assert(new_v != 0);
initDynArr(new_v, newCap);
//copy old values into the new array
for (int i = 0; i < new_v->capacity; i++) {
new_v->data[i] = v->data[i];
}
//free the old memory
freeDynArr(v);
//pointer is changed to reference the new array
v = new_v;
}
int main(int argc, const char * argv[]) {
//Initialize an array
struct DynArr myArray;
initDynArr(&myArray, 5);
printf("size = 0, return: %d\n", myArray.size);
printf("capacity = 5, return: %d\n", myArray.capacity);
//Add value to the array
addDynArr(&myArray, 10);
addDynArr(&myArray, 11);
addDynArr(&myArray, 12);
addDynArr(&myArray, 13);
addDynArr(&myArray, 14);
addDynArr(&myArray, 15);
for (int i = 0; i < myArray.size; i++) {
printf("myArray value - return: %d\n", myArray.data[i]);
}
return 0;
}
//pointer is changed to reference the new array
v = new_v;
This is your problem, a classic mistake in C. In fact the function changes its own copy of the pointer, the caller never sees the change. The problem is amply described by this C FAQ.
I suggest a different approach. There's no reason to make a new v: you simply want more storage associated with it. So instead of actually changing v, you'll probably want to just call realloc on the storage: v->DATA.
You might get away with something like:
tmp = realloc(v->data, newCap * sizeof *v->data);
if (!tmp)
error;
v->data = tmp;
And this way you don't need to copy the elements either: realloc takes care of that.
//pointer is changed to reference the new array
v = new_v;
Your original pointer outside the function is not changed, since you passed the value of the pointer not the address of it here:
void _setCapacityDynArr(struct DynArr *v, int newCap)
{
Yes it's an error in _setCapacityDynArr. It's an error because you declare an DynArr structure on the stack, then you try to free it and assign a new pointer to it. That will not work, as items allocated on the stack can't be freed.
What you want to do is to reallocate only the actual data, not the whole structure. For this you should use the realloc function.
There are other problems with the function as well, like you assigning to the pointer. This pointer is a local variable so when the function returns all changes to it will be lost.

Resources