-1

I have the following C program:

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

typedef struct node_t node_t;
    struct node_t
{
    char *name;
    node_t **nodes;
};

node_t* init(int p_n)
{
    node_t *node = malloc(sizeof(node_t));
    node->name = "_ROOT_";
    if(p_n > 0 && p_n < 10)
    {
        node->nodes = malloc(p_n*sizeof(node_t**));
        char nbuffer[9];
        int i;
        for(i = 0; i < p_n; i++)
        {
            node_t *child = malloc(sizeof(node_t));
            sprintf(nbuffer, "NAME %d", i);
            child->name = nbuffer;
            node->nodes[i] = child;
        }
    }
    return node;
}

int main(int argc, char *argv[])
{
    int n = 3;
    node_t *ROOT = init(n);
    printf("%sNODE {name:%s [%lu]}\n",
        "", ROOT->name, sizeof(ROOT->nodes)/sizeof(ROOT->nodes[0])
    );
    assert(n == sizeof(ROOT->nodes)/sizeof(ROOT->nodes[0]));
    free(ROOT);
    return 0;
}

The assertion from the beginning of the main method fails and this is my problem. What I am doing wrong in the evaluation of the length of member nodes?

This post is know by me but from some reason it doesn't work for me. Why?

SK

Community
  • 1
  • 1
Kilátó
  • 403
  • 3
  • 10
  • 19
  • 3
    Because there are no arrays in your code. The `sizeof/sizeof` trick only works on arrays. – Oliver Charlesworth May 03 '14 at 11:31
  • 3
    `child->name = nbuffer;` nbuffer is a local array, each pointer will point to this same memory area (which goes out of scope when the function returns) Also: you fail to initialise the members of the allocated structs. – wildplasser May 03 '14 at 11:34
  • 1
    `malloc(p_n*sizeof(node_t**))` should be `malloc(p_n*sizeof(node_t*))`. On most architectures these will be the same, yet the logic is wrong. – chi May 03 '14 at 11:40
  • OK, I corrected the malloc. But there is no solution for getting the number of elements stored in the nodes member? – Kilátó May 03 '14 at 12:12
  • no, pointers don't have that information available. – Jens Gustedt May 03 '14 at 12:13

1 Answers1

0

Assuming a 32 bit pointer.

The sizeof(ROOT->nodes) is going to be 4 bytes. A pointer to a pointer it still a pointer.

The sizeof(ROOT->nodes[0]) is also going to be 4 bytes. It too is a pointer.

Hence 4/4 != 3 and your assert fails.

I'm not sure what your objective is, but if you're wanting to do something like this with dynamically allocated storage you might do something like the following. It can be extended with additional APIs to add, remove, etc. This solution maintains a count of the number of elements in the list.

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

#define NAME_SIZE 32

typedef struct node_s {
    char *name;
} node_t;

typedef struct node_list_s {
   int     count;
   node_t *nodes;
} node_list_t;

void init(node_list_t *l, int p_n) {
   int i = 0;
   char name[NAME_SIZE];

   if(!l) return;

   memset(l, 0, sizeof(node_list_t));
   l->nodes = malloc(p_n*sizeof(node_t));
   l->count = p_n;

   for(i=0;i<l->count;i++) {
      snprintf(name,sizeof(name),"NAME %d",i);
      l->nodes[i].name = strdup(name);
   }
}

void term(node_list_t *l) {
   int i = 0;
   if(!l) return;
   for(i=0;i<l->count;i++) {
      if(l->nodes[i].name) free(l->nodes[i].name);
   }
   if(l->nodes) free(l->nodes);
}

void print(node_list_t *l) {
   int i = 0;
   if(!l) return;
   for(i=0;i<l->count;i++) {
      printf("%d %s\n", i, l->nodes[i].name ? l->nodes[i].name : "empty" );
   }
}

int main(int argc, char *argv[]) {
    node_list_t list;

    init(&list, 3);
    print(&list);
    term(&list);
    return 0;
}
maha
  • 605
  • 6
  • 13