Thread: Here we go again: when to use Malloc and when not?

  1. #1
    Registered User
    Join Date
    Jul 2011
    Posts
    99

    Here we go again: when to use Malloc and when not?

    I do not have a good theoretical grasp of when to use malloc(). I know what it does, but I am too new to C to really dig it. I am quite aware that a considerable number of eyes are starting to glaze over now out of sheer boredom, but I searched for it, found a lot, but nowhere a good and concise overview.

    I have found one clear use for malloc(), if I want persistent results from a function that do not get cleared when I exit the function, I use malloc. The rest is kind of vague with ominous talks about memory management, safe pieces of memory and what all, conceptual clarity is lacking. So, to be clear, my question is when one should use malloc.

    The example I am using is a very simple concatenation.

    Malloc version (not mine):
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BEGIN "@@"
    #define END "CCC"
    
    int main (void)
      {  
        char *result = malloc(100 * sizeof(char));  // create some string space
    
        strcpy(result, BEGIN);              
        // result holds @@
        strcat(result, "this is a message");
        //result holds @@this is a message
        strcat(result, END);   
        // result holds @@this is a messageCCC
    
        printf("%s\n\n", result);
        free(result); 
        return 0; }
    The version without malloc:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BEGIN "@@"
    #define END "CCC"
    
    int main (void)
      {  
       char *result;
    
        strcat(result, BEGIN);    
        // result holds @@
        strcat(result, "this is a message");     
        //  result holds @@this is a message
        strcat(result, END);   
        // result holds @@this is a messageCCC
    
        printf("%s\n\n", result);
        return 0; }
    Both versions run well, but is this coincidence? What risks to I run if I work without malloc in this case, is this good programming or a don't?
    Last edited by django; 08-08-2011 at 08:59 AM.

  2. #2
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    What you really need to do is read about the differences between static and dynamic (malloc & friends) memory allocation. This is a subject that has been debated so many times that I just won't believe you haven't found anything on it so far. You don't even care that much about C in particular right now, but rather about understanding the broader subject.
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by django
    Both versions run well, but is this coincidence?
    Yes. The first version is fine, other than a missing check that malloc does not return a null pointer. You end up with a string of length 22, which means that you need a char array of at least size 23 to contain it. Since the pointer points to the first character of a dynamic char array of size 100, you're safe.

    The second example results in undefined behaviour. result was not initialised, so it contains "garbage", and you will essentially be overwriting memory that was not allocated to you.

    Code:
    Note that in this case it would be easier to do without malloc by using a fixed size array, e.g.,
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BEGIN "@@"
    #define END "CCC"
    
    int main(void)
    {
        char result[100];
    
        strcat(result, BEGIN);
        // result holds @@
        strcat(result, "this is a message");
        //  result holds @@this is a message
        strcat(result, END);
        // result holds @@this is a messageCCC
    
        printf("%s\n\n", result);
        return 0;
    }
    I would be more likely to use malloc if there is need for a dynamic array, or if the size is large.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Jul 2011
    Posts
    99
    Ok. However, malloc does not initialize either, for that you would have to use calloc. Now suppose that I would use as a first statement not strcat, but strcpy, would this initialize the results pointer in a correct way? And, having done this and thus eliminated the fault of using an uninitialized pointer, would it still be fundamentally incorrect code (although it may by coincidence display the right result)?
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BEGIN "@@"
    #define END "CCC"
    
    int main (void)
      {  
        char *result;
    
        strcpy(result, BEGIN);                       
        // result holds @@
        strcat(result, "this is a message");     
        //  result holds @@this is a message
        strcat(result, END);                         
        // result holds @@this is a messageCCC
    
        printf("%s\n\n", result);
        return 0; }

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by django
    However, malloc does not initialize either, for that you would have to use calloc.
    No, malloc initialises your pointer. It does not initialise the contents of the allocated memory, but that is fine since you are using strcpy immediately.

    Quote Originally Posted by django
    Now suppose that I would use as a first statement not strcat, but strcpy, would this initialize the results pointer in a correct way? And, having done this and thus eliminated the fault of using an uninitialized pointer, would it still be fundamentally incorrect code (although it may by coincidence display the right result)?
    Oh, right. I did not notice that you were using strcat before strcpy in your second example. An uninitialised pointer is an uninitialised pointer, regardless of what you try to do to what it points to.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Read up on the subtleties of static vs. dynamic memory allocation here.

  7. #7
    Registered User
    Join Date
    Jul 2011
    Posts
    99
    itCbitC, thanks for the link, helpful, especially on what initializing a pointer is exactly.

    Quote Originally Posted by laserlight View Post
    No, malloc initializes your pointer. It does not initialize the contents of the allocated memory, but that is fine since you are using strcpy immediately.
    Ok, insightful, I missed the distinction, I stand corrected.

    Quote Originally Posted by laserlight View Post
    Oh, right. I did not notice that you were using strcat before strcpy in your second example. An uninitialised pointer is an uninitialised pointer, regardless of what you try to do to what it points to.
    So basically, there are two ways to initialize a pointer:
    (1) dynamically assign memory to it
    (2) statically assign memory to it by doing something of the sort
    Code:
        int i = 2;
        int *p;
        p = &i;
    correct?

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by django
    So basically, there are two ways to initialize a pointer:
    (1) dynamically assign memory to it
    (2) statically assign memory to it by doing something of the sort
    I would not say "dynamically assign memory" or "statically assign memory". Rather, I would consider the two ways to be:
    • Assign the address of an object (or function, in the case of a function pointer) to the pointer (or as a special case, the address one past that of the last element of an array).
    • Assign a null pointer constant, or the value of a null pointer, to the pointer.

    Whether the address was obtained via malloc or by taking the address of a local variable does not matter when we are just talking about providing a pointer with a value.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by django View Post
    Both versions run well, but is this coincidence? What risks to I run if I work without malloc in this case, is this good programming or a don't?
    The second version works by pure dumb luck and nothing better... Ask yourself: "Where does result point?" ... pray it's not pointing at your program's stack or some necessary system control block when you start dumping text into it...

    You cannot ever use memory you don't own... It's like carrying water without a bucket... malloc() and free() lease and return memory. There are no shortcuts.
    Last edited by CommonTater; 08-08-2011 at 11:57 AM.

  10. #10
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Here is another good read on pointers that might help explain some of these things: Prelude's Pointer Tutorial.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  11. #11
    Registered User
    Join Date
    Jul 2011
    Posts
    99
    Ok, I get it. Using an uninitialized pointer is bad programming (the truth is so simple when you see it).

    Please allow me for one more question in which I try to concatenate two pointers:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    #define BEGIN "@@"
    #define END "CCC"
    
    int main (void) {
      
    	char *p;
    	char *q;
    	p = BEGIN;
    	q = "yessss";
    	printf("Concatenation: %s\n",strcat(q,p));
    	printf("Value of BEGIN: %s\n",BEGIN);
    	
        return 0; 
    }
    Now, I know how this can be done. By using a target pointer with enough memory allocated etc. But that is not my point, the point is that I try to understand what's happening here. The output I get is this:
    Code:
    Concatenation: yessss@@
    Value of BEGIN: @
    As you can see, the value of BEGIN has changed unintentionally. What could be an explanation, is that I try to write too much to a string that was initially allocated less memory and that this basically screws up everything and overwrites the BEGIN array. Is this correct reasoning?
    Now to be sure, just another snipplet:
    Code:
    char *p = "so fine";
    <...lots of other code...>
    p = "even finder";
    In my current understanding, this is all neat and dandy because the pointer simply gets assigned to the first element of another chunk of well managed memory. Correct?

    Silly questions from where you stand, but I am stepwise trying to get my head around it.
    Thanks for your patience.

  12. #12
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    p and q both point to read-only memory (string literals are put somewhere, and you are not guaranteed any ability to modify them), and any attempt to write to read-only memory is not going to end well.

  13. #13
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Well no... it's because you are modifying a string literal... (i.e. text in quotes) and that's an even bigger No No than uninitialized pointers.

    C does not do "neat and dandy" very well at all... you have to do that for it. There is no garbage collection, memory management... heck, there isn't even an official string type (other than "char arrays with trailing 0s). If it's going to happen in C, it's because you've told it to do it!

  14. #14
    Registered User
    Join Date
    Jul 2011
    Posts
    99
    Does that mean that my second code snipplet is also bad programming, so things like:
    Code:
    char *p = "so fine";
    <...lots of other code...>
    p = "even finder";
    ?

  15. #15
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    How are we supposed to know? That depends on what you do with <...lots of other code...>. You can make p point to stuff. You just can't try and change that stuff once you've done so. (Neither of the two lines you posted involve trying to change that stuff.)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 05-19-2010, 02:12 AM
  2. Malloc help
    By MyNameIs.. in forum C Programming
    Replies: 5
    Last Post: 04-19-2010, 02:19 PM
  3. Replies: 7
    Last Post: 10-01-2008, 07:45 PM
  4. malloc()
    By vb.bajpai in forum C Programming
    Replies: 8
    Last Post: 06-14-2007, 10:50 AM
  5. When and when not to use malloc()?
    By John.H in forum C Programming
    Replies: 5
    Last Post: 03-24-2003, 06:00 PM