简体   繁体   中英

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM