0

I want to make a function in C that would dynamically allocate memory for a pointer in parameter of the function.

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

int allocate(char * arr, int size){
    int code = -1;
    arr = malloc(size);
    if(arr != NULL) code = size;

    return code;    
}

void main(){
    char * array;

    if(allocate(array,4) != -1){
        printf("allocated!\n");

        if(array == NULL) printf("Oops it actually didn't allocate!\n");
    }
} 

When I execute the program; it will only display "allocated!" and "Oops it actually didn't allocate!". That means the memory allocation did happen (because the return code of the function is not -1. But then when I check if array is equal to NULL; it actually is!

This is a programming problem that I've had and sadly in some cases I can't use a workaround like this char * allocate(char * arr, int size); and assigning the return value to char * array.

M.M
  • 138,810
  • 21
  • 208
  • 365
Paiku Han
  • 581
  • 2
  • 16
  • 38
  • you need char** arr, the arr you assign to now in the function is a copy of the one in main – stijn Dec 13 '14 at 08:28
  • 3
    C uses pass-by-value. The function receives a copy of the argument supplied. – M.M Dec 13 '14 at 08:38

4 Answers4

8

You lack a level of indirection, you need char**.

Excuse the bad formatting, I write from my phone.

Char* array, array is bound to a memory slot (that will contain a value that points to another memory slot that would be interpreted as a char).

So you copy that value to the function and modify that value locally in allocate, but the modification never reaches the outside scope.

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

int allocate(char ** arr, int size){
    int code = -1;
    *arr = malloc(size);
    if(*arr != NULL) code = size;

    return code;    
}

void main(){
    char * array;

    if(allocate(&array,4) != -1){
        printf("allocated!\n");

        if(array == NULL) printf("Oops it actually didn't allocate!\n");
    }
} 

Not done C in something like 10 years but it should be OK.

freakhill
  • 628
  • 3
  • 6
  • I have my doubt on this answer because "that will contain a value that would be interpreted as a char" is not always true. let's take for instance an string: we can represent it with a char pointer. Take this example: `char * str = malloc(256);` and then go through the entire array and assign a value to each char of the array like this `for(i = 0; i < 256; i++) str[i] = 'x';`. The program would work perfectly (no crash, or segmentation fault). as long as I am working within the array's boundaries. what you did is actually more like an array of an array (e.g. char * argv[] aka char ** argv[]). – Paiku Han Dec 13 '14 at 08:52
  • It works fine with your method but I keep thinking Matt McNabb explains better the reason why it does! – Paiku Han Dec 13 '14 at 09:15
  • oh sorry the phone ate a part of my sentence. – freakhill Dec 13 '14 at 11:58
2

You can allocate memory inside your function and return the address as shown below There are also changes like instead of void main it should be int main()

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

char *allocate( int size){
    char *arr;
    arr = malloc(size);

    return arr;    
}

int main(){
    char * array;

    if((array = allocate(4)) != NULL){
        printf("allocated!\n");
    }
    return 0;
} 
Gopi
  • 19,784
  • 4
  • 24
  • 36
  • This example is confusing. First argument to `allocate` is never used. – Piotr Praszmo Dec 13 '14 at 08:57
  • @Banthar Yes that is not required removed it – Gopi Dec 13 '14 at 08:58
  • I've been asked to return a -1 if something went wrong! (by the way that workaround is the one I've always used - see and of my post). – Paiku Han Dec 13 '14 at 09:01
  • @PaikuHan What `malloc()` returns is NULL when there is a allocation failure or allocation of zero bytes is done so it is better you do it this way else you some variable and return that value as required you can return -1 – Gopi Dec 13 '14 at 09:05
  • I agree, the first argument to allocate() should be eliminated. However, overall this is a much better method that having to mess with multiple de-reference operations – user3629249 Dec 13 '14 at 09:07
  • @user3629249 Which first arguement is it you are talking about? Just the size is what being passed – Gopi Dec 13 '14 at 09:08
  • @Gopi someone asked me to solve a programming exercice he has been given to. And it states "create a function that allocate memory dynamically and return -1 if something went wrong" – Paiku Han Dec 13 '14 at 09:09
  • @PaikuHan Yes you can return -1 instead of 0 here and check for -1 instead of NULL in your main() – Gopi Dec 13 '14 at 09:11
1

Arguments to functions in C are passed by value. This means following function has no sense:

void f(int x) {
    x = 1;
}

int y = 0;
f(y);
// y is still 0

When f is invoked, y is copied to x. Any change to x changes that copy and won't affect y. To work around this, you need to either use return value or pass a pointer to y:

void f(int* x) {
    *x = 1;
}

int y = 0;
f(&y);
// y is now 1

Here x is still a copy (of a pointer) but it points to y. Changes to x wont be visible outside that function. But changing *x modifies y.

The same rules apply to pointer arguments. You just need one more * for arguments you want to modify:

int allocate(char** arr, int size) {
    *arr = malloc(size);
}

char *ptr;
allocate(&ptr);
Piotr Praszmo
  • 17,928
  • 1
  • 57
  • 65
0

Also note that checking array for NULL isn't sufficient here, because a locally defined variable could contain garbage value (thus, not being NULL). You have to assign NULL to it before the allocation:

char *array = NULL;

Philipp Murry
  • 1,660
  • 9
  • 13
  • 3
    He expects that `array = malloc`... will update `array` (therefore initializing array prior to that is unnecessary) – M.M Dec 13 '14 at 08:42