6

I have the following struct:

 struct node {
    int data;
    struct node *next;
};


struct node *n1 = malloc(sizeof(struct node));

I am not sure how initialize all the pointer fields of struct pointer to NULL without causing any potential for memory leaks?

Tom
  • 61
  • 1
  • 1
  • 2
  • 6
    By using `calloc` instead of `malloc`. – Weather Vane Jan 23 '16 at 01:11
  • 2
    What's wrong with `n1->next = NULL;` ? – Crowman Jan 23 '16 at 01:11
  • 1
    @WeatherVane: that will work with current processors, but it is not strictly correct. – chqrlie Jan 23 '16 at 01:18
  • 2
    If you don't like calloc, you can follow your malloc call with a memset, which would accomplish the same thing. – bruceg Jan 23 '16 at 01:18
  • @chqrlie I am sure I have read in these very pages, that `NULL` always evaluates to `0`. Are you saying we should code for tomorrow's processors? – Weather Vane Jan 23 '16 at 01:22
  • 1
    @WeatherVane: this is a tricky one: it has value `0` in the sense that `NULL` == 0 is true, but its representation might not be *all bits zero*. I don't know of any CPU where it is not, but the Standard allows it. – chqrlie Jan 23 '16 at 01:25
  • @WeatherVane Can I use calloc first instead of malloc? – Tom Jan 23 '16 at 01:26
  • @Tom yes you can. `calloc` initializes the whole structure to all bits `0`. `data` will be `0`, `next` will be null on all CPUs I know of. – chqrlie Jan 23 '16 at 01:28
  • @chqrlie going a bit off-topic now, but should code intended for a typical contemporary computer also allow 9-bit bytes and EBCDIC character coding to be transparent? – Weather Vane Jan 23 '16 at 01:29
  • @WeatherVane: in my humble opinion, we should ditch a lot of obsolete stuff from the C Standard, among which all the above and quite a few more (padding bits, non 2s complement, implementation defined signed right shift, char signed by default, non mandatory 8, 16, 32 and 64 bit types...), but there are many DSPs out there that have non 8-bit bytes and a few purists who insist on keeping all options open. – chqrlie Jan 23 '16 at 01:40
  • @chqrlie Many of those things remain completely relevant when you take into account that embedded processors (which are targeted by C) as old as the Z80 remain in modern production and are widely used. – David Hoelzer Jan 23 '16 at 01:42
  • @DavidHoelzer: the Z80 has none of these shortcomings. – chqrlie Jan 23 '16 at 01:43
  • @chqrlie I think you're missing my point. For example, have a look at Intel's Intel 64 and IA-32 architecture manual 2A in section 16.3.2 on the Intel MPX: "The upper bounds are architecturally represented in 1's complement form." I don't think you'd disagree that this is a modern processor. One's complement is used in network communications and other IO mechanisms quite commonly. – David Hoelzer Jan 23 '16 at 01:57
  • @DavidHoelzer: I'm afraid *The upper bounds are architecturally represented in 1's complement form.* does not refer to a representation of negative numbers, but that of maximum values for an offset. Same remark for network communications: sign magnitude may be used, I've never seen 1's complement. – chqrlie Jan 23 '16 at 02:05
  • @WeatherVane you probably misread. `NULL` may be various things. `(void *)0` is the most common definition of it. – M.M Jan 25 '16 at 02:30
  • @chqrlie I think it is useful to allow address zero to be a valid address, on systems that only have a small amount of memory. – M.M Jan 25 '16 at 02:31
  • @M.M: of course! but `NULL` may still be all bits zero and point to that, it just happens to be writeable of such systems, and should not be used for anything that is compared to `NULL`. – chqrlie Jan 25 '16 at 02:34
  • @chqrlie you have to jump through hoops though (e.g. `char *ptr = (char *)1; --ptr;`). Trying to dereference a null pointer causes undefined behaviour. Before you say "the compiler for the system could define dereferencing null", the *last* thing we need is constraints that must be hardcoded into the compiler. It's horrible getting a hardware kit for embedded system and you are forced to use the crappy compiler they bundled with it and is full of bugs. We want to use a standard-compliant compiler and be able to update the compiler regularly. – M.M Jan 25 '16 at 02:36
  • @M.M `NULL` has to be represented by *some* value. Here is one [reference of my comment](http://stackoverflow.com/questions/16124397/why-null-is-not-predefined-by-the-compiler/16125085#16125085). As with the `double` representation for `0` being encoded as a "special" value, in both cases, this suits the blanket zeroing of memory. – Weather Vane Jan 25 '16 at 10:03
  • @WeatherVane `NULL` is a preprocessor macro, it's not represented by anything. Maybe you mean that the null pointer has to have some representation? If so, what's your point? The null pointer representation might not be all bits zero. – M.M Jan 25 '16 at 10:05
  • @M.M, my point was that I didn't misread anything. The anwser I linked says what I wrote, but additionally that the `NULL` pointer might not be `0` at machine level. So (apart from crappy compilers) if the machine doesn't use `0` as the `NULL` pointer, that's dealt with by the compiler, not by any hoops you have to go through to manipulate the pointer – Weather Vane Jan 25 '16 at 10:10
  • `calloc` bypasses that "dealing with" however (which is the point of this comment discussion) – M.M Jan 25 '16 at 10:31

2 Answers2

7

You need to initialize the members of the structure after you allocate it with malloc:

struct node {
    int data;
    struct node *next;
};

struct node *n1 = malloc(sizeof(struct node));
n1->data = 0;
n1->next = NULL;

If you want to initialize your structure in one step with default values, which can be handy if it is much larger, use a static structure with these defaut values:

struct node def_node = { 0, NULL };

struct node *n1 = malloc(sizeof(struct node));
*n1 = def_node;

Alternately, you can use the C99 syntax:

struct node *n1 = malloc(sizeof(struct node));
*n1 = (struct node){ 0, NULL };

As commented by Leushenko, you can shorten the initializer to { 0 } for any structure to initialize all members to the appropriate zero for their type:

struct node *n1 = malloc(sizeof(struct node));
*n1 = (struct node){ 0 };
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • I was looking for a way to make the entire n1 NULL. For example : n1= {0,NULL}; I dont want to go variable by variable. I want to set all of n1 to NULL at once. – Tom Jan 23 '16 at 01:26
  • 1
    The advantage of this is that any fields you leave out of the struct you use to initialize the value will be automatically set to the appropriate zero value for that type, so this is very maintainable: just write one field (can't have an empty literal), and the others will take care of themselves. – Alex Celeste Jan 23 '16 at 01:36
4

You have four choices:

1) Set the pointers manually, e.g. node-> next = NULL;

2) Use calloc() to zero out the memory when you allocate it

3) Use memset() to zero out the memory after you've allocated it.

... OR ...

4) Don't worry about explicit initialization until you actually need to use the struct. Design your program such that you make sure any pointer is assigned before you try to read it.

FYI, this is one of the main purposes of a "constructor" in OO languages like C++ or C#: to initialize "class invariants".

PS:

5) I forgot about C99 struct initialization, which Leushenko mentioned:

what is the difference between struct {0} and memset 0

struct A
{
    int x;
    int y;
};
...
A a = {0};

This is vastly preferred to either calloc() or memset().

It also applies to other initialization values besides "0":

C99 Standard 6.7.8.21

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

Community
  • 1
  • 1
paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Someone is going to come here and say that `calloc()` and `memset()` are not guaranteed to set pointers to NULL, which is technically true, but to them, I preemptively say that systems where it doesn't work are so impossibly rare that we simply don't care about them. – Dietrich Epp Jan 23 '16 at 01:26
  • @Dietrich Epp: you're absolutely correct. These links explain further: http://c-faq.com/null/, http://stackoverflow.com/questions/9894013/is-null-always-zero-in-c. You're also correct that calloc() and memset() are OK in just about every imaginable circumstance. The main reason one *wouldn't* use them is "performance" - the (miniscule!) overhead of assigning memory whether actually need to or not. – paulsm4 Jan 23 '16 at 01:28
  • @DietrichEpp: I already did in comments above, but agree it is a moot point. Thank you paulsm4 for the link. – chqrlie Jan 23 '16 at 01:34
  • A better reason to not use them is because it's inelegant to use a function over `void *` when the language provides primitive builtins that do the same job. For non-arrays, there's literally *no* reason to ever use `calloc`. – Alex Celeste Jan 23 '16 at 01:38