Thomas
Thomas

Reputation: 384

Allocating memory for a pointer inside a function call in C

I've made an example program to illustrate the problem. In test I allocate memory for foo to store two integers. Then, I set each of these integers to a value, and then I print them. Pretty simple, except I can only assign values to the integers if I do it inside of main - it won't work when I do it inside of test.


This code works:

#include <stdio.h>
#include <stdlib.h>

void test(int **foo) {
    *foo = malloc(2 * sizeof(int));
}

int main() {
    int *foo;

    test(&foo);

    foo[0] = 4;  // <---
    foo[1] = 3;  // <---

    printf("foo[0]: %d\n", foo[0]);
    printf("foo[1]: %d\n", foo[1]);

    return 0;
}

Output:

foo[0]: 4
foo[1]: 3

This code doesn't:

#include <stdio.h>
#include <stdlib.h>

void test(int **foo) {
    *foo = malloc(2 * sizeof(int));  // 3.
    *foo[0] = 4;  // 4. <---
    *foo[1] = 3;  // 5. <---
}

int main() {
    int *foo;  // 1.

    test(&foo);  // 2.

    printf("foo[0]: %d\n", foo[0]);
    printf("foo[1]: %d\n", foo[1]);

    return 0;
}

Output:

foo[0]: 4        // This is only 4 because it was already
                 //   4 from running the previous example
foo[1]: 5308612  // And this is obviously garbage

So, what's going on? This answer has been very helpful (or I thought it was at least), but it doesn't address why the assignments work in main but not test.

Here's my understanding of how the code in the second example should be working (I've put footnotes in the code to indicate the lines I'm referring to here):

  1. The program starts at main. I create the integer point foo, which is assigned a 4-byte block of memory at (for the sake of simplicity) address 1000.

  2. I send a reference to foo to the function test. So, it is passed 1000 as its parameter.

  3. A block of memory two integers in size (8 bytes) is allocated for foo.

  4. 4 is stored at address 1000

  5. 3 is stored at address 1004

So, what am I misunderstanding, and how can I fix the code in the second example so I can do my initialization of foo in a test rather than main?

Thanks!

Upvotes: 4

Views: 104

Answers (3)

Jo&#227;o Pinheiro
Jo&#227;o Pinheiro

Reputation: 122

Like Jonathan pointed out, it's a problem with operator precedence. [] has precedence over *, so it was being processed as an array of int pointers rather than a pointer to an array of ints.

Another possible solution that would avoid using pointers to pointers entirely would be for the function test() to return the memory address with the allocated memory instead of receiving foo as an argument.

#include <stdio.h>
#include <stdlib.h>

int* test() {
    int *bar = malloc(2 * sizeof(int));
    bar[0] = 4;
    bar[1] = 3;

    return bar;
}

int main() {
    int *foo = test();

    printf("foo[0]: %d\n", foo[0]);
    printf("foo[1]: %d\n", foo[1]);

    free(foo);
    return 0;
}

Upvotes: 0

Geoduck
Geoduck

Reputation: 8995

try this and you will see...order of operations:

void test(int **foo) {
    *foo = malloc(2 * sizeof(int));  // 3.
    (*foo)[0] = 4;  // 4. <---
    (*foo)[1] = 3;  // 5. <---
}

foo is a pointer to an int pointer. Accessing foo[1] would access whatever is on the stack after the foo declaration in main (nothing, so bad memory). You need to dereference before using the array [] operator. Hence, the parens should fix it.

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 753585

Precedence!

You need:

(*foo)[0] = 4;  // 4. <---
(*foo)[1] = 3;  // 5. <---

Without the parentheses, *foo[0] is *(foo[0]), which is actually the same as (*foo)[0], but *(foo[1]) goes writing who-knows-where. The * operator binds less tightly than the [] operator does, so you have to use parentheses.

char *arr[];   // array of pointers to char
char (*arr)[]; // pointer to array of char

Upvotes: 8

Related Questions