Passing structs into function by address vs a pointer in C - 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.

Related

How does malloc work within wrapper function? [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.
I have a question dedicated to:
void* malloc (size_t size);
In the regular example that can be found on millions of sites over the internet it's shown that the right way to use malloc is the following:
int main()
{
int* num;
num = malloc(sizeof(int));
*num = 10;
printf("Value = %d\n", *num);
free(num);
return 0;
}
But If I want to allocate memory within a function and use it in main like below, then the only option is to implement the function the following way:
void func_alloc(int** elem, int num_value)
{
*elem = malloc(sizeof(int));
**elem = num_value;
}
int main()
{
int* num;
func_alloc(&num, 10);
free(num);
return 0;
}
I assumed by mistake, that such code as below would work:
void func_alloc(int* elem, int num_value)
{
elem = malloc(sizeof(int));
*elem = num_value;
}
int main()
{
int* num;
func_alloc(num, 10);
free(num);
return 0;
}
Could you please explain or maybe give a link to resource with explanation why does it work only this way?
I really cannot understand why do I need double pointer as an input parameter and why in the other case it comes to "segmentation fault"...
Thank in advance ;)
I assumed by mistake, that such code as below will work.
In C, the arguments are passed by value, when you pass a pointer as an argument of a function, you are passing the value of the pointer, basically a copy of it, not the pointer itself, malloc will change the value of that pointer, but since what you passed was a copy, that is what's changed, not the original pointer, that one remains unchanged.
In the second code snippet, the working code, *elem = malloc(sizeof(int)); broadly means make this pointer elem point to this valid memory address given to me by malloc(assuming it succeeds), the value of the pointer to the pointer elem which you passed as an argument remains unchanged, it being a copy doesn't matter because it's not changed, it's still the same address that was passed as argument, the address of the pointer num which is now pointing to the memory location given by malloc.
**elem = num_value means store num_value in the address stored in the pointer where elem is pointing to, which is where num is pointing to, which is the new memory block previously given by malloc.
That being said, it's not the only option, you can use a local pointer, return it and assign it to another local pointer in the caller side, this is still a copy, but it's a copy of the changed pointer:
int *func_alloc(int num_value)
{
int *elem = malloc(sizeof *elem); //more idiomatic
if(elem == NULL){ // check for allocation errors
perror("malloc" );
exit(EXIT_FAILURE);
}
*elem = num_value;
return elem;
}
int main()
{
int* num = func_alloc(10);
free(num);
return EXIT_SUCCESS;
}
Footnote:
In the third code snippet, freeing num, given that it is uninitialized is a bad idea, I assume you know as much, nonetheless I thought I'd mention it. This may be the reason for the segfault you experienced, whatever garbage value num has will be assumed to be valid memory address, and free will try to deallocate it, doing this will invoke undefined behavior. If it was NULL, it's a different story, it's well defined behavior (execept in some very old standars). Initializing variables when they are declared is, in most cases, a good idea.
A commented explanation :
void func_alloc(int* elem, int num_value)
{
/* elem points to address gave by malloc, let's say 0x12345678 */
elem = malloc(sizeof(int));
/* at address 0x12345678 you have now your num_value */
*elem = num_value;
/* end of the function. Changes made to parameters passed by value are lost */
}
int main()
{
int* num;
/* num is a pointer to an address you could not have write access to, you actually don't know */
func_alloc(num, 10);
/* As C arguments are passed by value, changes made into the function are lost */
/* You try to free num which is still a pointer to an address you potentially have no access to => SEGFAULT */
free(num);
return 0;
}
EDIT:
Not shown in this example, but it is good practice to always check that pointer returned by malloc is not NULL, otherwise you should exit without trying to assign a value to the pointer.
If you have:
#include <stdio.h>
void foo(int x)
{
x = 9;
}
int main(void)
{
int a = 1;
foo(a);
printf("%d\n", a);
}
you probably don't expect the value of a in main() to change just because foo() assigned to x, right? It doesn't change, because parameters are assigned by value. The variables x in foo(), and a in main() are two different variables.
The same applies in your code. elem in func_alloc() is a different variable from num in main(), and assigning to the former doesn't change the value of the latter. The fact that these two are of type int *, and not e.g. just int, makes no difference in this.
That said, you can also return the pointer you got from malloc(), e.g.
int *alloc_int(int value)
{
int *p = malloc(sizeof(int));
*p = value;
return p;
}
(not that it seems to make much sense for a mere int.)

How to access and modify pointer type variable declared inside a structure through a element of array containing pointers to the structure?

I declared a double pointer of the structure type and allocated it the required memory using calloc. Then I allocated data member (pointer) required space but it gave segmentation fault error. So only done1 gets printed. Can't we access data member pointers in structure like this?
I even replaced q[0] with *q but it didn't work.
#include<stdio.h>
#include<stdlib.h>
struct one
{
int *a;
};
int main()
{
struct one **q;
q = (struct one**) calloc(sizeof(struct one*),10);
printf("done1\n");
q[0]->a = (int*) malloc(sizeof(int));
printf("done2\n");
*(q[0]->a) = 10;
printf("done3 , q[0]->a stores %d value\n",*(q[0]->a));
return 0;
}
Expected result would be printing of all the "done"'s but only first done is being printed.
You did a calloc so that you can create an array of pointers, i.e. {q[0], q[1], .., q[9]}. But, each individual element itself is a pointer and since you are doing calloc, they are probably initialized to NULL. But, then you are directly trying to access q[0]->a when q[0] is still pointer to NULL.
If you attach a debugger and see where it crashes, it will probably be the line q[0]->a = ...
First, you have to allocate memory to q[0] and then access q[0]->a.
#include <stdio.h>
#include <stdlib.h>
struct one
{
int *a;
};
int main()
{
struct one **q;
q = (struct one**) calloc(sizeof(struct one*), 10);
printf("done1\n");
q[0] = (struct one*) calloc(sizeof(struct one), 1);
q[0]->a = (int*) malloc(sizeof(int));
printf("done2\n");
*(q[0]->a) = 10;
printf("done3 , q[0]->a stores %d value\n", *(q[0]->a));
return 0;
}
BTW, your code wasn't compiling on my compiler saying unknown type one**. So I changed it with struct one everywhere.

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.

Need of Pointer to pointer

What is necessary for storing the address of a pointer?
int a = 2;
int *p = &a;
int **q = &p;
Any practical use? Real time applications.
In C you can either pass "value" or "address" of an object. If you pass value in function call, then changes made in the function don't reflect at calling place. And to reflect changes, you need to pass address of the object, for example:
void insert(node* head){
head->data = 10; // address(or head) is still same
}
By object I means any type int, char or struct e.g. node
In the above example you change value at addressed by head pointer and change in data will be reflected.
But suppose if you want to change head itself in your list (e.g. insert new node as first node).
void insert(node* head){
head = malloc(sizeof(head)); // head changed
head->data = 10;
}
Then value doesn't reflect at calling place because this head in function is not the same as head at calling place.
You have two choice, either return head or use pointer to pointer (but remember only one value can be return).
Use pointer to pointer:
void insert(node** head){
(*head) = malloc(sizeof **head);
(*head)->data = 10;
}
Now changes will reflect!
The point is, if address is your value (need to updated address), then you need to use pointer of address or I should say pointer to pointer to reflect changes at the calling place.
As your question is what is need of pointer to pointers, one more place where pointer to pointer used in array of string, and dynamic 2-D arrays, and for same use you may need pointer to pointer to pointer for example dynamic matrix of String or/ 3D char array.
Read also this:Pointers to Pointers I just found, to tell you for an example.
A ** is just a pointer to a pointer. So where an *p contains the address of an p, p** contains the address of an p* that contains the address of an p object.
** is used when you want to preserve the Memory-Allocation or Assignment even outside of a function call.
Also check this article.
EXAMPLE:-
void allocate(int** p)
{
*p = (int*)malloc(sizeof(int));
}
int main()
{
int* p = NULL;
allocate(&p);
*p = 1;
free(p);
}
Does
int main (int argc, char** argv) { ... }
Look familiar?
If you want to allocate Nth order pointer in other function, you should use (N+1)th order pointer. For example:
void allocate_matrix(int ***ptr, int x, int y);
Lets us allocate a matrix:
int **matrix:
allocate_matrix(&matrix, 5, 5);
One use for this is to change the value of a pointer from within a function. For example:
#include <stdio.h>
void swapStrings(const char **strA, const char **strB)
{
const char *tmp = *strB;
*strB = *strA;
*strA = tmp;
}
int main()
{
const char *a;
const char *b;
a = "hello";
b = "world";
swapStrings(&a,&b);
// now b points to "hello" and a points to "world"
printf("%s\n", a);
printf("%s\n", b);
}
Outputs:
world
hello

Malloc inside another function

I have to allocate a struct from within another function, obviously using pointers.
I've been staring at this problem for hours and tried in a million different ways to solve it.
This is some sample code (very simplified):
...
some_struct s;
printf("Before: %d\n", &s);
allocate(&s);
printf("After: %d\n", &s);
...
/* The allocation function */
int allocate(some_struct *arg) {
arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg);
return 0;
}
This does give me the same address before and after the allocate-call:
Before: -1079752900
In function: -1079752928
After: -1079752900
I know it's probably because it makes a copy in the function, but I don't know how to actually work on the pointer I gave as argument. I tried defining some_struct *s instead of some_struct s, but no luck. I tried with:
int allocate(some_struct **arg)
which works just fine (the allocate-function needs to be changed as well), BUT according to the assignment I may NOT change the declaration, and it HAS to be *arg.. And it would be most correct if I just have to declare some_struct s.. Not some_struct *s.
The purpose of the allocation function is to initialize a struct (a some_struct), which also includes allocating it.
One more thing I forgot to mention. The return 0 in the allocate function is reserved for some status messages and therefore I can't return the address using this.
Typically, I'd return the pointer from allocate:
void * allocate()
{
void * retval = malloc(sizeof(some_struct));
/* initialize *retval */
return retval;
}
If you want to return it in a parameter, you have to pass a pointer to the parameter. Since this is a pointer to a some_struct, you have to pass a pointer to a pointer:
void allocate (some_struct ** ret)
{
*ret = malloc(sizeof(some_struct));
/* initialization of **ret */
return;
}
to be called as
some_struct *s;
allocate(&s);
I highly doubt this is what your teacher had in mind, but you can cheat using a series of legal type conversions.
int allocate(some_struct *arg)
/* we're actually going to pass in a some_struct ** instead.
Our caller knows this, and allocate knows this. */
{
void *intermediate = arg; /* strip away type information */
some_struct **real_deal = intermediate; /* the real type */
*real_deal = malloc(sizeof *real_deal); /* store malloc's return in the
object pointed to by real_deal */
return *real_deal != 0; /* return something more useful than always 0 */
}
Then your caller does the same:
{
some_struct *s;
void *address_of_s = &s;
int success = allocate(address_of_s);
/* what malloc returned should now be what s points to */
/* check whether success is non-zero before trying to use it */
}
This relies on a rule in C that says any pointer to an object can be implicitly converted to a void pointer, and vice-versa, without loss.
Note that formally this is undefined, but it is all but sure to work. While any object pointer value is required to be able to convert to a void* and back without loss, there is nothing in the language that guarantees that a some_struct* can store a some_struct** without loss. But it has a very high likelihood of working just fine.
Your teacher gave you no option but to write formally illegal code. I don't see that you have any other option besides "cheating" like this.
int func(some_struct *arg) {
arg = malloc(sizeof(some_struct));
...
}
Here you just assign the result of malloc to the local arg variable. pointers are passed by value in C, a copy of the pointer gets passed to the function. You cannot change the pointer of the caller this way. Keep in mind the difference in a pointer and what it points to.
You have various options:
Return the pointer from the function:
some_struct *func(void) {
arg = malloc(sizeof(some_struct));
...
return arg;
}
...
some_struct *a = func();
Allocate the structure in the caller:
int func(some_struct *arg) {
...
arg->something = foo;
}
...
some_struct a;
func(&a);
Or dynamically allocate it
some_struct *a = malloc(sizeof *a);
func(a);
Using a pointer to the callers pointer:
int func(some_struct **arg) {
*arg = malloc(sizeof **arg);
}
...
some_struct *a;
func(&a);
Use a global variable (ugly..)
some_struct *global;
int func(void) {
global = malloc(sizeof *global);
}
...
some_struct *a;
func();
a = global;
You can't do it this way. You can't declare a struct by value, and then change it by address.
some_struct *s;
printf("Before: %d\n", s");
allocate(&s);
printf("After: %d\n", s");
...
/* The allocation function */
int allocate(some_struct **arg) {
*arg = malloc(sizeof(some_struct));
printf("In function: %d\n", *arg");
return 0;
}
You need to modify the pointed value for the struct. So you need another level of indirection, thus you have to send a pointer to the struct pointer.
Well, C uses pass-by-value, which means that functions get copies of their arguments, and any changes made to those copies don`t affect the original in the caller.
/* The allocation function */
int allocate(some_struct *arg) {
arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg");
return 0;
}
Here you pass in the address of your some_struct s. Then you discard that address, and replace it with whatever was returned by malloc. Then you return, and the return value of malloc is lost forever, and you've leaked memory. And your some_struct s has not been changed. It still has whatever random number it was initialized to, which you printed out.
If you may not change the signature of the allocate function, it can never be useful. It must either take the address of a pointer, so that it can modify the value of that pointer, or it must return a pointer that your caller can tuck away.

Resources