получение ошибки C: требуется преобразование в нескалярный тип - PullRequest
4 голосов
/ 26 января 2012

Эй, я получаю эту ошибку:

error: conversion to non-scalar type requested

Вот мои структуры:

typedef struct value_t value;

struct value{
   void* x;
   int y;
   value* next;
   value* prev;
};

typedef struct key_t key;

struct key{
   int x;
   value * values;
   key* next;
   key* prev;
};

Вот код, который вызывает у меня проблемы:

struct key new_node = (struct key) calloc(1, sizeof(struct key));
struct key* curr_node = head;

new_node.key = new_key;

struct value head_value = (struct value) calloc(1, sizeof(struct value))

Разве я не должен использовать calloc на структурах?Кроме того, у меня есть структура, которую я создал, и затем я хочу установить ее на указатель того же типа структуры, но получаю ошибку.Это пример того, что я делаю:

struct value x;
struct value* y = *x;

это дает мне эту ошибку

error: invalid type argument of ‘unary *’

Когда я делаю y = x, я получаю это предупреждение:

warning: assignment from incompatible pointer type

Ответы [ 6 ]

13 голосов
/ 26 января 2012

Вы пытаетесь присвоить выражение указателя (тип возврата malloc () и friends void *) для типа struct (struct new_node). Это чепуха. Также: приведение не требуется (и, возможно, опасно, поскольку может скрывать ошибки)

struct key *new_node = calloc(1, sizeof *new_node);

та же проблема с другой строкой malloc ():

struct value *head_value = calloc(1, sizeof *head_value);

Больше ошибок: вы опускаете ключевое слово struct (что разрешено в C ++, но бессмысленно в C):

struct key{
   int x;
   struct value *values;
   struct key *next;
   struct key *prev;
};

ОБНОВЛЕНИЕ: использование структур и указателей для структурирования.

struct key the_struct;
struct key other_struct;
struct key *the_pointer;

the_pointer = &other_struct; // a pointer should point to something

the_struct.x = 42;
the_pointer->x = the_struct.x; 

 /* a->b can be seen as shorthand for (*a).b :: */
(*thepointer).x = the_struct.x;

/* and for the pointer members :: */

the_struct.next = the_pointer;
the_pointer->next = malloc (sizeof *the_pointer->next);
3 голосов
/ 26 января 2012

Я не думаю, что вы правильно поняли typedef s.

Распространенная идиома использования typedefs для удобства именования такова:

struct foo {
    int something;
};

typedef struct foo foo_t;

Затем вы используете типfoo_t вместо менее удобного struct foo.

Для удобства вы можете объединить объявление структуры и typedef в один блок:

typedef struct {
    int something;
} foo_t;

Это определяет foo_t точно так же, как указано выше.

Маркер last в строке typedef - это имя, которое вы назначаете.Я понятия не имею, что код, который вы написали, на самом деле делает с вашим пространством имен, но я сомневаюсь, что это то, что вам нужно.

Теперь, что касается самого кода: calloc возвращает указатель, что означает и ваш тип, и тип хранилища должны быть struct key* (или, если вы исправите имя, key_t).Правильная строка - struct key* new_node = (struct key*)calloc(1, sizeof(struct key));

Для вашего второго, независимого выпуска последняя строка должна быть struct value* y = &x;.Вы хотите, чтобы y сохранял адрес x, а не по адресу x .Сообщение об ошибке указывает на это - вы неправильно используете унарный звездный оператор, чтобы попытаться разыменовать переменную без указателя.

2 голосов
/ 26 января 2012
struct key new_node = (struct key) calloc(1, sizeof(struct key)); 

calloc возвращает значение указателя (void *), которое вы пытаетесь преобразовать и назначить агрегатному (IOW, нескалярному) типу (struct key). Чтобы это исправить, измените тип new_node на struct key * и переписайте свое распределение следующим образом:

struct key *new_node = calloc(1, sizeof *new_node);

Две вещи на заметку. Прежде всего, угробите литое выражение. malloc, calloc и realloc все возвращают void *, которые могут быть присвоены любому типу указателя объекта без необходимости приведения 1 . Фактически, присутствие приведения может потенциально замаскировать ошибку, если вы забудете включить stdlib.h или у вас нет объявления для malloc в области действия 2 .

Во-вторых, обратите внимание, что я использую выражение *new_node в качестве аргумента для sizeof, а не (struct key). sizeof не оценивает его оператор (если только это не переменный тип массива, а это не так); он просто вычисляет тип выражения. Поскольку тип выражения *new_node равен struct key, sizeof вернет правильное количество байтов для хранения этого объекта. Это может сэкономить некоторые трудности при обслуживании, если ваш код структурирован как

T *foo;
... // more than a few lines of code
foo = malloc(sizeof (T))

и вы измените тип foo в объявлении, но не забудьте обновить вызов malloc.

Кроме того, неясно, чего вы пытаетесь достичь с помощью определений типов и структур. Код

typedef struct value_t value;  

struct value{
   void* x;
   int y;
   value* next;
   value* prev;
};

не делает то, что вы думаете. Вы создаете имя typedef value, которое является синонимом для пока неопределенного типа struct value_t. Этот тип value отличается от типа struct value, который вы создадите позже (имена typedef и теги struct находятся в разных пространствах имен). Перепишите свои структуры, чтобы следовать этой модели:

struct value_t {
  void *x;
  int y;
  struct value_t *next;
  struct value_t *prev;
};

typedef struct value_t value;

Кроме того, жизнь будет проще, если вы напишите декларации так, чтобы * ассоциировался с декларатором, а не спецификатором типа 3 . Декларация типа T* p анализируется, как если бы она была написана T (*p). Это избавит вас от смущения написания int* a, b; и ожидания того, что и a, и b будут указателями (b - это просто обычный int).


1 - это одна из областей, где C и C ++ различаются; C ++ не допускает неявные преобразования между void * и другими типами указателей объектов, поэтому, если вы скомпилируете это как код C ++, вы получите ошибку во время компиляции. Кроме того, до принятия стандарта 1989 года функции *alloc возвращали char *, поэтому в те дни приведение требовало , если вы назначали другой тип указателя. Это должно быть проблемой, только если вы работаете на очень старой системе.

2 - Вплоть до стандарта 1999 года, если компилятор видел вызов функции без предшествующего объявления, он предполагал, что функция вернула int (именно поэтому вы все еще время от времени видите примеры, подобные

 main()
 {
   ...
 }

в некоторых уроках; main это неявно набрано, чтобы вернуть int. Начиная с C99, это больше не разрешено). Поэтому, если вы забудете включить stdlib.h и вызвать calloc (а вы не компилируете как C99), компилятор примет функцию, возвращающую int, и сгенерирует машинный код соответствующим образом. Если вы оставите преобразование выключенным, компилятор выдаст диагностическое сообщение о том, что вы пытаетесь присвоить указателю значение int, что недопустимо. Если вы оставите приведение, код скомпилируется, но значение указателя может быть изменено во время выполнения (преобразование указателей в int и обратно в указатели снова не гарантируется).

3 - Есть несколько редких случаев, ограниченных C ++, где стиль T* p может сделать код немного более понятным, но в целом вам лучше следовать стилю T *p. Да, это личное мнение, но оно подкреплено нетривиальным количеством опыта.

1 голос
/ 26 января 2012

Вы не должны назначать указатель на переменную без указателя.Измените new_node на указатель.

Кроме того, чтобы использовать адрес переменной, вам нужно &, а не *, поэтому измените его на struct value* y = &x;

Edit: ваши typedefsтоже не правы.поменять их местами.

1 голос
/ 26 января 2012

calloc (3) возвращает указатель в память, которую он выделяет.

struct key new_node = (struct key) calloc(1, sizeof(struct key));

должно быть

struct key* new_node = calloc(1, sizeof(struct key));
0 голосов
/ 26 января 2012

Для второй проблемы, вы хотите использовать амперсанд "&" вместо астриска "*".Астрик разыменовывает указатель, амперсанд дает указатель от значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...