Kenji Emura
Kenji Emura

Reputation: 69

Using malloc to initialize char pointer VS not using malloc and just assign a string directly to the char pointer

I'm trying to understand how this memory allocation thing works when it comes to char and strings.

I know that the name of a declared array is just like a pointer to the first element of the array, but that array will live in the stack of the memory.

On the other hand, we use malloc when we want to use the heap of the memory, but I found that you can just initialize a char pointer and assign a string to it on the very same declaration line, so I have some questions regarding this matter:

1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";

2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:

char *pointer = malloc(sizeof(char) * 12); *pointer = "Hello world";

Can you please help me understand more about pointers and memory allocation? Thank you very much! :)

Upvotes: 1

Views: 7546

Answers (4)

Eric Postpischil
Eric Postpischil

Reputation: 222486

I know that the name of a declared array is just like a pointer to the first element of the array,…

This is not correct. An array behaves similarly to a pointer in many expressions (because it is automatically converted), but it is not just like a pointer to the first element. When used as the operand of sizeof or unary &, an array will be an array; it will not be converted to a pointer. Additionally, an array cannot be assigned just like a pointer can; you cannot assign a value to an array.

… but that array will live in the stack of the memory.

The storage of an array depends on its definition. If an object is defined outside of any function, it has static storage duration, meaning it exists for the entire execution of the program. If it is defined inside a function without _Thread_local or static has automatic storage duration, meaning it exists until execution of its associated block of code ends. C implementations overwhelmingly use the stack for objects of automatic storage duration (neglecting the fact that optimization can often make use of the stack unnecessary), but alternatives are possible.

On the other hand, we use malloc when we want to use the heap of the memory, but I found that you can just initialize a char pointer and assign a string to it on the very same declaration line, so I have some questions regarding this matter:

1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";

For the string literal "Hello world", the C implementation creates an array of characters with static storage duration, the same as if you had written char MyString[12]; or int x; at file scope. Assuming this array is not eliminated or otherwise altered by optimization, it is in some general area of memory that the C implementation uses for data built into the program (possibly a “.rodata” or similar read-only section).

Then, for char *pointer, the C implementation creates a pointer. If this definition appears outside a function, it has static storage duration, and the C implementation uses some general area of memory for that. If it appears inside a function, it has automatic storage duration, and the C implementation likely uses stack space for it.

Then, for the = "Hello world", the C implementation uses the array to initialize pointer. To do this, it converts the array to a pointer to its first element, and it uses that pointer as the initial value of pointer.

2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:

char *pointer = malloc(sizeof(char) * 12);

*pointer = "Hello world";

The second line is wrong because *pointer has a different role in a declaration than it does in an expression statement.

In char *pointer = …;, *pointer presents a “picture” of what should be a char. This is how declarations work in C. It says *pointer is a char, and therefore pointer is a pointer to a char. However, the thing being defined and initialized is not *pointer but is pointer.

In contrast, in *pointer = "Hello world";, *pointer is an expression. It takes the pointer pointer and applies the * operator to it. Since pointer is a pointer to char, *pointer is a char. Then *pointer = "Hello world"; attempts to assign "Hello world" to a char. This is an error because "Hello world" is not a char.

What you are attempting to do is to assign a pointer to "Hello world" to pointer. (More properly, a pointer to the first character of "Hello world".) To do this, use:

pointer = "Hello world";

Upvotes: 1

0___________
0___________

Reputation: 67476

Long question but the answer is very easy. Firstly you need to understand what the pointer is.

 *pointer = "Hello world";

Here you try to assign a pointer to the char. If you remove the * then you will assign the pointer to the string literal to the pointer.

Unless you have overloaded the assign operator it will not copy it to the allocated memory. Your malloc is pointless as you assign new value to the pointer and the memory allocated by the malloc is lost

You need to strcpy it instead

where is this information living?

It is implementation dependant where the string literals are stored. It can be anywhere. Remember that you can't modify the string literals. Attempt to do so is an Undefined Behaviour

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84551

1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";

Neither on the stack or on the heap. "Hello world" is a string literal, generally created in the rodata (read-only data) segment of the executable. In fact, unless you specify differently, the compiler is free to only store a single copy of "Hello world" even if you assign it to multiple pointers. While typically you cannot assign strings to pointers, since this is a string literal, you are actually assigning the address for the literal itself -- which is the only reason that works. Otherwise, as P__J__ notes, you must copy strings from one location to another.

2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:

char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";

You are mixing apples and oranges here. char *pointer = malloc (12); allocates storage for 12-characters (bytes) and then assigns the beginning address for that new block of storage to pointer as its value. (remember, a pointer is just a normal variable that holds the address to something else as its value)

For every allocation, there must be a validation that the call succeeded, or you will need to handle the failure. Allocation can, and does fail, and when it fails, malloc, calloc * realloc all return NULL. So each time you allocate, you

char *pointer = malloc(12);       /* note: sizeof (char) is always 1 */
if (pointer == NULL) {            /* you VALIDATE each allocation */
    perror ("malloc-pointer");
    return 1;
}

Continuing with your case above, you have allocated 12-bytes and assigned the starting address for the new memory block to pointer. Then, you inexplicably, derefernce pointer (e.g. *pointer which now has type char) and attempt to assign the address of the string literal as that character.

*pointer = "Hello world";    /* (invalid conversion between pointer and `char`) */

What you look like you want to do is to copy "Hello world" to the new block of memory held by pointer. To do so, since you already know "Hello world" is 12-characters (including the nul-terminating character), you can simply:

memcpy (pointer, "Hello world", 12);

(note: if you already have the length, there is no need to call strcpy and cause it to scan for the end-of-string, again)

Now your new allocated block of memory contains "Hello world", and the memory is mutable, so you can change any of the characters you like.

Since you have allocated the storage, it is up to you to free (pointer); when that memory is no longer in use.

That in a nutshell is the difference between assigning the address of a string literal to a pointer, or allocating storage and assigning the first address in the block of new storage to your pointer, and then copying anything you like to that new block (so long as you remain within the allocated bounds of the memory block allocated).

Look things over and let me know if you have further questions.

Upvotes: 5

Peter
Peter

Reputation: 36597

1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";

The string literal "Hello world" has static storage duration. This means it exists somewhere in memory accessible to your program, for as long as your program is running.

The exact place where it is located is implementation specific.

2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:

char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";

This doesn't work, since *pointer is the first char in the dynnamically allocated memory (returned by malloc()). The string literal "Hello world" is represented as an array of characters. An array of characters cannot be stored in a single char.

What you actually need to do in this case is copy data from the string literal to the dynamically allocated memory.

char *pointer = malloc(sizeof(char) * 12);
strcpy(pointer, "Hello world");            /* strcpy() is declared in standard header <string.h> *

Note that this doesn't change the data that represents the string literal. It copies the data in that string literal into the memory pointed at by pointer (and allocated dynamically by malloc()).

If you really want pointer to point at the (first character of) the string literal, then do

const char *pointer = "Hello world";

The const represents the fact that modifying a string literal gives undefined behaviour (and means the above prevents using pointer to modify that string literal).

If you want to write really bad code you could also do

char *pointer = "Hello world";   /*  Danger Will Robinson !!!! */

or (same net effect)

char *pointer;
pointer = "Hello world";     /*  Danger Will Robinson !!!! */

This pointer can now be used to modify contents of the string literal - but that causes undefined behaviour. Most compilers (if appropriately configured) will give warnings about this - which is one of many hints that you should not do this.

Upvotes: 2

Related Questions