Search code examples
cmallocdynamic-arrays

Dynamically allocating and copying an array


I sometimes see code like this:

char* copyStr(char* input) {
  int inputLength;
  char *answer;

  inputLength = strlen(input);

  answer = malloc(inputLength + 1);
  answer = input;

  return answer;
}

People often say this code doesn't work and that this pattern

answer = malloc(inputLength + 1);
answer = input;

makes no sense. Why is it so? To my eye, the code is OK. It allocates the right amount of memory for the answer, and then copies the input to the answer. And it seems to work in my tests, for example

int main()
{
   printf ("%s\n", copyStr("Hello world!"));
}

does what I expect it to do. So what's wrong with it?


Solution

  • To put it simply. This code:

    var = foo();
    var = bar();
    

    is 100% equivalent to this in all1 situations:

    foo();
    var = bar();
    

    Furthermore, if foo() has no side effects, it's 100% equivalent to just the last line:

    // foo(); 
    var = bar();
    

    This goes for ANY function, including malloc. If we for a moment forget what malloc does and just focus on what just have been said, we can quickly realize what's written in the comments in this code:

    answer = malloc(inputLength + 1);
    // Here, the variable answer contains the return value from the call to malloc
    answer = input;
    // Here, it contains the value of input. The old value is overwritten, and
    // is - unless you saved it in another variable - permanently lost.
    

    What malloc does really simple. It returns a pointer to a memory block, or a NULL pointer if the allocation failed.2 That's it. What you are doing with a call like ptr = malloc(size) is absolutely nothing more fancy than storing that address in the pointer variable ptr. And pointer variables are in the same way no more fancy than other variables like int or float. An int stores an integer. A pointer stores a memory address. There's no magic here.

    1It's 100% equivalent except you're doing really fancy stuff like reading the variable var with an external program 2malloc(0) can return a non-null pointer, but in practice it does not make a difference since it would be undefined behavior to dereference it, and allocating zero bytes is a pretty pointless (haha, point) operation.