Thread: Another question about dynamic allocation

  1. #16
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Where did I make that claim?

  2. #17
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Barney McGrew View Post
    Where did I make that claim?
    ?

    I'm sorry, that is the entire basis of the discussion. You want to explicitly initialize pointers to NULL, because you think that somehow makes a difference from zero.

  3. #18
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Eh, you are the one who claim that: *P = NULL is different from *p = 0 or *p = (void*)0.
    void *p = NULL;
    void *p = 0;
    These two statements have the same effect. I never once claimed they didn't. Have you looked at both the footnote in 7.22.3.2 and the link I gave you earlier?

  4. #19
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Barney McGrew View Post
    void *p = NULL;
    void *p = 0;
    These two statements have the same effect. I never once claimed they didn't.
    Of course you did! You want to use: malloc(some stuct size) then explicitly set each each member to NULL, calloc sets the entire memory region to 0.

  5. #20
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Subsonics
    I'm sorry, that is the entire basis of the discussion. You want to explicitly initialize pointers to NULL, because you think that somehow makes a difference from zero.
    From what I see, Barney McGrew is not confused about that. The problem is that you want to initialise the pointers to all bits zero using calloc, because you think that somehow is always equivalent to the representation of a null pointer

    I was looking for a refutation of your suggestion to use calloc, but I see that Barney McGrew has already referred to "the footnote referenced in 7.22.3.2 of the standard". This presumably refers to C11, because in C99 that footnote is number 252 referenced in clause 7.20.3.1.

    EDIT:
    Okay, instead of just referring to it, let's just cite it:
    Note that this need not be the same as the representation of floating-point zero or a null pointer constant.
    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. #21
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Of course you did!
    You're wrong.

    Have you looked at both the footnote in 7.22.3.2 and the link I gave you earlier?

    EDIT:
    @laserlight:

    This presumably refers to C11, because in C99 that footnote is number 252 referenced in clause 7.20.3.1.
    Oh, I didn't realise that. Good catch.
    Last edited by Barney McGrew; 03-27-2013 at 09:50 AM.

  7. #22
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by laserlight View Post
    From what I see, Barney McGrew is not confused about that. The problem is that you want to initialise the pointers to all bits zero using calloc, because you think that somehow is always equivalent to the representation of a null pointer
    In that case it's only because 0 does not necessary have to be 'all bits zero' no?

    Quote Originally Posted by laserlight View Post
    I was looking for a refutation of your suggestion to use calloc, but I see that Barney McGrew has already referred to "the footnote referenced in 7.22.3.2 of the standard". This presumably refers to C11, because in C99 that footnote is number 252 referenced in clause 7.20.3.1.

    EDIT:
    Okay, instead of just referring to it, let's just cite it:
    Well exactly, there was no section 7.22.3.2 where ever I looked.

  8. #23
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Subsonics
    In that case it's only because 0 does not necessary have to be 'all bits zero' no?
    I think it does: as an unsigned integer, that would be the representation. All three signed integer representations allowed by the standard are such that 0 has all bits zero (I don't think negative zero applies here). On the other hand, the representation of a null pointer (or possible null pointer constants) is left to the implementation without such a constraint.
    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. #24
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by laserlight View Post
    On the other hand, the representation of a null pointer (or possible null pointer constants) is left to the implementation without such a constraint.
    See, that's what I don't get. If you assign NULL to a pointer, and NULL is 0 or (void*)0, then the only way the value the pointer would get by being initialized to 'all bits zero' could be different, is if somehow 0 is not 'all bits zero'. Which is why the distinction from a floating point zero also makes sense no?
    Last edited by Subsonics; 03-27-2013 at 10:20 AM.

  10. #25
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Subsonics
    If you assign NULL to a pointer, and NULL is 0 or (void*)0, then the only way the value the pointer would get by being initialized to 'all bits zero' would be different, is if somehow 0 is not 'all bits zero'.
    If NULL is 0, and a null pointer's internal representation is not all bits zero, then the compiler could just translate it as such when it sees that NULL is assigned to or used to initialise a pointer. If the representation of (void*)0 is not all bits zero, then the compiler can translate the result of the cast to be whatever the representation of the null pointer constant should be.

    Quote Originally Posted by Subsonics
    Which is why the distinction from a floating point zero also makes sense no?
    Consider (double)0. If the representation of 0.0 is not all bits zero, then (double)0 could well have a representation that is not all bits zero. But how is that possible when 0 is all bits zero?
    Last edited by laserlight; 03-27-2013 at 10:26 AM.
    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

  11. #26
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by laserlight View Post
    If NULL is 0, and a null pointer's internal representation is not all bits zero, then the compiler could just translate it as such when it sees that NULL is assigned to or used to initialise a pointer. If the representation of (void*)0 is not all bits zero, then the compiler can translate the result of the cast to be whatever the representation of the null pointer constant should be.
    Well that's subtle, especially since the value of NULL is required to be 0. It would be interesting to know of one practical example of this on this side of the seventies, and the rationale for leaving it in the standard.

    Quote Originally Posted by laserlight View Post
    Consider (double)0. If the representation of 0.0 is not all bits zero, then (double)0 could well have a representation that is not all bits zero. But how is that possible when 0 is all bits zero?
    I was thinking of how IEEE 754 is not a standard requirement and how in theory an integer could also be represented differently but per post #23 that isn't allowed apparently.

  12. #27
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    It would be interesting to know of one practical example of this on this side of the seventies, and the rationale for leaving it in the standard.

    Well, like I said, that link I gave you explains this topic thoroughly: Question 5.17


  13. #28
    Registered User
    Join Date
    Mar 2013
    Posts
    31
    Hi again guys,

    Thanks for the interesting discussion. I have a follow up question.

    I'm using a modified version of the allocation function in the OP shown below. Sorry in advance for any weird indentations. The post box seems to hate my properly indented code (being pasted from a linux VM) and fixing it requires modifiying every line. Hopefully it's not too difficult to parse.

    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));
        conn->db->numrows = numrows;
        conn->db->stringsize = stringsize;    
        if(!conn->db) die("Memory error");
    
    
        //Allocate memory for a set of Address 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 = malloc(sizeof(char)*stringsize);
            printf("The pointer to name is %p\n",conn->db->rows[i].name);
            if(!conn->db->rows[i].name) die("Memory error in name field creation");
            
            conn->db->rows[i].email = malloc(sizeof(char)*stringsize);
            printf("The pointer to email is %p\n",conn->db->rows[i].email);
            if(!conn->db->rows[i].email) die("Memory error in email field creation");
            
            conn->db->rows[i].id = i;
            conn->db->rows[i].set = 0;
        } 
    
    
        if(mode == 'c') {
            conn->file = fopen(filename, "w");
        } else {
            conn->file = fopen(filename, "r+");
    
    
            if(conn->file) {
                Database_load(conn);
            }
        }
    
    
        if(!conn->file) die("Failed to open the file");
    
    
        return conn;
    }
    For the purposes of my question, we're not interested in the branch that calls Database_load. Assume that the function is always being called with "c" being the active case.

    Database_open is called from the following main:

    Code:
    int main(int argc, char *argv[])
    {
        if(argc < 3) die("USAGE: ex17 <dbfile> <action> [action params]");
    
    
        //Test constants
        int numrows = 5;
        int stringsize = 5;
    
    
        char *filename = argv[1];
        char action = argv[2][0];
        struct Connection *conn = Database_open(filename, action, numrows, stringsize);
        int id = 0;
    
    
        if(argc > 3) id = atoi(argv[3]);
        if(id >= numrows) die("There's not that many records.");
    
    
        switch(action) {
            case 'c':
                Database_create(conn);
                Database_write(conn);
                break;
    
    
            case 'g':
                if(argc != 4) die("Need an id to get");
    
    
                Database_get(conn, id);
                break;
    
    
            case 's':
                if(argc != 6) die("Need id, name, email to set");
    
    
                Database_set(conn, id, argv[4], argv[5]);
                Database_write(conn);
                break;
    
    
            case 'd':
                if(argc != 4) die("Need id to delete");
    
    
                Database_delete(conn, id);
                Database_write(conn);
                break;
    
    
            case 'l':
                Database_list(conn);
                break;
            default:
                die("Invalid action, only: c=create, g=get, s=set, d=del, l=list");
        }
    
    
        Database_close(conn);
        return 0;
    }
    I'm always calling this with the "c" argument. Now, for the source of the problem, the Database_write function:

    Code:
    void Database_write(struct Connection *conn)
    {
        rewind(conn->file);
    
        int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
        if(rc != 1) die("Failed to write db to database.\n");
    
    
        int sc = fwrite(conn->db->rows, sizeof(struct Address)*conn->db->numrows,1,conn->file);
        if(sc !=1) die("Failed to write rows to database.\n");
    
    
        int i =0;
        for(i = 0; conn->db->numrows; i++){
            printf("Name addr:\t%p\n",conn->db->rows[i].name);
            printf("Email addr:\t%p\n",conn->db->rows[i].email);
            
    /*
            int rowname = fwrite(conn->db->rows[i].name, (sizeof(char*)*(conn->db->stringsize)), 1, conn->file);
            if(rowname != 1) die("Failed to write name row");
            int rowemail = fwrite(conn->db->rows[i].email, (sizeof(char*)*(conn->db->stringsize)), 1, conn->file);
            if(rowemail != 1) die("Failed to write email row");
    */
        }
    
    
        rc = fflush(conn->file);
        if(rc == -1) die("Cannot flush database.");
    }
    I've replaced the functional code with print statements to see what was going on, because I was getting a segfault and it seemed that each fwrite operation was seeing the "conn->db->rows[i].email/name" pointer as being null.

    When I run it with functional code active and valgrind I get a segfault and the notification that address 0x0 is not stack'd malloc'd or recently freed.

    When I run it with print codes active, it goes into an infinite loop printing "Name addr: (nil)" etc.

    Now, the truly confusing thing. In an earlier stage of development, I ran the main code without calling any of the switch stuff (commented out), it just went straight from Database_open to Database_close (shown below).

    Code:
    void Database_close(struct Connection *conn)
    {
        int i = 0;
        if(conn) {
            if(conn->file) fclose(conn->file);
            if(conn->db->rows){
                for(i=0;i<conn->db->numrows;i++){
                    if(conn->db->rows[i].name) free(conn->db->rows[i].name);
                    if(conn->db->rows[i].email) free(conn->db->rows[i].email);
                }
                free(conn->db->rows);
            }        
            if(conn->db) free(conn->db);
            free(conn);
        }
    }
    Database_close had absolutely no trouble freeing the allocated memory, which would imply to me that it wasn't seeing nil pointers. So what does the write function see nil pointers (how is nil different from null).

    Sorry for the big code bomb, does anyone have any insight as to why I'm getting segfault errors?
    Last edited by AAnderson; 03-28-2013 at 06:00 PM.

  14. #29
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Look at line 14 in your third code snippet. What condition must be true for the body of the for statement to be performed?
    Last edited by Barney McGrew; 03-28-2013 at 06:30 PM.

  15. #30
    Registered User
    Join Date
    Mar 2013
    Posts
    31
    *Bangs head

    I can't believe I missed that, funny how we see what we want to see! Unfortunately the function still sees null pointers.

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