3

I'm trying to create a code that creates a list of points. I have a file named "punti.c" with its header and a file named "item.c" with its header. The problem is that I can't access the variables of the struct point(x,y) from the item.

//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}
//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);
//punti.c
#include "utilities.h"
#include "punti.h"
#include <math.h>

struct punto
{
    double x;
    double y;
};
//punti.h
typedef struct punto *Punto;

I tested the type Punto in many ways, so I'm sure it works. I tried to change the typedef of item, made it a pointer to Punto, but it didn't work. (Part of the code is in Italian, sorry:) )

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • you can't access the structure fields as they're defined in the other .c file. The structure must be defined in a header file that you're currently including. If you want it private, then move your eq code in "punti.c" – Jean-François Fabre Mar 31 '23 at 08:11
  • The problem is that the .h file only says that a struct exists. It doesn't tell us what the members are. Those are only visible inside punti.c, so cannot be used elsewhere. The usual solution is to put the struct definition also in header file. – BoP Mar 31 '23 at 08:13
  • Do access the members of a structure, the compiler needs to actually *know* that the member exists. If you want to use the member `x` then the compiler needs the definition of the structure and know that it have a member named `x`, and what type it has. – Some programmer dude Mar 31 '23 at 08:13
  • Please [edit] your question and copy&paste the commands to compile the program and the resulting error. C does not have classes. Please explain what you want to achieve with the different names for the same structure pointer: `Punto`, `item`. – Bodo Mar 31 '23 at 08:13
  • 1
    If you want to hide the structure definition, and make it [an opaque data type](https://en.wikipedia.org/wiki/Opaque_data_type) then you need to create an API to access the structure. To help with this think of the structure, its members and the functions in terms of *behavior* instead of simply a grouping of variables. – Some programmer dude Mar 31 '23 at 08:14
  • 1
    Extending on the opaque type (if you want it): `punti.h: double getX(struct punto* p);` and `punto.c: double getX(struct punto* p) { return p->x; }` – Aconcagua Mar 31 '23 at 08:17
  • 2
    Side note: Please don't ever typedef pointers – this is just information hiding without any further benefit (with view exceptions in cases where the pointer nature really is not of interest, like e.g. the `HANDLE` type in WinAPI). Instead rather typedef the struct: `typedef struct punto Punto;` and use `Punto*` afterwards where a pointer is needed. – Aconcagua Mar 31 '23 at 08:20
  • Seems `item` is `struct punto *` which is (not fine but) allowed. You can have a pointer to struct without knowing what is inside the struct. But once you try to use that "pointer to struct" to access the struct members, the compiler needs to know what is inside the struct. In your case it doesn't. The struct definition is inside `punti.c` so the difinition is not known when compiling `item.c`. Therefore you can't do `it1->x`. Solution: Move the definition to `punti.h` or move the function `eq` to `punti.c` – Support Ukraine Mar 31 '23 at 08:26
  • And think well about using floating point, they come with quite a few implications for not allowing precise math (mostly around rounding issues and comparisons, see e.g. [here](https://stackoverflow.com/questions/588004/is-floating-point-math-broken/), [here](https://stackoverflow.com/questions/2100490/floating-point-inaccuracy-examples) or [here](https://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison). – Aconcagua Mar 31 '23 at 08:31
  • There *are* scenarios where they *can* be meaningful (e.g. in astronomic applications), most of the time you are better of with fixed point arithmetic, though, i.e. if need be calculating in sub-units like cents (or 10th of) instead of euros or dollars, µs instead of ms, ..., if need be switch to larger types (uint64_t instead of uint32_t or using some big-integer library). – Aconcagua Mar 31 '23 at 08:31
  • Does this answer your question? [dereferencing pointer to incomplete type](https://stackoverflow.com/questions/2700646/dereferencing-pointer-to-incomplete-type) – Karl Knechtel Mar 31 '23 at 09:58
  • In that case, I think the reason several people voted to close the question was because it wasn't a [mre]. Instead of posting your code as part of a class `Solution`, it would have been more helpful to include a `main` function which called your `reverse` function on specific input, so people can see what input you used, what output you got, and what output you expected. – Stef May 04 '23 at 11:05

2 Answers2

1

The header punti.h declares the name Punto as an alias for the pointer type struct punto * to the incomplete type struct punto.

//punti.h
typedef struct punto *Punto;

This header is included in the header item.h where there is declared the typedef name item as an alias for the typedef name Punto that is used in parameter declaration list of the function eq:

//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);

The both typedef names Punto and item still denote pointer types to an incomplete structure type. They may be used in the function declaration because pointers themselves are always complete types.

But then in the module item.c in the definition of the function eq there are used expressions to access data members of the incomplete structure type struct punto

//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}

AT this point the compiler does not know whether indeed the structure struct punto contains the data member x. SO it issues an error. You need to include the complete structure declaration in modules where there are attempt to access data members of the structure. Otherwise the compiler will report errors.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

The definition of struct punto needs to be known to item.c (f.e. included with punti.h).

// punti.h
struct punto
{
    double x;
    double y;
};

typedef struct punto *Punto;

You can think about typedef as an alias. "The typedef declaration provides a way to declare an identifier as a type alias, to be used to replace a possibly complex type name" (cppreference). The compiler pretty much just replaces typedef with what it defines. Your function is then equivalent to:

int eq(struct punto* it1, struct punto* it2)
{
    return it1->x == it2->x;
}

Because of that, it needs to know the definition of struct punto.


If you don't want the definition of struct punto to be known, you need to provide an alternative way of accessing its members. f.e.:

Stack overflow - what defines an opaque type in c

//punti.h
typedef struct punto *Punto;
double get_x(Punto p);
//punti.c
...
struct punto
{
    double x;
    double y;
};

double get_x(Punto p)
{
    return p->x;
}
//item.c
...
int eq(item it1, item it2)
{
    // This is ok, as there is no `->` or `*it1`.
    return get_x(it1) == get_x(it2);
}

Thank you @Someprogrammerdude for the idea.

Vojtěch Chvojka
  • 378
  • 1
  • 15