Пример компиляции ошибок из книги ANSI C, глава «Связанные списки» - PullRequest
5 голосов
/ 10 февраля 2012

Я делаю некоторые примеры из более старой книги C [Первая книга ANSI C] и получаю ошибку при попытке скомпилировать этот пример кода:

#include <stdio.h>

struct tele_typ {
  char name[30];
  char phone_no[15];
  struct tele_typ *nextaddr;
};

main() {
  struct tele_typ t1 = {"Acme, Sam", "(201) 555-6678"};
  struct tele_typ t2 = {"Dolan, Edith", "(213) 682-3104"};
  struct tele_typ t3 = {"Lanfrank, John", "(415) 718-4581"};
  tele_typ *first;    /* create a pointer to a structure */

  first = &t1;          /* store t1's address in first */
  t1.nextaddr = &t2;    /* store t2's address in t1.nextaddr */
  t2.nextaddr = &t3;    /* store t3's address in t2.nextaddr */
  t3.nextaddr = NULL;   /* store the NULL address in t3.nextaddr */

  printf("\n%s %s %s",first->name,t1.nextaddr->name,t2.nextaddr->name);
}

.. и вывод из gcc newstruct.c -o newstruct:

newstruct.c: In function 'main':
newstruct.c:13:3: error: unknown type name 'tele_typ'
newstruct.c:15:9: warning: assignment from incompatible pointer type [enabled by default]
newstruct.c:20:28: error: request for member 'name' in something not a structure or union

Это глава 10.4 о связанных списках. Есть ли ошибка в книге? или что-то изменилось в стандартах / gcc version 4.6.2 20120120 (prerelease)? Спасибо!

Ответы [ 6 ]

3 голосов
/ 10 февраля 2012

Я не смог воспроизвести первое предупреждение;Вы уверены, что код, который вы вставили сюда, является кодом, который выдает предупреждение?

Ошибка unknown type name 'tele_typ' легко исправить: вы объявили тип struct tele_typ, но не имеетеstruct перед строкой:

  tele_typ *first;    /* create a pointer to a structure */

Если вы измените это на:

  struct tele_typ *first;    /* create a pointer to a structure */

Он будет скомпилирован без ошибок.(А также без предупреждений в моем gcc-4.5.real (Ubuntu / Linaro 4.5.2-8ubuntu4) 4.5.2.)

Если вы хотите скомпилировать тело функции точно как есть, то вы бытакже хочу добавить:

typedef struct tele_typ tele_typ;

сразу после определения struct tele_typ:

struct tele_typ {
  char name[30];
  char phone_no[15];
  struct tele_typ *nextaddr;
};

typedef struct tele_typ tele_typ;

Но меня немного беспокоит книга C, которая не дает main() функция типа возврата или набранные параметры.int main(int argc, char* argv[]) или int main(int argc, char** argv) обычно, и любая книга, которая отклоняется от этих двух вариантов, кажется мне немного странной. Язык программирования C - хорошая книга;это трудно улучшить для его ясности и правильности.Рассмотрите возможность перехода на оригинал.

2 голосов
/ 12 февраля 2012

В вашем коде есть следующие ошибки, некоторые из них незначительные.

  1. main() должно быть int main(void). Форма main() является определением старого стиля; он устарел в соответствии со стандартом ANSI C 1989 года и совершенно недействителен в соответствии со стандартом ISO C 1999 года, в котором исключено правило "implicit int". Использование (void) вместо () делает очевидным, что main не имеет параметров; форма () все еще действительна, но устарела с 1989 года. Многие компиляторы C будут принимать подобные функции старого типа для обратной совместимости, но по крайней мере будут предупреждать о них в режиме соответствия. Вы должны узнать, как включить такие предупреждения для вашего компилятора.

  2. tele_typ *first; должно быть struct tele_typ *first;. Это главная проблема. (Добавление typedef - это еще один способ обойти это, но это абсолютно не нужно. Код уже ссылается на тип как struct tele_typ; вам просто нужно делать это последовательно.) Обратите внимание, что в C ++ вы можете ссылаться на тип либо как struct tele_typ, либо как tele_typ - конечно, C ++ - это другой язык с другими правилами.

  3. Вы должны иметь \n на конце строки, которую вы печатаете; Вам это не нужно в начале.

    printf("%s %s %s\n",first->name,t1.nextaddr->name,t2.nextaddr->name);

  4. Вы должны иметь return 0; перед закрытием } в вашей функции main. В соответствии со стандартом ANSI C 1989 года (или эквивалентным стандартом ISO C 1990 года) падение значения main без возврата значения возвращает неопределенный результат в вызывающую среду. Начиная со стандарта 1999 года, падение в конце main означает неявное return 0;, но нет ничего плохого в том, чтобы быть откровенным об этом.

При включенных предупреждениях некоторые компиляторы могут жаловаться на отсутствие инициализаторов в объявлениях t1, t2 и t3, поскольку вы не указали значения для члена nextaddr. Это нормально, поскольку (а), пока у вас есть инициализатор, любые неопределенные члены инициализируются нулями (в случае указателя, нулевым указателем), и (б) вы впоследствии явно присваиваете значения этим элементам .

Я вижу, что вы используете gcc. Чтобы получить хороший набор предупреждений, вы можете использовать это:

gcc -ansi -pedantic -Wall -Wextra

Измените -ansi на -std=c99 или -std=c1x, если вы хотите протестировать более новую версию стандарта C. Обратите внимание, что использование -ansi или одного из параметров -std=... может отключить некоторые нестандартные расширения. Иногда вам нужно написать непереносимый код; в этом случае вы можете отказаться от этой опции, а также, возможно, -pedantic. Но эта программа не использует никаких расширений и не нуждается в этом.

2 голосов
/ 10 февраля 2012

Эта строка неверна:

tele_typ *first;    /* create a pointer to a structure */

Вы забыли ключевое слово struct.

Кроме того, main действительно должен быть объявлен как возвращающий int, и заканчиваться return.

2 голосов
/ 10 февраля 2012

Вам не хватает «struct» в начале 4-й строки функции main.Он должен читать

struct tele_typ *first;

Это бы хорошо работало в C ++, поскольку ключевое слово struct необязательно, а в C - обязательно.

1 голос
/ 10 февраля 2012

Использование typedef - определенно правильный путь.

Просто придира: зарезервированы двойные подчеркивания;они НЕ должны использоваться прикладными программистами, потому что они могут вызвать проблемы с пространством имен.

Книга Kernahan & Ritche "Язык программирования C" не является лучшей книгой.Однако для новичка это сложная задача.Книга, написанная человеком, у которого есть вопрос, явно неверна!

1 голос
/ 10 февраля 2012

Вы должны изменить объявление структуры указателя на что-то вроде этого:

struct tele_typ *first;    /* create a pointer to a structure */

Почему, поскольку вы еще не определили структуру tele_type как прямой тип, вы все равно должны указывать наиспользуя struct tele_typ.

Если бы вы на другой стороне сделали что-то вроде этого:

typedef struct TELE_TYP {
  char name[30];
  char phone_no[15];
  struct TELE_TYP *nextaddr;
}tele_typ;

Вы бы смогли вызвать ранее определенный тип, и это было быхорошо, если вы написали:

tele_typ *first;

Короче говоря, книга не права: P

...