-1

I have come across this error i can not explain. Was working on a liked list:

main.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

int main(int argc, char *argv[]) {
    
    Container* c = initList((void*)0x1);

    void* value1 = list_get_content(c,0);  //1.
    void* value2 = list_get(c,0)->content; //2.

    printf("%p",value1);
    printf("%p",value2);
    
    return 0;
}

1. Works fine, but 2. doesn't compile, eventhough they should do the same thing.
Why does the function call make a diffrence here?

list_get_content is just a wrapper for list_get()->content

Compiled using MinGW GCC 4.7.2 in Dev-C++.
No parameters or settings

list.h:

struct _Node;
typedef struct _Node Node;
 
struct _Container;
typedef struct _Container Container;
 
Node* createNode(Node* last, Node* next, void* content);
Container* initList(void* firstValue);
 
void list_add(Container* list,void* e);
void* list_get_content(Container* list,int index);
Node* list_get(Container* list,int index);
void list_remove(Container* list,int index);

list.c:

#include <stdlib.h>
#include <stdio.h>
#include "list.h"

struct _Node{
    void* content;
    struct Node* last;
    struct Node* next;
};

struct _Container{
    Node* start;
    Node* end;
};

Node* createNode(Node* last, Node* next, void* content){
    Node *n = (Node *) malloc(sizeof(Node));
    n->content = content;
    n->last = last;
    n->next = next;
    return n;
}

Container* initList(void* firstValue){
    Container *c = (Container *) malloc(sizeof(Container));
    Node* n = createNode(NULL,NULL,firstValue);
    c->start = n;
    c->end = n;
    return c;
}

Node* list_get(Container* list,int index){
    Node* n = list->start;
    for(int i=0;i<index;i++){
        n = n->next;
    }   
    return n;
}

void* list_get_content(Container* list,int index){
    return list_get(list,index)->content;
}
onebacon
  • 30
  • 5
  • 3
    Can you create a [mcve]? – Nate Eldredge Mar 30 '21 at 21:32
  • I edited the top part, it's where the error happens. – onebacon Mar 30 '21 at 21:37
  • There's a compiler warning that you're passing an `int` as the third argument to `createNode`, which is supposed to be a `void *`. What's your goal here? – Nate Eldredge Mar 30 '21 at 21:39
  • i saw the warning about the void* just now too, in my real program i import all the List stuff from list.c. When i use it "imported" i get the dereferencing error when i define the functions in the same file it works. – onebacon Mar 30 '21 at 21:42
  • Just because it doesn't crash doesn't mean it's "fine". Check with a debugger here. It's highly probable you have a bad pointer somewhere. – tadman Mar 30 '21 at 21:45
  • Could be an issue with the prototypes. Update your example to use multiple source files (since that's where you have a problem) and show how you're compiling / linking them. – dbush Mar 30 '21 at 21:47
  • Belaying your "real" program for a moment. Does *this* code, exactly as present, reproduce your problem or not? – WhozCraig Mar 30 '21 at 21:50
  • Code should be pasted directly in the question, not a link. – dbush Mar 30 '21 at 21:54
  • I've edited the question show my code directly. The problem is the error in line 10 of main.c "dereferencing pointer to incomplete type" . I dont understand why list_get_content doesnt throw the same error, eventhough it does the same. – onebacon Mar 30 '21 at 21:57
  • 1
    This code doesn't compile. Please use the **exact** code that you compile and run and experiences the problem you are having. Also give the command line for the compiler / linker. – dbush Mar 30 '21 at 21:58
  • Avoid starting identifiers with underscores, see [this post](https://stackoverflow.com/questions/25090635/use-and-in-c-programs) for an explaination. Note that you can just write `typedef struct Node {...} Node;`. – G. Sliepen Mar 30 '21 at 22:00
  • @dbush the problem is that the code doesnt compile. Line 9 works but line 10 doesn't. They do the same thing, but L10 is in a function call, why does 9 compile but 10 doesn't? – onebacon Mar 30 '21 at 22:01
  • 1
    @onebacon Before you said the code crashes, and now you're saying it doesn't compile, so which is it? Again, show us the **exact** code that reproduces your original issue. – dbush Mar 30 '21 at 22:02
  • You might also want to consider updating your compiler, GCC 4.7.2 is more than 8 years old by now. – G. Sliepen Mar 30 '21 at 22:02
  • @dbush I'm sorry with crashes i meant "crashes while compiling", fixed the question. My Problem is in Line 10 of main.c. This is all the code. I have the 3 Files (main.c, list.h, list.c) in the same directory – onebacon Mar 30 '21 at 22:06
  • Your `struct _Node{ void* content; struct Node* last; struct Node* next;};` can't be right - it should be `struct _Node{ void* content; struct _Node* last; struct _Node* next;};` - I don't thing it should even compile. – Jerry Jeremiah Mar 30 '21 at 22:09
  • @JerryJeremiah I guess it executes the typedef in the header file first, should be typedef Node{...} Node in the first place as G. Sliepen said. – onebacon Mar 30 '21 at 22:12
  • The typedef is of an incomplete type because the struct is not defined before the typedef. And that's why the code you posted doesn't compile. If I move the definition of the structs to the header file, then it compiles and runs: https://onlinegdb.com/Hkw8fQ-B_ – Jerry Jeremiah Mar 30 '21 at 22:14
  • Thank you @JerryJeremiah I understand the problem now – onebacon Mar 30 '21 at 22:23

2 Answers2

3

Your header file only contains declarations for struct _Node and struct _Container, while the definitions reside in list.c. So for main.c those types are incomplete.

This means that in main.c you can use pointers to those types but cannot dereference them because it doesn't have the definition of those structures.

If you want the definitions of struct _Node and struct _Container to be viewable outside of list.c then you need to move them into list.h. Otherwise you need to rely on functions in list.c to return any data inside of them.

You also have a problem here:

struct _Node{
    void* content;
    struct Node* last;
    struct Node* next;
};

The next and last fields are pointing to a different struct type which has not been defined. This results in a type mismatch when you later attempt to assign values to those pointers. You want:

struct _Node{
    void* content;
    struct _Node* last;
    struct _Node* next;
};
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    So only things directly imported are visible? That actually explains a lot. Thank you so much – onebacon Mar 30 '21 at 22:22
  • @onebacon you should take a look at include guards ([1](https://stackoverflow.com/questions/27810115/what-exactly-do-c-include-guards-do), [2](https://stackoverflow.com/questions/44673885/c-redefinition-of-struct)). Let's say that in both file `a` and `b` you import some `c` that you have written in a naive way, then you also import `a` into `b`. At that point the compiler would give you a "redefinition error" because you will have imported `c` twice, which is not good because it's like declaring variables and functions with the same name multiple times. – rdxdkr Mar 30 '21 at 22:44
0

I know it doesn't provide a solution for your problem, but please please please stop using Dev-C++. It might still receive updates (from whom I don't know, since it's said to be unmaintained), but the compiler version it ships with is completely obsolete (even for toy projects or school assignments) and last time I've heard about it, even the IDE experience was very lacking.

If you're on Windows you can install a more recent version of gcc with MinGW and run it manually while programming on something like VSCode; it's not very straightforward to configure, but it's probably the best "enhanced code editor" around. If you want a full fledged IDE there's Visual Studio Community shipped with (but not limited to) the MSVC++ compiler, which might not be 100% compatible with the more recent C standards but at least it doesn't require a convoluted setup.

On Mac there's LLVM's clang compiler preinstalled and you could use XCode, while in Linux the preinstalled one is gcc and it seems that KDevelop is a very good IDE. Of course you can always use VSCode as it's multiplatform.

rdxdkr
  • 839
  • 1
  • 12
  • 22
  • Or continue using the IDE from DevC++ and just upgrade the compiler. Then there is no learning curve. https://www.bloodshed.net/ even has an IDE-only download so they are expecting people to install their own compilers. – Jerry Jeremiah Mar 30 '21 at 22:42
  • @JerryJeremiah Honestly I don't even know which version is the right one to download. On some websites it says it's been updated very recently but it doesn't look like the official version and the whole ordeal looks sketchy at the very least. If Visual Studio is too heavy/complicated there's always Code::Blocks if one is really fond of the 90s' look, otherwise the experience with a modern editor that even supports language server protocols is just superior. – rdxdkr Mar 30 '21 at 22:53
  • I wasn't suggesting that DevC++ was a good choice - just that if you like the IDE you don't have to change it - you could just upgrade the compiler. Personally, I like Visual Studio. Sorry for any confusion my previous comment caused. – Jerry Jeremiah Mar 30 '21 at 23:09
  • Eh, given that he's probably a beginner it's likely that he still hasn't used anything else so he doesn't even know what to look for. Some people think that it's best for beginners to do everything manually without autocompletion or other fancy features, and then they ask themselves why those same beginners after some years of programming are still debugging with `print()` and don't even know what breakpoints or loggers are. – rdxdkr Mar 30 '21 at 23:42
  • Fair enough. I guess that's why there are an inordinate number of SO questions where the correct answer is "learn to use a debugger". like this one: https://stackoverflow.com/questions/66845644/learning-c-for-cs50-lab1-population-growth-my-program-runs-but-doesnt-do-wha – Jerry Jeremiah Mar 30 '21 at 23:50
  • Yep. To be fair C is in a rough spot because a preconfigured graphical debugger is very rare to find and possibly not even trivial to setup manually, and a beginner that is still not used to the terminal has every right to hate `gdb`, at least initially. – rdxdkr Mar 31 '21 at 00:10