0

I want to return my struct pointer as a void pointer. In this function when I print the noOfTuples I correctly get zero.

typedef void* HashjoinDatabase;
HashjoinDatabase HashjoinAllocateDatabase(unsigned long totalNumberOfEdgesInTheEnd) {
  HashjoinDatabase db;
  
  struct database* d = malloc(sizeof(struct database));
  if(d == NULL) {
    puts("Some kind of malloc() error");
  }

  d->tuples = malloc(totalNumberOfEdgesInTheEnd * sizeof(struct tuple));
  if(d->tuples == NULL) {
    puts("Some kind of malloc() error");
  }

  d->noOfTuples = 0;
  db = &d;
  printf("Hello %i\n", d->noOfTuples);
  return db;
}

However when in main I cast the returned void pointer back to the struct pointer and try to get the same noOfTuples and I get large varying values with each run which I suspect are addresses

int main() {
  HashjoinDatabase testDB = HashjoinAllocateDatabase(10);
  int no = ((struct database*)testDB)->noOfTuples;
  printf("Hello %i", no);
  return 0;
}
  • 2
    Hiding a struct behind a typedef is one thing, but hiding a *pointer* behind a typedef is a bad idea. Why not just write normal code and return proper pointers-to-types? – Jonathon Reinhart Nov 09 '20 at 08:51
  • Your problem is you're retuning *the address of* the pointer `d` which is a local variable that goes out of scope when the function returns. You want `db = d` or just ` return d`. – Jonathon Reinhart Nov 09 '20 at 08:53
  • "I want to return my struct pointer as a void pointer." Why? 9 times out of 10 this leads to the problem discussed here https://stackoverflow.com/questions/58280538/how-to-verify-if-a-void-pointer-void-is-one-of-two-data-types/58281061#58281061 – Yunnosch Nov 09 '20 at 08:53
  • But really, learn about the difference between declarations and definitions and just return `struct database *`. – Jonathon Reinhart Nov 09 '20 at 08:54
  • See this similar discussion: https://softwareengineering.stackexchange.com/questions/294761/why-use-an-opaque-handle-that-requires-casting-in-a-public-api-rather-than-a-t – Jonathon Reinhart Nov 09 '20 at 08:56
  • This is an assessed exercise, so the typedef actually came with the skeleton code – Ihowa Onaro Nov 09 '20 at 09:07
  • 1
    Find a better course then... :-D – DevSolar Nov 09 '20 at 09:10
  • 1
    Please direct your instructor here so that professionals may explain to him/her why their code is wrong. It is a horrible pattern that exists because some people don't understand the C language. – Jonathon Reinhart Nov 09 '20 at 09:12
  • @IhowaOnaro [edit] and show the skeleton code. – Jabberwocky Nov 09 '20 at 09:26
  • 1
    Hiding a pointer behind a typedef is a bad idea, but hiding a `void*` behind a counter-intuitive name such as `HashjoinDatabase` is especially illogical. – printf Nov 09 '20 at 09:55

2 Answers2

3
struct database* d = malloc(sizeof(struct database));

d is of type "pointer to struct database".

db = &d;
// ...
return db;

You are assigning to db, and returning, the address to "pointer to struct database".

int no = ((struct database*)testDB)->noOfTuples;

You are interpreting the address of "pointer to struct database" as "pointer to struct database", so noOfTuples is no such thing.

And that is why you should pass around "pointer to datatype", not "pointer to void" (and avoid casting), so the compiler can actually warn you if you get the types wrong. ;-)

DevSolar
  • 67,862
  • 21
  • 134
  • 209
1

You're making things more complicated than they are.

You probably want this:

struct database* HashjoinAllocateDatabase(unsigned long totalNumberOfEdgesInTheEnd) {
  struct database* d = malloc(sizeof(struct database));
  if (d == NULL) {
    puts("Some kind of malloc() error");
    exit(1);
  }

  d->tuples = malloc(totalNumberOfEdgesInTheEnd * sizeof(struct tuple));
  if (d->tuples == NULL) {
    puts("Some kind of malloc() error");
    exit(1);
  }

  d->noOfTuples = 0;                    // why put this to 0 btw?
  printf("Hello %i\n", d->noOfTuples);  // shouldn't it be rather totalNumberOfEdgesInTheEnd ?
  return d;
}


int main() {
  struct database *testDB = HashjoinAllocateDatabase(10);
  int no = testDB->noOfTuples;
  printf("Hello %i", no);
  return 0;
}

There is no need for using void* here. Nor is there any need to hide a pointer type behind a typedef.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115