Passing arrays in c - c

I have a question regarding passing arrays in c to a function.
When I run this program it gives me a segmentation fault
int main()
{
char **ptr= NULL;
test(ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char **ptr)
{
ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(ptr[0], "abc");
return;
}
but this worked just fine
int main()
{
char **ptr= NULL;
test(&ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char ***ptr)
{
*ptr = (char **) malloc(sizeof(char *));
*ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(*ptr[0], "abc");
return;
}
Could someone explain why?

You're passing the parameter ptr by value; the formal parameter ptr in test is a different object from the actual parameter ptr in main, so changing the value of test::ptr is not reflected in main::ptr.
Thus, you need to pass a pointer to ptr into test, and test needs to dereference that pointer to write to the correct object.
For any type T, if you want to modify the value of the function argument, you need to do the following:
void foo( T *param )
{
*param = ...;
}
void bar( )
{
T obj;
foo( &obj );
}
In this particular instance, T is char **.

In C, when you pass an array to a function, the array "decays" to a pointer. The function receives a pointer to the first element of the array. It does not receive the array itself. Any changes made to the pointer assignment in the called function are not reflected in the calling function.
In your first example, test() receives the array of strings, and inside the function, it changes what that pointer points to. So the local copy of ptr, which was NULL, gets allocated memory inside the function, as does ptr[0]. However, those changes are local to test(). They are not reflected in the calling function. When test() finishes executing and returns, the value of ptr in the calling function is still NULL. And you have a memory leak because there is no way to access the memory that was allocated in test().
In order for the changes to be reflected in the calling function, you have to pass a pointer to the array of strings: hence the &ptr in the call and the three-level pointer in the definition of test(). Another, simpler approach would be:
int main()
{
char **ptr= NULL;
ptr = test();
printf("%s", ptr[0]);
return 0;
}
char** test(void)
{
char **ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char) * 5);
strcpy(ptr[0], "abc");
return ptr;
}
One clarification: I said "Any changes made to the pointer assignment in the called function are not reflected in the calling function." This is not the same as saying "Any changes to array elements are not reflected in the calling function." Consider this:
int main (void) {
int array [] = { 0, 1, 2, 3, 4 };
test1 (array);
printf ("%d\n", *array);
test2 (array);
printf ("%d\n", *array);
return 0;
}
void test1 (int* array) {
int new_array[] = { 3, 4, 5, 6, 7 };
array = new_array;
return;
}
void test2 (int* array) {
array [0] = 5; // or *array = 5
array [1] = 6;
array [2] = 7;
array [3] = 8;
array [4] = 9;
return;
}
Output:
0
5
Here in test1() the change is to where the array pointer itself is pointing, which won't be reflected in the caller. So in the calling function, *test is still 0. In test2(), the changes are to the array elements, which are reflected in the caller. Hence the difference in output: *test is now 5. All this uses static rather than dynamic memory allocation, but the principle is the same.

It's because you expect your function not to return a value, but to modify a variable you have already created in another scope.
You expect, from your function, to pass ptr and end up with the following structure:
ptr -> b -> []
where b is a pointer to the array [].
In the first example you are not modifying the outer ptr inside the function, but a copy of it. In that case, to get the desired structure you'd need your function to return a char** so that you could return the allocated pointer. And you wouldn't need to pass the original ptr.
In the second example, on the other hand, you are passing a pointer to the outer ptr, so the function will be modifying the same memory space that the outer ptr uses.
I hope this can help a little.

Consider below code for understandling
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test(char **ptr);
int main()
{
char *ptr= NULL;
test(&ptr);
printf("%s\n", ptr);
return 0;
}
void test(char **ptr)
{
*ptr = malloc(sizeof(char *));
strcpy(*ptr, "abc");
return;
}
Whatever doing in function definition has to be reflect in main function. So if you want to make changes in ptr variable you have to pass the address of the ptr variable.
ptr is single pointer(char ptr) variable, we need to pass address of the pointer(&ptr) variable.
In function definition we are receiving address of pointer variable, so argument has to be the type of double pointer.
This concept is similar to call by reference.
Similar things happening in your code also.
You need to pass address of double pointer to make changes in pointer variable.
Address of double pointer has to taken by triple pointer in function definition.

To expand on the answer from #rcrmn.
It is a good program design to have data get passed "up" the calling structure. In this case main() needs to free the storage it received from test.
Notice that this code avoids all of the double pointers in the original question and still meets the requirements. This is the essence of good programming, write clear, simple, code that gets the job done.
#include <stdio.h>
char *test();
int main()
{
char *ptr = test();
printf("%s", ptr);
free(ptr);
return 0;
}
char *test()
{
char *ptr = (char *) malloc(sizeof(char) * 5);
strncpy(ptr, "abc", 3);
return ptr;
}

Related

Passing double pointer as function argument

I simply want to assign a pointer to another pointer via the function (same memory address). My code is below:
#include <stdio.h>
void d(int** a)
{
int* val_ptr = malloc(1);
*val_ptr = 5;
printf("%d\n", *val_ptr);
a = &val_ptr;
}
int main()
{
int* a = NULL;
d(&a);
printf("%d\n", *a);
return 0;
}
Output from Link
5
Segmentation fault
Your code has three problems:
Here int* val_ptr = malloc(1);, you allocate 1 byte rather than allocating space for an int. Use the following to fix it:
int* val_ptr = malloc(1 * sizeof(int));
This a = &val_ptr; is not what you want. It changes the local pointer and makes it point to the address of val_ptr. This will not affect the pointer that you've defined in main.
Fix it using
*a = val_ptr;
This way, the pointer in main will also reflect the change and will point to the malloced memory
You should free the allocated memory after its use. Add
free(a);
after the printf in main to free it.

Passing structs into function by address vs a pointer in C

I was hoping someone could help me figure out why one version of the below code works, while the other doesn't. Below I've included the initArray method, stored in "worksheet.c". The function is accessed in main, both versions are given below.
void initArray(struct dynArray *a) {
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
}
This works. I create a dynArray struct and pass it to initArray by reference.
#include "worksheet0.h"
#include <stdio.h>
int main(void)
{
struct dynArray b;
initArray(&b);
return 0;
}
This fails with a seg fault. I thought that passing b here would be the same as passing the struct by reference.
int main(void)
{
struct dynArray *b = NULL;
initArray(b);
return 0;
}
Because in the second case there is no memory allocated to which the struct pointer points to. It is simply a pointer having the value NULL. On your case by dereferencing the value NULL you have invoked undefined behavior.
It would work if you allocate memory, make changes to it and then return it's value. [But then you have to return the address of the allocated memory.] OR you can pass the address of the pointer variable and allocate memory to which dereferenced pointer (here the pointer has type struct dynAray**) would point to and make changes to it.
Let's be more clear now slowly:
Why the first case works? You have a struct dynArray variable whose address you have passed into the function and then you have accessed the content of that address - wait! that means you have accessed the struct dynArray variable itself and made changes to its member variables. Yes that is what exactly happened in the first case.
In the second case, you have a pointer to struct dynArray. And then you passed it - de-referenced it. Where was it pointing to? Is it some struct dynArray variable's address that it contained? No. It was NULL. So it is wrong if you expect it to work.
The second would work - but you have to change things a bit! Let's see how:
struct dynArray* initArray() {
struct dynArray* a = malloc(sizeof *a);
assert(a != NULL);
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
return a;
}
And in main()
struct dynArray* b;
b = initArray();
You don't even need to pass the pointer variable. That would be meaningless if you want to do it like this.
And you know you can also pass the address of the pointer variable so that you can make changes to it -
void initArray(struct dynArray** a) {
*a = malloc(sizeof **a);
assert((*a) != NULL);
(*a)->data = malloc(10 * TYPE_SIZE);
assert((*a)->data != 0);
(*a)->size = 0;
(*a)->capacity = 10;
}
For this in main() you would call it like this
struct dynArray* b;
initArray(&b);
In the first example a pointer holding the address of an actual struct is passed to the function. But, in the second example the pointer b does not point to a struct. Instead, this pointer is initialized to NULL, and when this null pointer is dereferenced in the initArray() function, undefined behavior ensues.

C language Array modification with Malloc

void helperWithoutMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperWithoutMalloc(data);
printf("%d\n", data[0]);
return 0;
}
The above method successfully modify the value of data through the method helperWithoutMalloc(); however, when malloc method is applied; similar way doesn't work. Three value in the data array still zero
void helperNotWorking(int *arr) {
arr = malloc(sizeof(int)*3);
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperNotWorking(data);
printf("%d\n", data[0]);
return 0;
}
I'm just wondering what happen when the line arr = malloc(sizeof(int)*3) is implemented; and makes two code so different?
The main confusion is that : first code regardless of its incorrectness, can still modify the array element while second code, can't modify the array elements; since both functions pass the address of array; and we manipulate the array element through address
Any data structure in C as in any other language must be provided with a memory region where it data could be kept. In your first example you failed to do so. The 'data' pointer does not point to any memory and is initialized. It worked by a chance and you just caused your program to write data somewhere, which happened to be writable. you needed something like the following:
int main() {
int data[3]; // allocate an array for data
helperWithoutMalloc(data);
In the above example the memory was provided by the C array of 3 elements.
In a similar fashion you can use malloc:
int main() {
int *data = malloc(sizeof(int) * 3);
helperWithoutMalloc(data);
Note that the space for data was allocated before calling to the function and passed to it. The function can use pointer (memory address) to access the array elements.
In your second example you did a different mistake. You allocated the space, but you assigned the pointer to the parameter of the function. The pointer in your case was passed to your function by value, therefore it is uni-directional. you can pass it to the function but not backwards. It worked perfectly well inside the function but it did not update 'data', so you cannot access the values after returning from the function. There are few ways to work around it. I.e. you can return your pointer from the function:
int *helper() {
int *arr = malloc(sizeof(int)*3);
...
return arr;
}
int main() {
int *data = helper();
...
or you can use a pointer to pointer to pass to the function:
void helper(int **arr) {
*arr = malloc(...)
(*arr)[0] = 0;
...
}
int main () {
int *data;
helper(&data);
In my opinion, the correct way should be
void NoMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data = (int *)malloc(sizeof(int) * 3);;
NoMalloc(data);
printf("%d\n", data[0]);
free(data);
return 0;
}
The malloc function allocates some memory and returns a pointer to that allocated memory.
Pointer stores addresses in the memory, and when you define a uninitialized pointer (such as the your first piece of code, int * data;) you don't know where the pointer (data) is pointing and therefore accessing the values stored at the location would often cause Access Violations and should never be used.
As with any other type of C variables, pointers are passed by values when serving as an argument of a function. So data itself would not be modified after calling helperWithoutMalloc or helperNotWorking. The second piece of code does not work because after calling helperNotWorking, the data pointer is still an uninitialized pointer. The numbers you though you have stored in data is actually stored in the modified value of arr in the helperNotWorking function, which does not affect does not point to the same address as data anymore.

modify array element through pointer to a pointer

I'm trying to build a program that modifies the element of an array through a pointer to a pointer. I loaded it into the debugger and I see that the value of my pointer changes, but for some reason that doesn't affect the element in the array. Is my pointer syntax wrong? Am I reassigning my pointer somewhere else?
#include <stdio.h>
#include <stdlib.h>
#define SIZE 6
/*
*
*/
void change (char **x);
int main() {
char arra[] = "Back";
char *c = arra;
change(&c);
int i;
printf("%c", arra[0]);
}
void change (char **x) {
*x = "H";
}
*x = "H";
should be
**x = 'H';
You are trying to modify the first character and character has to be within single quotes.
There is no need of pointer to pointer here. You can just pass the array which decays to a pointer when passed in the function parameterks as shown by #haccks
No need to use pointer to pointer in this case. Just use pointer to char.
void change (char *x);
and call it as
change(c);
with the function body
void change (char *x) {
*x = 'H';
}

How to set pointers throught functions?

I have a question about C pointers. Because I was wondering if I could set pointers through functions.
I mean like this:
void initptr(int **ptr)
{
ptr = (int *) malloc(sizeof(ptr));
}
int main()
{
int *ptr;
initptr(ptr);
}
Let me know.
Yes this is possible in C, you're just missing a dereference and address of operator in your sample
void initptr(int **ptr)
{
*ptr = (int *) malloc(sizeof(int*));
}
int main()
{
int *ptr;
initptr(&ptr);
}
The deference operator in *ptr = ... converts the type of ptr from int** to int* thus making it compatible with the assignment. Note: the casting of malloc is uneedded here.
The address of operator in initptr(&ptr) reversely converts the type of ptr from int* to int** thus making it compatible with the argument slot.
EDIT
As B Mitch pointed out the malloc size needs updating as well. You appear to be allocating an int* value and hence want the size to be that of an int*.
I believe you want this:
*ptr = (int *) malloc(sizeof(**ptr));
yes, but you need dereference ptr in your function in order to change what it points to
e.g.
void initptr(int **ptr)
{
*ptr = ...
}
when you call the method write
initptr( &ptr );
ptr = (int *) malloc(sizeof(ptr));
You missed to dereference the pointer to pointer so that it can actually take a pointer.
*ptr = (int *) malloc(sizeof(ptr));
// * newly added.
And also call to initptr(ptr); is wrong.
void initptr(int **ptr) ;
The function has an pointer to pointer as an argument. So, the argument ptr needs to hold the address of a pointer. So, change it to -
int *ptr = NULL ; // Initialize pointers to NULL
initptr(&ptr); // Passing the pointers address

Resources