Я пытаюсь создать код, который создает список точек. У меня есть файл с именем «punti.c» с его заголовком и файл с именем «item.c» с его заголовком. Проблема в том, что я не могу получить доступ к переменным точки структуры (x, y) из элемента.
//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;
Я тестировал тип Punto многими способами, поэтому я уверен, что он работает. Я попытался изменить typedef элемента, сделал его указателем на Punto, но это не сработало. (Часть кода на итальянском, извините :))
Проблема в том, что файл .h говорит только о том, что структура существует. Это не говорит нам, что это за члены. Они видны только внутри punti.c, поэтому их нельзя использовать где-либо еще. Обычное решение состоит в том, чтобы поместить определение структуры также в заголовочный файл.
Получайте доступ к членам структуры, компилятор должен знать, что член существует. Если вы хотите использовать элемент x
, то компилятору необходимо определить структуру и знать, что у нее есть член с именем x
и какой у него тип.
Пожалуйста, отредактируйте свой вопрос и скопируйте и вставьте команды для компиляции программы и полученную ошибку. C не имеет классов. Пожалуйста, объясните, чего вы хотите достичь, используя разные имена для одного и того же указателя структуры: Punto
, item
.
Если вы хотите скрыть определение структуры и сделать его непрозрачным типом данных, вам нужно создать API для доступа к структуре. Чтобы помочь в этом, подумайте о структуре, ее членах и функциях с точки зрения поведения, а не просто о группе переменных.
Расширение непрозрачного шрифта (если хотите): punti.h: double getX(struct punto* p);
и punto.c: double getX(struct punto* p) { return p->x; }
Дополнительное примечание: пожалуйста, никогда не указывайте typedef — это просто сокрытие информации без каких-либо дополнительных преимуществ (с исключениями просмотра в случаях, когда природа указателя действительно не представляет интереса, например, тип HANDLE
в WinAPI). Вместо этого наберите struct: typedef struct punto Punto;
и используйте Punto*
потом там, где нужен указатель.
Кажется, item
это struct punto *
, что (не хорошо, но) разрешено. Вы можете иметь указатель на структуру, не зная, что находится внутри структуры. Но как только вы попытаетесь использовать этот «указатель на структуру» для доступа к членам структуры, компилятору необходимо знать, что находится внутри структуры. В вашем случае это не так. Определение структуры находится внутри punti.c
, поэтому определение неизвестно при компиляции item.c
. Поэтому вы не можете сделать it1->x
. Решение: переместите определение в punti.h
или переместите функцию eq
в punti.c
.
И хорошо подумайте об использовании с плавающей запятой, они имеют довольно много последствий для невозможности точной математики (в основном вокруг проблем округления и сравнений, см., например, здесь , здесь или здесь.
Существуют сценарии, в которых они могут быть значимыми (например, в астрономических приложениях), но в большинстве случаев вам лучше использовать арифметику с фиксированной точкой, т. долларов, мкс вместо мс, ..., при необходимости переключитесь на более крупные типы (uint64_t вместо uint32_t или с помощью какой-либо библиотеки больших целых чисел).
Отвечает ли это на ваш вопрос? разыменование указателя на неполный тип
В этом случае я думаю, что причина, по которой несколько человек проголосовали за закрытие вопроса, заключалась в том, что это не был минимально воспроизводимый пример. Вместо того, чтобы публиковать свой код как часть класса Solution
, было бы полезнее включить функцию main
, которая вызывала бы вашу функцию reverse
для определенного ввода, чтобы люди могли видеть, какой ввод вы использовали, какой вывод вы получили и какой вывод вы получили. ожидал.
Определение struct punto
должно быть известно item.c
(например, включено в punti.h
).
// punti.h
struct punto
{
double x;
double y;
};
typedef struct punto *Punto;
Вы можете думать о typedef как о псевдониме. «Объявление typedef предоставляет способ объявить идентификатор как псевдоним типа, который будет использоваться для замены возможно сложного имени типа» (cppreference). Компилятор просто заменяет typedef тем, что он определяет. Тогда ваша функция эквивалентна:
int eq(struct punto* it1, struct punto* it2)
{
return it1->x == it2->x;
}
Из-за этого ему нужно знать определение struct punto
.
Если вы не хотите, чтобы определение struct punto
было известно, вам необходимо предоставить альтернативный способ доступа к его членам. например:
Переполнение стека — что определяет непрозрачный тип в 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);
}
Спасибо @Someprogrammerdude за идею.
Заголовок punti.h
объявляет имя Punto
как псевдоним для типа указателя struct punto *
на неполный тип struct punto
.
//punti.h
typedef struct punto *Punto;
Этот заголовок включен в заголовок item.h
, где объявлено имя typedef item
как псевдоним для имени typedef Punto
, которое используется в списке объявления параметров функции eq
:
//item.h
#include "punti.h"
typedef Punto item;
int eq(item x, item y);
Оба имени typedef Punto и item по-прежнему обозначают типы указателей на неполный тип структуры. Их можно использовать в объявлении функции, поскольку сами указатели всегда являются полными типами.
Но тогда в модуле item.c
в определении функции eq
используются выражения для доступа к элементам данных типа незавершенной структуры 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
}
В этот момент компилятор не знает, действительно ли структура struct punto
содержит элемент данных x
. ТАК выдает ошибку. Вам необходимо включить полное объявление структуры в модули, где есть попытка доступа к элементам данных структуры. В противном случае компилятор сообщит об ошибках.
вы не можете получить доступ к полям структуры, поскольку они определены в другом файле .c. Структура должна быть определена в заголовочном файле, который вы в настоящее время включаете. Если вы хотите, чтобы это было приватно, переместите код эквалайзера в «punti.c».