user3717434
user3717434

Reputation: 225

uthash: 2 level hash table, adding new elements in the nested table

I have a 2 level hash table as explained here(uthash), with two different struct as declared below. Hash struct b holds total count of s values and their frequency by parameter d in hash struct a(To understand better look at the design below).

update function should work like that: if s is encountered for the first time, adds it to the struct myb and adds also in struct mya. If it's already in struct myb, then checks if it's d value is encountered for the first time, in case adds it to the struct mya, otherwise increments it's value.

However when i run the code, it saves first encountered d value in the hash struct mya (and increment in the case) but i doesnt add other d values received on the same s value... What's wrong in the code?

   d1:3           d2:5    
  /              / 
 s1 - d2:4     s2 - d4:3
  \             \
   d3:1          d5:2

---------------------------
#include <stdio.h> 
#include <string.h>
#include "uthash.h"


struct a{ 
   int x;
   int count;
   UT_hash_handle hh;
};

struct b{ 
   char s[24];
   int total;
   struct a *mya;
   UT_hash_handle hh;
};


void update(struct b **myb, const char *s, u_int32_t d){
  struct b *pb;

  HASH_FIND_STR(*myb, s, pb);
  if(pb == NULL) {
    pb = (struct b*)malloc(sizeof(struct b));
    if(!pb) return;

    strncpy(pb->s, s, sizeof(pb->s));
    pb->total = 1;
    pb->mya = NULL;
    HASH_ADD_STR(*myb, s, pb);


    struct a *pa = (struct a*)malloc(sizeof(struct a));
    if(!pa) return;

    pa->x = d;
    pa->count = 1;
    HASH_ADD_INT(pb->mya, x, pa);
  }
  else{
    struct a *pp=NULL;
    pb->total++;

    HASH_FIND_INT(pb->mya, &d, pp);
    if(pp == NULL){
      pp = (struct a*)malloc(sizeof(struct a));
      if(!pp) return;

      pp->count = 1;
      HASH_ADD_INT(pb->mya, x, pp);
    }
    else pp->count++; 
  }
}


void printAll(struct b *myb){
  struct b *pb, *tmp;
  struct a *pa, *tmp2;
  int i = 0, j = 0;

  HASH_ITER(hh, myb, pb, tmp) {
    i++;
    printf("%d) %s: %u\n", i, pb->s, pb->total);

    HASH_ITER(hh, pb->mya, pa, tmp2) {
      j++;
      printf("\t%d) %u: %u\n", j, pa->x, pa->count);
    }
    j = 0;
  }
}



struct b *myb = NULL;

int main(int argc, char **argv ){

  char str[10][24] = {"abc","abc","def","abc","hij","def","hij","def","abc","hij"};
  int values[10] =    {10,    10,   9,    8,    5,    2,    6,    2,    5,    5};
  int i;

  for(i=0; i<10; i++)
    update(&myb,str[i],values[i]);

  printf("hash table\n");
  printAll(myb);


  return 0;

}

Upvotes: 0

Views: 559

Answers (1)

John Bollinger
John Bollinger

Reputation: 181008

Compare the two branches of the (mostly) working version of your update() function. Look at how you initialize a new struct a in each case. If you're not seeing it yet, then keep in mind what member stores the value that you observe not being recorded.

That's right: when you add a new struct a to an already-existing struct b, you fail to set its x member. That completely explains the problem.

For what it's worth, I'd factor out the code for creating and initializing a new struct a, so that you can eliminate the current duplication. As an added advantage, if the problem had occurred in a function with the specific purpose of allocating and initializing a struct a then it might well have been easier to recognize.

Upvotes: 0

Related Questions