adoprix
adoprix

Reputation: 63

difference between creating an array "normally" and with malloc

I was messing with C pointers to pointers in functions to learn. I created a string array, and wanted to change it in the function foo with a pointer to pointer. I then print it, just to see.

Problem is: if I create it "normally": char array[] = "yeah", the code doesn't work and I see a bunch of weird characters on the console. But, If I create it with a malloc, it works. I really want to understand the difference.

This works:

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

void foo(char **ptr);

int main(int argc, char *argv[]) {
    char *array = malloc(sizeof("yeah"));  //I need to malloc here, or it doesn't work. Why ?
    strcpy(array, "yeah");

    printf("array before : %s \n", array);

    char *ptr = array;
    char **pt = &ptr;

    foo(&array);

    printf("array after : %s \n", array);

    free(array);
}

void foo(char **ptr) {
    char *truc = malloc(sizeof(char) * 20);  //I need to malloc here, else it doesn't work. Why ?
    strcpy(truc, "then");

    *ptr = truc;
}

but this doesn't, it prints nasty characters on the console:

void foo(char **ptr);

int main(int argc, char *argv[]) {
    char array[] = "yeah"; //created "normally"

    printf("array before : %s \n", array);

    char *ptr = array;
    char **pt = &ptr;

    foo(&array);

    printf("array after : %s \n", array);

    free(array);
}

void foo(char **ptr) {
    char truc = "then";

    *ptr = truc;
}

What is the difference between:

char array[] = "yeah";

and

char *array = malloc(sizeof("yeah");
strcpy(array, "yeah");

Upvotes: 4

Views: 352

Answers (1)

Gutblender
Gutblender

Reputation: 1350

The Array Way

First thing you should note: The code: char array[] = "yeah"; will work.
Note: if you do this, you do not call free(array) because it is not a pointer to dynamically-allocated memory, and does not need to be dynamically returned to the heap. It exists on the stack. Read on...

But the function foo() here is the problem. When foo() is called, the string truc (which also could be declared char truc[] = "then";) exists in a stack frame, which is a section of program memory, which only exists until foo() returns. If you change array to point to memory within that stack frame, what happens when that function returns? That stack frame becomes undefined, and you're left pointing at junk memory.

If you want to change the contents of the string in array, you could ensure the buffer is long enough, and foo() could strcpy(array, "then") into it. So, you're not changing the pointer itself, just the memory it points to. This isn't what I'd call good software design, but for the sake of an example, it would work for you. Like this:

void foo(char * ptr)
{
    strcpy(ptr, "then");
}

So why doesn't it work without malloc() in main()?

When you don't malloc() in main(), array represents, as it suggests, an array. The identifier is not itself a pointer, it is an array; however, it decays to a pointer, or if you will, acts like one. That's why you could pass it off as one, if you wanted, like if you passed it to foo(). Now, if you reference the address of array, like &array, (char*)array, &array, &array[0] are all the same - pointers to the beginning of array. Your foo() is actually writing a memory address to the memory of array, in this case.

What does this do? Well, the technical answer is undefined behavior. But I would guess that it's writing a 32-bit integer (a memory address) to a chunk of memory that used to represent 4 8-bit characters in a string. So now you've corrupted exactly four characters. And, if foo() is using malloc() as you show, also introduced a memory leak.

The neat part of this is that your string is exactly four characters, so this shouldn't corrupt the null terminator '\0' at the end of the string. Let me guess, you see exactly four junk characters?

Upvotes: 2

Related Questions