-2

Why aren't the struct pointers initialized to NULL using the following code

code

#include <stdio.h>
#include <stdlib.h>

struct list_el
{
    int val;
    struct list_el * right, * left, *parent;
}item_default={0,NULL,NULL,NULL}; //Default values
typedef struct list_el node;

int main(int argc, char const *argv[])
{
    node * new_node = (node*) malloc (sizeof(node));
    (new_node == NULL) ? printf("0\n") : printf("1\n");
    (new_node->parent == NULL) ? printf("0\n") : printf("1\n");
    (new_node->right == NULL) ? printf("0\n") : printf("1\n");
    (new_node->left == NULL) ? printf("0\n") : printf("1\n");
    (new_node->val == 0) ? printf("0\n") : printf("1\n");
    return 0;
}

Output

1 1 1 1 0

Is it some issue regarding the pointer initialisation syntax?

Aerron
  • 310
  • 1
  • 12
  • 1
    `new_node` is pointing to a freshly allocated memory block with indeterminate contents. You're *never* setting any values there. The struct declaration is coupled with creation of **another** object named `item_default` that *is* zero-initialized. – Antti Haapala -- Слава Україні Sep 01 '17 at 19:22
  • 1
    C doesn't have any sort of constructor, so just because you declared one instance and initialized the values doesn't mean any other instance will do the same. Try using calloc instead. – Retired Ninja Sep 01 '17 at 19:23
  • Even calloc is not guaranteed to initialize *pointers* to NULL (though often it will). – Antti Haapala -- Слава Україні Sep 01 '17 at 19:23
  • `struct list_el{ /*...*/ }item_default={0,NULL,NULL,NULL}; //Default values` does not provide default values for the struct, it initializes a global variable of type `struct list_el` with name `item_default` to those values. – clcto Sep 01 '17 at 19:24
  • You need a good C book. Use `calloc` instead and your problems will go away – 0___________ Sep 01 '17 at 19:30
  • 1
    @PeterJ_01 Note that `calloc` is not 100% safe here. `calloc` fills the memory with zeros. `NULL` is not necessarily 0. – Schwern Sep 01 '17 at 20:08
  • @Schwern unfortunately is as the current standard, or as I interpret it (and any known be me implementations - I know quite a lot C compilers on many platforms) – 0___________ Sep 01 '17 at 20:10

2 Answers2

1
struct list_el
{
    int val;
    struct list_el * right, * left, *parent;
}item_default={0,NULL,NULL,NULL}; //Default values

This does not do what you think it does. You've basically written...

typename typedefinition variable = initial_value;

You've declared the type struct list_el, defined it as { int val; struct list_el * right, * left, *parent; }, declared a new variable of that type called item_default, and assigned it the value {0,NULL,NULL,NULL}.

Aside from the type definition, this is basically int foo = 0.

We can test that by printing out the parts of item_default.

int main(int argc, char const *argv[])
{
    printf("%d\n", item_default.val);
    printf("%p\n", item_default.right);
    printf("%p\n", item_default.left);
    printf("%p\n", item_default.parent);
    return 0;
}

And these will be 0, 0x0 (ie. NULL), 0x0, 0x0.


Unfortunately, C has no defaults for types. You always must initialize them. When working with structs, this typically means writing new and destroy functions so initialization and cleanup happens consistently.

// Declare the type and typedef in one go.
// I've changed the name from node to Node_t to avoid clashing
// with variable names.
typedef struct node
{
    int val;
    struct node *right, *left, *parent;
} Node_t;

// Any functions for working with the struct should be prefixed
// with the struct's name for clarity.
Node_t *Node_new() {
    Node_t *node = malloc(sizeof(Node_t));

    node->val = 0;
    node->right  = NULL;
    node->left   = NULL;
    node->parent = NULL;

    return node;
}

int main() {
    Node_t *node = Node_new();

    printf("%d\n", node->val);
    printf("%p\n", node->right);
    // and so on

    return 0;
}

Note that I did not use calloc. calloc fills the memory with zeros, but the machine's representation of a null pointer is not necessarily zero. Using NULL and 0 are safe, the compiler can do the translation from context, but calloc doesn't know what you're going to do with the memory its zeroing. It's a relatively minor portability concern that's probably more of a problem these days for embedded systems.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • If you are using C99 you can also use the `*node=(Node_t){.val = 0, .right = NULL, .left = NULL, .parent = NULL};` shorter syntax (see https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html) – Picaud Vincent Sep 01 '17 at 19:54
  • `struct $ { }{defaultvalues};` So hey are you sure there isn't any convention of this type ? – Aerron Sep 01 '17 at 19:54
  • @Aerron There could be any number of compiler extensions, but AFAIK standard C does not have default type initialization. `malloc` doesn't even know what type its initializing, it's just knows how much memory to allocate and hands you back a pointer to a block of allocated memory of the requested size. That block contains whatever garbage was in that hunk of memory. You're working in a language written to maximize the anemic resources available 45 years ago, not to be convenient. – Schwern Sep 01 '17 at 19:59
  • `node * new_node = (node*) malloc (sizeof(node)); *new_node = (node){.val = 0, .right = NULL, .left = NULL, .parent = NULL};` This might be good! – Aerron Sep 01 '17 at 20:03
  • 1
    @Aerron Yes, that is the same thing but more compact. Being compact is not necessarily a good thing for readability, YMMV. But [do not typecast malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc#605858). – Schwern Sep 01 '17 at 20:04
  • 1
    I was about to ask about the typecast. Thanks @Schwern – Aerron Sep 01 '17 at 20:09
0

Structure is a data type, you don't give default values to data types. What you're doing is like give an int the default of 3. What you want is give an instance of your struct a default value, but that is not possible in C.

You could have a function to help you with that:



    void init_struct(node* nd) {
      if (nd != NULL) {
        nd->val = 0;
        nd->parent = nd->right = nd->left = NULL;
      }
    }


savram
  • 500
  • 4
  • 18