Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't understand how tsearch return pointers work

I've been trying to figure out how the tsearch library works and I've reached a point where I am completely stumped. Here is my code:

#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <dirent.h>
#include <utime.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <signal.h>
#include <ctype.h>
#include <search.h>

int compare (const void *a, const void *b);
void action(const void *nodep, VISIT value, int level);

struct word {
    char word[100];
    int occur;          
};

int main (void) {
    void *root = NULL;
    char *words[] = {"a","b","c","a"};
    struct word *entry = malloc(10 * sizeof(struct word));  
    struct word *ptr;
    struct word *ptr2;
    int i;  

    for (i=0;i<4;i++) {
        memcpy(entry[i].word,words[i],100);
        entry[i].occur = 1;                 
        ptr = tfind(&entry[i],&root,compare);
        if (ptr == NULL) {          
            tsearch(&entry[i],&root,compare);
        }
        else {              
            printf("%i\n",ptr->occur);
            printf("%i\n",entry[0].occur);          
            entry[0].occur++;           
        }
    }
    twalk (root, action);   
    //tdestroy (&rootp,freefct);
    return 0;
}

int compare (const void *a, const void *b) {
    const struct word *w1, *w2;

    w1 = (const struct word *) a;
    w2 = (const struct word *) b;

    return strcmp(w1->word, w2->word);
}

void action(const void *nodep, VISIT value, int level) {
    struct word *w = *((struct word **) nodep);
    switch (value) {
    case leaf:
    case postorder:
        printf("%s: %i\n",w->word, w->occur);
        break;
    default:
        break;
    }
    return;
}

Now, I would think that ptr should point to entry[0] (because that is where the value it found is) and ptr->occur should give me the occur value for "a". But it doesn't. It gives me 0, as seen below in the results:

0 1 a: 2 b: 1 c: 1

Changing the value of entry[0] does change what it prints during the walk.

I have tried every combination of dereferencing or casting ptr I can think of, declaring it as void* or as struct word*...

So my question basically is:

Given a return from tfind (and what should that be declared as), how do I access the values within the struct?

like image 965
HamHamJ Avatar asked May 11 '26 09:05

HamHamJ


1 Answers

The return value from tfind is NOT the entry, it's a pointer to the tree-internal node structure whose first element is a pointer to the entry. As the node structure is opaque, you can think of ptr as a struct word **.

If you rewrite your else part to

    else {
        printf("i=%d ptr=%p *ptr=%p entry=%p,%p,%p,%p\n", i, ptr, *(struct word **)ptr, entry, entry+1, entry+2, entry+3);
        printf("wrong: %i\n",ptr->occur);
        printf("right: %i\n",(*(struct word **)ptr)->occur);
        printf("right: %i\n",entry[0].occur);
        entry[0].occur++;
    }

you'll get (on my machine at least)

i=3 ptr=0x8f32430 *ptr=0x8f32010 entry=0x8f32010,0x8f32078,0x8f320e0,0x8f32148
wrong: 0
right: 1
right: 1
a: 2
b: 1
c: 1

As you see, it's not ptr that is pointing to elem[0], but *ptr is.

like image 70
Guntram Blohm Avatar answered May 13 '26 23:05

Guntram Blohm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!