0
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

ElleryL
  • 507
  • 7
  • 16
  • You're doing the malloc() inside the function. The data is allocated there, but the pointer is not returned to the calling function. Therefore the allocated memory gets lost (this is a memory leak!). To fix, do the malloc from the calling function (main). Also, you are lucky that your first example worked because you did not allocate the memory for it to work. It might crash on some platforms. – TheGreatContini Sep 25 '17 at 01:36
  • @TheGreatContini Do you mean that; when the malloc is called, I actually successfully modify the array within the helperNotWorking(); but since it doesn't return the pointer; so I can't access the modified values that stored in the heap once I'm out of helperNotWorking()? – ElleryL Sep 25 '17 at 01:40
  • @ElleryL Correct! – TheGreatContini Sep 25 '17 at 01:41
  • 2
    These are both undefined behaviour – M.M Sep 25 '17 at 01:41
  • 3
    None of this code is correct. The first version is writing to an uninitialized pointer. Maybe it will "work", sometimes, but it is corrupting your runtime environment and will likely cause visible problems down the road. The second version allocates an array, writes to it, then effectively discards the pointer. Why not *return* the pointer so that it's visible to the caller? – Tom Karzes Sep 25 '17 at 01:41
  • @TomKarzes thanks; so for the second code; I can think that when malloc() is called; the heap memory have store three array's elements address(different address than they are created in the main) and values; then I modify each of them locally, the values in the heap memory changes correspondingly; however, I didn't return the pointer to the address saved in heap; once I'm out of the local, I can't access to the data I modify in the heap. – ElleryL Sep 25 '17 at 01:46
  • @xing, can you explain why the first code (regardless of its incorrectness) can "sometimes" modify the array element while second can't? – ElleryL Sep 25 '17 at 01:53
  • @xing; is it because second code have actually create a local variable arr while the first doesn't? – ElleryL Sep 25 '17 at 01:55
  • Your first problem, in your first method, is that you never allocate memory for `data` to point to. Surprisingly, the program may even seem to work, some of the time. See [this answer](https://stackoverflow.com/questions/37087286/c-program-crashes-when-adding-an-extra-int/37087465#37087465) to a related question, for an explanation of how this can happen (and how confusing it can be). – Steve Summit Sep 25 '17 at 02:08
  • And then your second problem, in your second method, is that since C passes arguments to functions *by value*, your function receives a *copy* of the `data` pointer from `main()`, and it overwrites that pointer when it calls `malloc`, but this doesn't change the `data` pointer in `main`. – Steve Summit Sep 25 '17 at 02:10

2 Answers2

3

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);
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Serge
  • 11,616
  • 3
  • 18
  • 28
0

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.

leyanpan
  • 433
  • 2
  • 9
  • Sorry, I didn't test the code after adding free. I just found out that I didn't free it before I posted the answer so I didn't think about it carefully. Thank you for the corrections. – leyanpan Sep 25 '17 at 02:08
  • No problem, I already saw that you fixed it, so I deleted my comment already. – Steve Summit Sep 25 '17 at 02:11