Lokesh
Lokesh

Reputation: 3112

String and pointers in C

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

int main(void)
{
        char* a = malloc(5 * sizeof(char));
        a = "1";
        free(a);
}

I have two questions regarding the above code:

  1. Why does the code gives an error with free(a) when I initialize a like this :

a = "1"

and doesn't give any error with free(a) when I initialize a like this :

a[0] = '1'.

  1. When I initialize a with a[0] = '1' and print the string a using printf("%s", a) why do I get the result

    '1'

without declaring the second index with a '\0'?

Upvotes: 5

Views: 193

Answers (5)

David Heffernan
David Heffernan

Reputation: 612993

The rules with malloc and free are that you must only pass to free a pointer that was allocated by a call to malloc (or one of its equivalents like realloc or calloc). You do not do that:

char* a = malloc(5 * sizeof(char));
a = "1";
free(a);

When you call free, you pass a which was not allocated by a call to malloc. This results in your program having undefined behaviour.


The problem in your understanding is that I suspect you don't understand what a = "1" does.

I suspect that you imagine this to copy the string in to the memory that you allocated it does not. It changes the pointer a to point to a different address.

Indeed, by assigning to a, rather than the memory that it points to, you are leaking the allocated memory. Your code is exactly analogous to this:

int i = 1;
i = 2;

I'm sure you can see that the initialization of i is pointless because you immediately overwrite the value of i with a new value. That's exactly what you did with your pointer.


You can copy the string with strcpy. Like this:

char* a = malloc(5 * sizeof(char));
strcpy(a, "1");
free(a);

Similarly, when you wrote

char* a = malloc(5 * sizeof(char));
a[0] = '1';
printf("%s", a);
free(a);

you were assigning the contents of the buffer allocated by your call to malloc. And hence the call to free is correct.

However, the string is not necessarily null-terminated when you do that. You observed that your printf appeared to work but that was just by chance.

The contents of a[1] are ill-defined and it seems that, by chance, a[1] did contain a null when you ran your program.

This is why you typically use a string function like strcpy to perform copies and ensure null-termination. You do of course need to take care not to overrun your buffer.


Finally, by definition, sizeof(char) == 1 so you can write the malloc like this:

char* a = malloc(5);

Upvotes: 11

Dr. Debasish Jana
Dr. Debasish Jana

Reputation: 7118

Corrected program with inline comments for your understanding:

int main(void)
{
  char* a = (char *) malloc(5 * sizeof(char)); // prefer casting from void * to char *
  // a = "1"; -- wrong conversion from string constant to char *
  strcpy(a, "1"); // this would work
  free(a);
}

Upvotes: -2

macfij
macfij

Reputation: 3209

a = "1";

makes a point to a string literal, which is stored in read-only memory. You can not free() that part of memory.

a[0] = '1'; makes it to store a value of 31 (since that's the hex ascii value of 1) in the first byte that a points to. a still points to address that malloc had returned, therefore freeing it is legal operation. a[0] is the same as *(a + 0), so you see that address of a is untouched, contents where a points to are changed.

Other answers already have the information about null terminating your char array. You should know that printf() stops writing values to stdout when it encouters a null terminator. If there's '1' at 0th position and no '\0' at 1st position of your array, you might see some garbage values.


You should know that "1" and '1' are two different things.

Upvotes: 1

Bathsheba
Bathsheba

Reputation: 234715

a = "1"; is assigning read-only memory to a. a now points to a completely different memory location. The previous return of malloc is now lost so you will not be able to free the memory.

This is a disaster since, not including the memory leak, you have undefined behaviour when attempting to free the new value of a. Boom. Futhermore, if you attempt to modify the contents of a then that's undefined behaviour too. Boom.

Without the errant reassignment, a[0] = '1' is perfectly fine: you're deferencing the zeroth element of the allocated character buffer and setting its value to literal 1.

But if you attempt printf("%s", a) on this then, boom! More undefined behaviour since you haven't null-terminated the character buffer which printf requires you to do in order to prevent it from accessing memory that you don't own. To to that, use a[1] = 0.

Upvotes: 4

Imre Kerr
Imre Kerr

Reputation: 2428

When you do

a = "1";

a no longer points to the memory you allocated with malloc. Rather, it points to a string constant, stored in the text segment of your program. Naturally, such a pointer can't be freed. The original a pointer is lost.

As for your second question, that is undefined behavior. a[1] happened to be a null character by sheer dumb luck, but you should of course not rely on this happening.

Upvotes: 2

Related Questions