Dynamic memory location in C

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • vktripathi
    New Member
    • Sep 2008
    • 1

    #1

    Dynamic memory location in C

    This is about how to use {malloc,calloc, alloc} in efficient way.
    Also tell me about 'free' function and its use.
  • Laharl
    Recognized Expert Contributor
    • Sep 2007
    • 849

    #2
    Have you tried Google?

    Comment

    • gpraghuram
      Recognized Expert Top Contributor
      • Mar 2007
      • 1275

      #3
      My suggestion would be get K&R C book and start reading it.


      Raghu

      Comment

      • Alien
        New Member
        • Sep 2007
        • 61

        #4
        Please do some research (or Googling) on them, try them out. If you get stuck then come here.

        Don't take it the wrong way, but you can't just throw a random question like "Please explain what malloc does" without any sign of doing research on it.

        malloc is one of the difficult functions i came across when I did it and if you can't be bothered doing some research on it, chances are you won't go too far in coding with it.

        Comment

        • Tassos Souris
          New Member
          • Aug 2008
          • 152

          #5
          The C Standard Library has 4 Memory Management Functions, and these are:
          [code=c]
          void *calloc( size_t nmemb, size_t size );
          void free( void *ptr );
          void *malloc( size_t size );
          void *realloc( void *ptr, size_t size );
          [/code]

          You can use the calloc , malloc and realloc functions to dynamically allocate space for objects and then use the free or realloc functions to get rid of that space when you no longer need it.
          You should allocate only what storage you need and to free it as soon as you're done with it; sure it is deallocated at program termination but freeing the space you allocate when you do not need it, provides you more resources and prevents memory leaks which is a common problem.
          The functions work together; mallloc , calloc and realloc return a pointer to the allocated space (if successful) and free and realloc may accept that pointer to deallocate the space it points to; that is made available for further allocation.

          Let's say that you have a Student object defined as:
          [code=c]
          struct Student{
          char *name;
          char *surname;
          /* add more here... */
          };
          [/code]

          To allocate space for a struct Student object you can use this code:
          [code=c]
          struct Student *student = NULL; /*notice the initialization to NULL here! */

          student = ( struct Student * )calloc( 1, sizeof( struct Student ) );

          if ( student == NULL ){
          /* handle memory failure here */
          }

          student->name = NULL;
          student->surname = NULL;

          [/code]

          Notice something:
          calloc allocates space for an array of nmemb objects each of whose size is specified by size and initializes the space to all bits zero.
          malloc allocates space for an object whose size is specified by size and whose value is indeterminate.
          For the example i gave, i could have used this code for the allocation:
          [code=c]
          student = ( struct Student * )malloc( sizeof( struct Student ) );
          [/code]
          Which is equivalent, because i allocate space only for one struct Student object. I used the calloc function to show you something interesting.
          Before moving on to the struct Student example, let me tell you this:
          If you want to allocate space for an array of 3 integers then you will write:
          [code=c]
          arrayOfIntegers = ( int * )calloc( 3, sizeof( int ) );
          [/code]
          But not:
          [code=c]
          arrayOfIntegers = ( int * )calloc( 1, 3 * sizeof( int ) );
          /* or.. */
          arrayOfIntegers = ( int * )malloc( 3 *sizeof( int ) );
          [/code]
          This is not wrong but it might cause some problems when it comes to memory allignment and so on..

          Let's continue with the struct Student example now:
          Another thing to notice is the i typecast the return value of the calloc function to a appropriate type; you should do the same!
          Then notice the if test i make; i do this to test whether i got the space i wanted for my struct Student object or not. Only if i have the space i want can i proceed processing my struct Student object.
          Then comes one interesting thing. As i said above, calloc initializes all bits to zero. However, this need not be the same as the representation of a floating-point zero or a null pointer. So, for maximum portability i must not rely on name and surname attributes being null. So, i set them explicitly to NULL. Why i do that you may ask! It is very good to initialize all your variables before you use them especially the pointers (which you will set to NULL) !! As an example for this, notice that i set student to NULL before i use calloc even though i know that i will later use the calloc function.

          In the beginning i said that it is very important that you have a very good memory management in your program; that is allocate space for what you want and free what you do not want at the time that you do not want it.
          Let me show an example continuing the struct Student example.

          Now that i have my struct Student object i want to set values to it.
          Particularly, i have already read a name and a surname from the user and i want to store them as attributes to the struct Student object. Let's say that the name and surnames i already read are:
          [code=c]
          char *_name = NULL;
          char *_surname = NULL;

          _name = readName(); /* assume there is a readName() function */
          _surname = readSurname(); /* assume there is a readSurname() function */
          /* Notice that these functions will call either malloc or calloc to return a pointer */
          [/code]

          To store them as attributes to the struct Student object you can write:
          [code=c]
          student->name = _name;
          student->surname = _surname;
          [/code]

          Now, the name and surname attributes of the struct Student object will point to the strings pointed to by _name and _surname respectively. However there is one problem here.. Probably, the code for the allocation of the struct Student object would be distinct from the code reading the _surname and _name. The function responsible for the allocation would accept as arguments pointers to the strings that _name and _surname point at to do the initialization at the same time. In this way, however, if the function reading the _name and _surname chooses to free them, the struct Student object will have a serious problem!!
          So it is better to keep things for the struct Student object to itself; the solution to this is to make copies of the _name and _surname and assign them as name and surname attributes respectively.

          One way to do this is:
          [code=c]
          #define MAX_LEN 100
          /* assume that the allocations will succeed; you must check if calloc returns NULL as in the above example */
          student->name = ( char * )calloc( MAX_LEN, sizeof( char ) );
          student->surname = ( char * )calloc( MAX_LEN, sizeof( char ) );

          strcpy( student->name, _name );
          strcpy( student->surname, _surname );
          [/code]


          However, the above code has several drawbacks.
          -> It wastes space; what if the _name string has only 5 characters? Then, surely i wasted a lot of space!!
          -> Since, the function responsible for the allocation does not know about the function responsible for the reading of _name and _surname, then it assumes a max limit of MAX_LEN. What if _name or _surname is larger? Then strcpy will surely cause problems!!

          There is a simple solution to this:
          [code=c]
          size_t len = 0; /* length of _name or _surname */

          /* Again assume that allocations will succeed.... */

          /* Obtain the length of the _name */
          len = strlen( _name );

          /* Allocate as much space as REQUIRED */
          student->name = ( char * )calloc( len + 1, sizeof( char ) ); /* notice that i allocate space for len + 1 to make space for the terminating null character */

          /* Make the copy safely */
          memmove( student->name, _name, len + 1 ); /* copy len + 1 to ensure that the terminating null character is copied; just for maximum portability */

          /* Do the same as above for the _surname */

          len = strlen( _surname );

          ....
          [/code]

          So, we have seen how to allocate space and also that we must be careful about memory management with a simple example of using strlen to determine exactly how much space we want. This is just an example.

          Now let's see hot to free space. This is actually very simple.
          When you do not longer need the struct Student object free it using free (well you can use and realloc but leave it...)
          [code=c]
          free( ( void * )student );
          student = NULL;
          [/code]

          Notice that i assign NULL to student to be completely safe! I advice you to make this a rule!

          But, this code is wrong!!! Not actually wrong, but in a correct memory management aspect yes it is wrong. See this new code and see why:
          [code=c]
          free( ( void * )student->name );
          free( ( void * )student->surname );
          free( ( void * )student );
          student = NULL;
          [/code]

          Well, this is correct. Remember you must free whatever you have allocated. Do not forget anything! There are some techniques that can help you with that... read Code Complete 2 for some examples. Notice that freeing ->name and ->surname must be done before freeing student cause after freeing student the space will no longer be accessible.

          The above is just an example, actually it is very little of how tricky memory management is. I do not describe the realloc function because i do not thnk it will be of any use for you now; you need to work on malloc free and calloc .

          Hope i helped!

          With respect,

          Tassos Souris

          Comment

          • Banfa
            Recognized Expert Expert
            • Feb 2006
            • 9067

            #6
            Originally posted by Tassos Souris
            But not:
            [code=c]
            arrayOfIntegers = ( int * )calloc( 1, 3 * sizeof( int ) );
            /* or.. */
            arrayOfIntegers = ( int * )malloc( 3 *sizeof( int ) );
            [/code]
            This is not wrong but it might cause some problems when it comes to memory allignment and so on..
            I do not think you are correct here, I can not think of any reason not to use memory allocation statements like this and I am absolutely sure that they will not cause memory alignment problems.

            Comment

            • JosAH
              Recognized Expert MVP
              • Mar 2007
              • 11453

              #7
              Originally posted by Banfa
              I do not think you are correct here, I can not think of any reason not to use memory allocation statements like this and I am absolutely sure that they will not cause memory alignment problems.
              Yep true; for a T* tp the following should be true:

              Code:
              T* tp= ...
              char* cp= (char*)tp;
              int n= ...;
              
              if (((char*)(tp+n)) == (cp+n*sizeof(T))) puts("true")
              kind regards,

              Jos

              Comment

              • Tassos Souris
                New Member
                • Aug 2008
                • 152

                #8
                Originally posted by Banfa
                I do not think you are correct here, I can not think of any reason not to use memory allocation statements like this and I am absolutely sure that they will not cause memory alignment problems.
                To quote from Plauger:

                Nor should you assume that the product of the two arguments is all that matters. An implementation can select a storage alignment for the allocated data object based on the size specified by the second argument.
                I interpreted this as i said in my "large" post. Maybe i am wrong... but then what do we need the calloc function? It says allocate space for an array of nmemb objects (...). If this wasn't the case, malloc would be what we only need and we would use as an argument to the malloc function the multiplication of the two calloc arguments. Both functions have their uses.
                Correct me if i am wrong to erase the related text from my "large" post.
                Thank you.

                With respect,
                Tassos Souris

                Comment

                • JosAH
                  Recognized Expert MVP
                  • Mar 2007
                  • 11453

                  #9
                  Originally posted by Tassos Souris
                  I interpreted this as i said in my "large" post. Maybe i am wrong... but then what do we need the calloc function? It says allocate space for an array of nmemb objects (...). If this wasn't the case, malloc would be what we only need and we would use as an argument to the malloc function the multiplication of the two calloc arguments. Both functions have their uses.
                  Calloc may decide to allocate the memory somewhere else from where malloc
                  would've allocated it and, calloc sets every bit of the allocated memory to zero,

                  kind regards,

                  Jos

                  Comment

                  • Banfa
                    Recognized Expert Expert
                    • Feb 2006
                    • 9067

                    #10
                    Nor should you assume that the product of the two arguments is all that matters. An implementation can select a storage alignment for the allocated data object based on the size specified by the second argument.
                    What this means is that

                    assuming some type T

                    calloc(2, sizeof(T));

                    is not equivalent to

                    calloc(sizeof(T ), 2);

                    Because the calloc function uses the size of the 2nd parameter to determine the required alignment for the data block to be allocated. The first case given will be correct because the 2nd argument is sizeof(T) so calloc will return a block with alignment for an object of size sizeof(T). However the second case may not be correct because calloc will return a block with alignment for an object of size 2. However in both cases the product of the 2 parameters is the same.

                    The quote is making the point that it is important to put the object size in the second argument if you call calloc.

                    The first call to calloc will however allocate a block of memory of size 2 * sizeof(T) and aligned for an object of size sizeof(T).

                    You could directly allocate the full size memory block in either of these 2 other ways

                    calloc(1, 2*sizeof(T));
                    malloc(2*sizeof (T));

                    In these cases you get a block of memory of size 2 * sizeof(T) and aligned for an object of size 2 * sizeof(T). A block of memory aligned for an object of size 2 * sizeof(T) should be fine for a block of memory of size sizeof(T). If anything it will be more stringently aligned than is actually required.

                    So

                    calloc(2, sizeof(T));

                    can be replaced by

                    calloc(1, 2*sizeof(T));
                    or
                    malloc(2*sizeof (T));

                    without a problem but must not be replaced with

                    calloc(sizeof(T ), 2);


                    As to your point about the pointlessness of calloc you are right their is not much point to that function. I have seen several implementations where calloc just calls malloc and then memset and most of the projects I have worked on that used heap memory tended to use malloc exclusively.

                    Comment

                    • Tassos Souris
                      New Member
                      • Aug 2008
                      • 152

                      #11
                      OK, thank's for that information!!

                      Comment

                      Working...