Thread: Another question about dynamic allocation

  1. #1
    Registered User
    Join Date
    Mar 2013
    Posts
    31

    Another question about dynamic allocation

    Hi all,

    I'm working my through Zed Shaw's "Learn C the Hard Way" online book, currently at exercise 17 (link for those interested).

    Anyway, I've been scratching my head over the problem of allocating memory for a series of nested structs which contain dynamically sized members. To clarify, I have the following two structs:
    Code:
    struct Address {
    int id;
    int set;
    char *name;
    char *email;
    };
    Code:
    struct Database {
    int numrows; int stringsize;
    struct Address *rows;
    };
    The user will be required to enter values for the number of row entries and string size, where each row corresponds to an "Address" struct and string size indicates the size of the name and email fields of each Address struct.

    I've come up with the following function for allocating memory in a dynamic fashion. Note that "die" is a function utilising the errno functions to print and exit if something goes wrong.

    Code:
    struct Connection *Database_open(const char *filename, char mode, int numrows, int stringsize)
    {
        struct Connection *conn = malloc(sizeof(struct Connection));
        if(!conn) die("Memory error");
    
    
        conn->db = malloc(sizeof(struct Database));
        if(!conn->db) die("Memory error");
    
    
        //Allocate memory for a set of row pointers
        conn->db->rows = malloc(sizeof(struct Address*)*numrows);
        if(!conn->db->rows) die("Memory error in row creation");
    
    
        //Allocate the memory for each string field of the each Address struct and
        //assign.
        int i = 0;
        for(i = 0; i < numrows; i++){
            conn->db->rows[i].name = (char*)malloc(sizeof(char)*stringsize);
            if(!conn->db->rows[i].name) die("Memory error in name field creation");
            conn->db->rows[i].email = (char*)malloc(sizeof(char)*stringsize);
            if(!conn->db->rows[i].email) die("Memory error in email field creation");
        }  
    
    
        ... //irrelevant code
    
    
        return conn;
    }
    It compiles, but it feels wrong. Can anyone suggest a simpler method of allocating the required space and still allowing the Address structs to be indexed through?

    I've been wrestling with this for a couple of days it feels like I'm missing something simple.

    Your help is much appreciated.

  2. #2
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Looks good to me.
    I'd just remove the casts to char * on the malloc() calls;
    Also the non pointer members of your structs could be initialized in that function.
    Kurt

  3. #3
    Registered User
    Join Date
    Mar 2013
    Posts
    31
    Ok, thanks!

    Stylistically, would you suggest any modifications?

  4. #4
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    I'm working my through Zed Shaw's "Learn C the Hard Way" online book
    That title's actually quite accurate, considering that stacks and heaps have nothing to do with C.

    It compiles, but it feels wrong. Can anyone suggest a simpler method of allocating the required space and still allowing the Address structs to be indexed through?
    Ideone.com | Online C Compiler & Debugging Tool

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    505
    Quote Originally Posted by AAnderson View Post
    Ok, thanks!

    Stylistically, would you suggest any modifications?
    When you allocate a structure which contins a pointer, set all the pointer fields to zero the first thing after malloc() returns.

    Then write a kill function or destructor to match your allocator.

    In the kill fuction, make sure you don't iterate over any null pointers (calling free on them is harmless, but easy to avoid).

    Then the code is far neater. You allocate everythign in one fucntion, free it in another, and if you get an error, you kill the entire partly-constructed object, and return an error. You then die or take some other action in a top-level function.
    I'm the author of MiniBasic: How to write a script interpreter and Basic Algorithms
    Visit my website for lots of associated C programming resources.
    https://github.com/MalcolmMcLean


  6. #6
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Malcolm McLean View Post
    When you allocate a structure which contins a pointer, set all the pointer fields to zero the first thing after malloc() returns.
    Or use calloc.

  7. #7
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Or use calloc.
    calloc sets all the bits of the space it allocates to zero. A null pointer needn't have such a representation.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

  9. #9
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Now i'm not quite certain about this, since i'm not a C veteran by any stretch of the imagination, and since nobody seems to think it's wrong, but this line:

    Code:
    conn->db->rows = malloc(sizeof(struct Address*)*numrows);
    Allocates space for a certain number of pointers, what you want is space for a certain numbers of Address structs, so you should remove the asterisk after Address, otherwise you will get less memory than you need, and run into segmentation faults later on.
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  10. #10
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
    With a regular assignment, for instance, you may have something like this: void *a = 0;

    In this case 0, a null pointer constant described in your post, is converted to a null pointer of the type 'void *' and stored in a. The internal representation of that value needn't have all its bits set to zero. You'll find this is mentioned in the footnote referenced in 7.22.3.2 of the standard. If you have the interest, further information on the topic can be read here: Null Pointers

  11. #11
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Barney McGrew View Post
    With a regular assignment, for instance, you may have something like this: void *a = 0;

    In this case 0, a null pointer constant described in your post, is converted to a null pointer of the type 'void *' and stored in a.
    No. My post is directly taken from the C standard. It's been the same since ansi C, so you need to go back pre standard C to find any substance to what you are talking about.

    NULL is either

    0

    or

    (void*)0

    http://www.busybox.net/~landley/c99-draft.html#6.3.2.3
    Last edited by Subsonics; 03-27-2013 at 08:54 AM.

  12. #12
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Yes, your quote is correct, but it's irrelevant here. The NULL expression is *converted* to a null pointer which has an implementation-defined representation.

    EDIT: For instance, this will store a null pointer in a: void *a = 0;

    And this may not: void *a; memset(&a, 0, sizeof a);
    Last edited by Barney McGrew; 03-27-2013 at 09:01 AM.

  13. #13
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Barney McGrew View Post
    Yes, your quote is correct, but it's irrelevant here. The NULL expression is *converted* to a null pointer which has an implementation-defined representation.
    The value is 0 since the NULL pointer is either 0 or (void*)0.

    Assigning *p = 0, or *p = (void*)0 is equivalent to NULL. calloc in this case will set it to 0.

    Some public backup:

    http://stackoverflow.com/questions/7...ter-in-c-and-c

  14. #14
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    You're confusing NULL with "null pointer". Have you looked at both the footnote in 7.22.3.2 and the link I gave you earlier?

  15. #15
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Barney McGrew View Post
    You're confusing NULL with "null pointer".
    Eh, you are the one who claim that: *P = NULL is different from *p = 0 or *p = (void*)0. Well, let's go back and look what value the NULL pointer constant has then because that is the value that *p will get.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Question about dynamic memory allocation
    By dayanike in forum C Programming
    Replies: 2
    Last Post: 12-11-2012, 08:35 AM
  2. Dynamic Memory Allocation Question
    By somniferium in forum C Programming
    Replies: 6
    Last Post: 10-12-2012, 07:51 PM
  3. A possibly foolish question about dynamic allocation.
    By manasij7479 in forum C++ Programming
    Replies: 4
    Last Post: 08-24-2011, 06:09 PM
  4. Dynamic Memory Allocation Question
    By Piknosh in forum C++ Programming
    Replies: 1
    Last Post: 04-14-2004, 01:55 PM
  5. dynamic allocation question
    By vale in forum C++ Programming
    Replies: 1
    Last Post: 08-26-2001, 04:23 PM