1. ## 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;
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
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.

2. 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. Ok, thanks!

Stylistically, would you suggest any modifications?

4. 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. Originally Posted by AAnderson
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.

6. Originally Posted by Malcolm McLean
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. 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. An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

9. 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.

10. 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. Originally Posted by Barney McGrew
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

12. 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);

13. Originally Posted by Barney McGrew
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. 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. Originally Posted by Barney McGrew
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.