0

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;

}
user3717434
  • 215
  • 4
  • 19
  • What is variable `my`, appearing in `HASH_ADD_STR(*my, s, pb)`? That doesn't look like it's what you want, supposing that the overall code compiles at all. – John Bollinger Jun 15 '17 at 16:20
  • @PaulOgilvie, no it works, it truely adds new s values to the hash table. the problem is with d values. pb is the struct where it returns the searched value if it finds it or returns null if can't find it. – user3717434 Jun 15 '17 at 16:29
  • @JohnBollinger, it was just a type error. i fixed it. it must be myb struct. – user3717434 Jun 15 '17 at 16:30
  • Also, what is variable `f`? Your original code may work, but what you're presenting here, to us, does not appear to do. – John Bollinger Jun 15 '17 at 16:30
  • 1
    It seems that `HASH_FIND_STR(*myb, s, pb)` is a macro that takes the address of the output parameter `pb`. So there seems nothing wrong there. Use a debugger to step through the code? – Paul Ogilvie Jun 15 '17 at 16:38
  • @PaulOgilvie, yeah pb is a pointer to the struct. I check again from uthash manual, i think that part is ok. Problem is in HASH_FIND_INT in the else clause. I stepped with gdb, it goes through `if(pp==null)` clause but somehow HASH_ADD_INT doesn't add the d value – user3717434 Jun 15 '17 at 16:42
  • Overall, your code does not come close to compiling. In addition to apparent typos and incorrect names, there are missing semicolons and malformed declarations. Whatever you have that works, *it is not what you've presented to us*. To the extent that these problems arise from an attempt on your part to keep your question brief, we appreciate it. Sort of. Nevertheless, the numerous errors make it hard for us to analyze the problem. Please present a *bona fide* [mcve]. – John Bollinger Jun 15 '17 at 16:52
  • First show us a compilable, working example and show how you call the functions that demponstrate the problem. Otherwise we can't help you. – Paul Ogilvie Jun 15 '17 at 16:59
  • @JohnBollinger I added full working code. It prints also values so you can see that its not saving values other than first encountered one. – user3717434 Jun 15 '17 at 17:53

1 Answers1

0

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157