Allocate memory and save string in c

72,770

Solution 1

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

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|x|x|x|x|x|x|x|x|x|x|x|x|   (uninitialized memory, heap)
        +-+-+-+-+-+-+-+-+-+-+-+-+

test = "testingonly";

        +-+-+-+-+-+-+-+-+-+-+-+-+
test +  |x|x|x|x|x|x|x|x|x|x|x|x|
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     +->|t|e|s|t|i|n|g|o|n|l|y|0|  
        +-+-+-+-+-+-+-+-+-+-+-+-+

free(test); // error, because test is no longer pointing to allocated space.

Instead of changing the pointer test, you need to copy the string "testingonly" into the allocated place using e.g. strcpy or use strdup. Note that functions like malloc and strdup return NULL if insufficient memory is available, and thus should be checked.

char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+

or

char *test = strdup("testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+

Solution 2

You answered your question already. Essentially , strcpy is the appropriate way of copying string.

Solution 3

The first version doesn't create a string on the stack, but you're correct that you're not allowed to free it after the assignment. String literals are usually stored in constant/read-only sections of memory. The assignment doesn't copy anything, just makes test point to that area of memory. You cannot free it. You also cannot modify that string.

Your second piece of code is correct and usual. You might want to also look into strdup if your implementation has that.

Solution 4

Well you are correct. Now lets examine first piece of code.

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

Above code is no issues.

test = "testingonly";

Here you modified the pointer test leading to memory leak. And when you try to free you are not freeing actual allocated pointer but one "testingonly" literal pointing to. Literal points to constant memory which cannot be overridden in usual scenarios.

Now about second piece of code, this will work fine as you explicitly copied data from where literal is residing to heap where your test is pointing.

To your second point yes strcpy is a usual way. Other ways are 'memcpy' if you are copying raw bytes.

NOTE: Literals are not stored on stack. But you cannot modify location where literals are stored.

Share:
72,770

Related videos on Youtube

pluckyDuck
Author by

pluckyDuck

Updated on January 02, 2020

Comments

  • pluckyDuck
    pluckyDuck over 4 years

    I was wondering why the following code isnt't working

    int main(int argc, char **argv)
    {
         char *test = (char*) malloc(12*sizeof(char));
         test = "testingonly";
         free(test);
    }
    

    After thinking about it my assumption was that first i allocate space for 12 chars in memory but the assignment in the next line creates a char array on the stack and the memory address of that is passed to test. So free() tries to release space on the stack which is not allowed. Is that correct?

    So what would be the correct approach to save a string on the heap? Is the following a common way?

    int main(int argc, char **argv)
    {
         char *test = (char*) malloc(12*sizeof(char));
         strcpy(test, "testingonly");
         free(test);
    }
    
    • Jonathan Leffler
      Jonathan Leffler over 12 years
      The first solution illustrates a classic memory leak; you get a pointer to some allocated memory, then lose the only reference to it when you assign the pointer to the string literal to test. Thereafter, there is no legitimate way for you to reference the allocated memory - a leak.
    • Lundin
      Lundin over 12 years
      Never typecast the result of malloc in C, it is pointless and only hides away bugs and compiler warnings.
    • Agnius Vasiliauskas
      Agnius Vasiliauskas over 12 years
      yes - use strcpy or strncpy or memcpy. strncpy is better than strcpy, because it helps to avoid buffer overrun problem while copying at max N characters.
    • Lundin
      Lundin over 12 years
      @0x69 strncpy won't help against buffer overruns, that's a myth. Because strncpy will indeed write n characters to a buffer, but if there is no more room in said buffer it will not write any null termination of the string. So it will cause the program to crash and burn just as much as strcpy will. The solution to either problem is of course, to know what you are doing. There are no problems with using strcpy, as long as you know the nature of both the source and the destination.
    • Agnius Vasiliauskas
      Agnius Vasiliauskas over 12 years
      Still i think that not writing null termination to buffer is better situation than writing null char to outside of buffer (buffer overrun). In first case - usually when printing such string you will see garbage data from memory while in second - your program may crash in ANY un-predictable way. So i somehow think that first error type is more easy to localize in code than second. But i may be wrong.
  • Dave
    Dave over 12 years
    As long as you know the appropriate memory has already been allocated in the destination string, and both strings are null terminated.
  • Keith Thompson
    Keith Thompson over 12 years
    strncpy is not a safer version of strcpy. It can leave the target array unterminated. It's very rarely the right solution.
  • Mat
    Mat over 12 years
    @Keith: right, removed reference to that one. strdup is kind of nice though (assuming you know your input to be 1. a valid C string and 2. of acceptable size - whatever that is for your app).
  • Amit Singh Tomar
    Amit Singh Tomar over 12 years
    +1 for "this will work fine as you explicitly copied data from where literal is residing to heap where your test is pointing"
  • Cătălina Sîrbu
    Cătălina Sîrbu over 3 years
    what about test[0] = 0 and then test = ''desired string''?
  • AndersK
    AndersK over 3 years
    assuming you allocated test before - then your first statement test[0] = 0 will set the first character to \0 but once you do test = "desired string", test will point to the new string somewhere in read-only memory (since it is a literal). once that literal goes out of scope, test will no longer point to valid memory.