By John


2009-10-07 19:00:00 8 Comments

Can someone explain to me why my call to malloc with a string size of 6 returns a sizeof of 4 bytes? In fact, any integer argument I give malloc I get a sizeof of 4. Next, I am trying to copy two strings. Why is my ouput of the copied string (NULL)? Following is my code:

int main()
{
    char * str = "string";
    char * copy = malloc(sizeof(str) + 1);
    printf("bytes allocated for copy: %d\n", sizeof(copy));
    while(*str != '\0'){
        *copy = *str;
        str++;
        copy++;
    }
    copy = '\0';
    printf("%s\n", copy);
}

8 comments

@Informate.it 2014-01-17 11:51:37

You can use:

size_t malloc_usable_size (void *ptr);

instead of : sizeof

But it returns the real size of the allocated memory block! Not the size you passed to malloc!

@Brad Larson 2014-01-17 17:36:20

As an aside, please stop suggesting edits that deface answers like this: stackoverflow.com/review/suggested-edits/3830819 . When you have the ability to comment, leave a comment if you disagree with the answers, but don't try to rewrite them yourself.

@kriss 2009-10-07 20:13:25

First you should understand that sizeof(xxx) where xxx is any left value expression (a variable) is always equivalent to do sizeof(type of xxx). Hence what is really doing your sizeof(str) is returning the size of a char *, that is the size of any other pointer. On a 32 bits architecture you'll get 4, on a 64 bits architecture it'll be 8, etc.

So, as others also explained you have to know the length of the string you want to allocate, and then add 1 to store the terminal \0, C implicitly use to put at the end of strings.

But to do what you want (copy a string and allocate necessary space) it will be more simple and more efficient to use strdup, that does exactly that : a malloc and a strcopy.

You should also not forget to free space you allocated yourself (using malloc, calloc, strdup or any other allocation function). In C it won't go away when allocated variable go out of scope. It will stay used until the end of the program. That's what you call a memory leak.

#include <string.h> /* for strdup, strlen */
#include <stdio.h> /* for printf */

int main()
{
    char * str = "string";
    char * copy = strdup(str);
    printf("bytes at least allocated for copy: %d\n", strlen(copy)+1);
    printf("%s\n", copy);
    free(copy);
}

One last point : I changed message to bytes at least allocated because you don't really know the size allocated when calling malloc. It quite often allocates a slighly more space that what you asked for. One reason is that in many memory managers free blocks are linked together using some hidden data structure and any allocated block should be able to contain at least such structure, another is that allocated blocks are always aligned in such a way to be compatible with any type alignment.

Hope it will help you to understand C a little better.

@Chris Lutz 2009-10-07 20:17:48

For what it's worth, strdup() is a nonstandard function, but it's so trivially easy to roll your own that it's not a big deal.

@kriss 2009-10-08 12:26:30

yes, you're right it's not standard with C, even C99, but very common (and you get _strdup, _wcsdup and some others in ISO C++). On the other hand library implementation are usually quite optimized not so trivial that it seems. I checked with gcc on Linux strdup if about 30% faster that a while loop and nearly 8% faster than the second best solution I could think of (malloc then strncpy). It's also easier to read. The big drawback is that malloc is hidden, hence programmers often forget freeing strduped vars. :-(

@eyalm 2009-10-07 19:47:35

  • sizeof() returns you the size of the pointer and not the amount of allocated bytes. You don't need to count the allocated bytes, just check if the returned pointer is not NULL.
  • The line copy = '\0'; resets the pointer and makes it NULL.

@John 2009-10-07 19:57:47

the pointer has been incremented at that point, so doesn't it just make the last byte of the string point to null?

@Chris Lutz 2009-10-07 20:04:45

@unknown - No, you left out the dereference operator. What you want is *copy = '\0' because copy = '\0' sets the pointer to '\0' (which is NULL as an int type).

@R Samuel Klatchko 2009-10-07 19:45:54

sizeof() returns the size of the actual type of the variable. So, when you define your type as char *, it returns the size of a pointer.

But if you made your variable an array, sizeof would return the size of the array itself, which would do what you want to do:

char *ptr = "moo to you";
char arr[] = "moo to you";

assert(sizeof(ptr) == 4);   // assuming 32 bit
assert(sizeof(arr) == 11);  // sizeof array includes terminating NUL
assert(strlen(arr) == 10);  // strlen does not include terminating NUL

@Chris Lutz 2009-10-07 19:51:33

You should include assert(strlen(ptr) == 10); for symmetry and completeness.

@mob 2009-10-07 19:09:41

To tackle your second questions, by executing the statement copy++ you have changed the value of copy (that is, the address in memory that holds a char array) so that by the time you print it out, it is pointing at the end of the array rather than the beginning (the value returned by malloc()). You will need an extra variable to update the string and be able to access the beginning of the string:

Edit to repair malloc/sizeof issue - thanks CL.

char * str = "string";
/*   char * copy = malloc(sizeof(str) + 1);  Oops  */
char * copy = malloc(strlen(str) + 1);
char * original_copy = copy;
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
    *copy = *str;
    str++;
    copy++;
}
copy = '\0';
printf("%s\n", original_copy);

@Chris Lutz 2009-10-07 19:18:21

There's still a problem with malloc(sizeof(str) + 1) - sizeof(str) is sizeof(char *) is 4 on most platforms, and is unrelated to the length of the string.

@John 2009-10-07 19:51:56

Ah! i'd forgotten that since I incremented the pointer printf was printing the null character I appended at the end and not the entire string. thanks so much.

@SayeedHussain 2013-05-15 08:00:08

copy='\0' should be *copy='\0'

@RedGlyph 2009-10-07 19:04:17

sizeof(str) returns the space necessary to store the pointer to the string, not the string itself. You can see the size of the string with strlen(str) for example.

Then you affect your copy pointer to an integer which has the value 0 (the character '\0'). It is the same as copy = NULL, which is what the printf() function shows you.

@AraK 2009-10-07 19:01:58

sizeof(str) returns the size of a pointer of type char*. What you should do is to malloc the size of the string it self:

char * copy = malloc(strlen(str) + 1);

Also, these lines:

while(*str != '\0'){
        *copy = *str;
        str++;
        copy++;
}
copy = '\0';

Can be rewritten easily in C like this:

while(*copy++ = *str++);

@Chris Lutz 2009-10-07 19:11:52

They can also be rewritten as strcpy(copy, str); which is probably more efficient than what you have.

@AraK 2009-10-07 19:18:15

@Chris Oops. I reinvented the wheel :)

@Ed S. 2009-10-07 19:18:20

@AraK: Agreed. A pretty common idiom in C

@Chris Lutz 2009-10-07 19:19:05

@Ed - I wouldn't say common (not in modern times, at least) but it's definitely widely-known.

@Andrew Song 2009-10-07 19:30:52

For completeness sake, it might be worth mentioning that this works because chars are one byte, and thus strlen(str) gives the number of bytes the text requires (which you add one too so you can fit the null terminator). Remember, malloc(..) takes the size (in bytes) of the heap-allocated space you require as an argument.

@David R Tribble 2009-10-07 20:51:35

Common idiom code can also be easy to get wrong. I'd replace the empty ';' null statement with a {} or, better yet, a continue; statement. And yes, @Lutz, strcpy() is probably more efficient as well as being more readable.

@RussellH 2009-10-08 00:23:09

Steve McConnell (Code Complete) used this very example (orignally from K & R) as code that was difficult to read.

@SayeedHussain 2013-05-15 08:00:31

copy='\0' should be *copy='\0'

@chux - Reinstate Monica 2014-11-20 17:04:55

As @paranoidcoder suggests, *copy = '\0'; is needed to fix this other-wise good answer.

@Dean J 2009-10-07 19:01:45

You're getting the size of the str pointer (4 bytes), not what it's pointing to?

@Byron Whitlock 2009-10-07 19:02:33

Why the question mark? you not sure of your answer ;) It's the right one. :)

@Chris Lutz 2009-10-07 19:12:41

Not really. The size of what it's pointing to (i.e. char type) is 1, which is even less useful. You need the string length like in @AraK's answer.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] Why does sizeof(x++) not increment x?

  • 2011-11-22 11:07:16
  • Neigyl R. Noval
  • 28859 View
  • 497 Score
  • 9 Answer
  • Tags:   c sizeof

13 Answered Questions

[SOLVED] Difference between malloc and calloc?

  • 2009-10-08 15:04:33
  • user105033
  • 510850 View
  • 756 Score
  • 13 Answer
  • Tags:   c malloc calloc

26 Answered Questions

[SOLVED] Do I cast the result of malloc?

  • 2009-03-03 10:13:02
  • Patrick McDonald
  • 221628 View
  • 2349 Score
  • 26 Answer
  • Tags:   c malloc casting

17 Answered Questions

[SOLVED] What's the rationale for null terminated strings?

11 Answered Questions

[SOLVED] Why isn't sizeof for a struct equal to the sum of sizeof of each member?

17 Answered Questions

[SOLVED] What REALLY happens when you don't free after malloc?

  • 2009-03-17 15:29:09
  • Scott
  • 108033 View
  • 526 Score
  • 17 Answer
  • Tags:   c malloc free

3 Answered Questions

[SOLVED] why sizeof unsigned char array[10] is 10

  • 2013-08-04 23:56:28
  • Maxwell S.
  • 4692 View
  • 1 Score
  • 3 Answer
  • Tags:   c sizeof

Sponsored Content