5

I am doing some examples out of an older C book [A First Book of ANSI C] and am getting an error while trying to compile this example code:

#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);
}

..and the output from 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

It's chapter 10.4 on Linked Lists. Is there an error in the book? or has something changed in the standards/gcc version 4.6.2 20120120 (prerelease)? Thank you!

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
nak
  • 3,077
  • 3
  • 27
  • 35
  • Can you check the code in the book? Does it really declare `tele_typ *first;`, and not `struct tele_type *first;`? Or did you just miss the `struct` keyword when you typed it? – Keith Thompson Feb 11 '12 at 23:23
  • Which edition of [the book](http://www.amazon.com/First-Book-Fourth-Introduction-Programming/dp/1418835560) are you using? ($166.95 list price for a paperback? Really?) – Keith Thompson Feb 11 '12 at 23:26
  • Here's a picture of the book Keith: http://i.imgur.com/hXnwX.jpg 2nd Edition, ISBN: 0-314-01086-6 A friend gave me the book a few years back. I got distracted from trying to learn C (got hooked on Python...) and have just started getting interested again :) – nak Feb 13 '12 at 04:22
  • That's definitely a serious error in the book. Either the author used a rather lax C++ compiler to compile the code, or he didn't bother compiling it at all; the latter is IMHO inexcusable. I hope later editions corrected this. – Keith Thompson Feb 13 '12 at 05:08

6 Answers6

3

I couldn't reproduce the first warning; are you sure the code you've pasted here is the code that gives you the warning?

The error unknown type name 'tele_typ' is easy to fix: you've declared a type struct tele_typ, but don't have the struct in front of the line:

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

If you change this to:

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

It'll compile without error. (And also without warnings in my gcc-4.5.real (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2.)

If you wanted to compile the function body exactly as-is, then you'd also want to add:

typedef struct tele_typ tele_typ;

immediately after the struct tele_typ definition:

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

typedef struct tele_typ tele_typ;

But I'm a little worried about a C book that doesn't give the main() function a return type or typed parameters. int main(int argc, char* argv[]) or int main(int argc, char** argv) is usual, and any book that deviates from these two options strikes me as a little strange. The C Programming Language is a fine book; it is hard to improve upon it for its clarity and correctness. Consider switching to the original.

sarnold
  • 102,305
  • 22
  • 181
  • 238
  • Although I understand your concern, I remember when I learnt C, my teacher would always say just add those things (input and output types), later you will know what they are for. And it would only confuse me. I guess it can either be gradual or not, I would have preferred an explanation before adding them. – El Developer Feb 10 '12 at 02:10
  • Heh, yes, `public static int main(String args[]) { ... }` is burned into my brain from my first Java days, even though it made no sense at the time why the function had to be `static` or in a class. Somehow the C `int main(int argc, char* argv[])` always made more sense to me. I guess I'm simple and simple languages make more sense. :) – sarnold Feb 10 '12 at 02:15
  • Ah, you're right I did edit the code here and used an old output, I changed the output to match the posted code. – nak Feb 10 '12 at 02:32
  • `int main(void)` is the other valid form. – Keith Thompson Feb 11 '12 at 23:05
  • @Keith: Thanks -- I knew there was a shorter, still legal, version, but I can never recall the details when I want to refer to it. – sarnold Feb 13 '12 at 00:28
  • I just ordered the "The C Porgramming Language" sarnold, thanks for the tip :) – nak Feb 13 '12 at 17:43
  • "The C Programming Language" book also doesn't define return type in MOST all examples that I've found :( oh well... it seems well written though. :) – nak Feb 20 '12 at 02:19
  • @nak: Ha! I've never noticed before now that K&R doesn't use `int main(int argc, char *argv[])` until page **115**, section **5.10**. I'm a bit speechless. – sarnold Feb 20 '12 at 07:08
2

You're missing the 'struct' at the beginning of the 4th line of function main. It should read

struct tele_typ *first;

That would have worked fine in C++, since the 'struct' keyword is optional, but in C it's required.

SteveB
  • 211
  • 1
  • 2
2

This line is wrong:

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

You forgot the struct keyword.

Also, main should really be declared as returning an int, and end with a return.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

Your code has the following errors, some of them minor.

  1. main() needs to be int main(void). The main() form is an old-style definition; it's deprecated as of the 1989 ANSI C standard, and flat-out invalid under the 1999 ISO C standard, which dropped the "implicit int" rule. Using (void) rather than () makes it explicit that main has no parameters; the () form is still valid, but has been deprecated since 1989. Many C compilers will accept old-style features like this for the sake of backward compatibility, but will at least warn about them in conforming mode. You should find out how to enable such warnings for your compiler.

  2. tele_typ *first; needs to be struct tele_typ *first;. This is the main problem. (Adding a typedef is another way to work around this, but it's absolutely unnecessary. The code already refers to the type as struct tele_typ; you just need to do so consistently.) Note that in C++ you can refer to the type either as struct tele_typ or just as tele_typ -- of course, C++ is a different language with different rules.

  3. You should have a \n at the end of the string you print; you don't need it at the beginning.

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

  4. You should have a return 0; before the closing } in your main function. As of the 1989 ANSI C standard (or the equivalent 1990 ISO C standard), falling off the end of main without returning a value returns an undefined result to the calling environment. As of the 1999 standard, falling off the end of main does an implicit return 0;, but there's no harm in being explicit about it.

With warnings enabled, some compilers may complain about missing initializers on the declarations of t1, t2, and t3, since you didn't provide values for the nextaddr member. This is ok, since (a) as long as you have an initializer, any unspecified members are initialized to zero (in the case of a pointer, to a null pointer), and (b) you explicitly assign values to these members later on.

I see that you're using gcc. To get a good set of warnings, you can use this:

gcc -ansi -pedantic -Wall -Wextra

Change the -ansi to -std=c99 or -std=c1x if you want to test against a newer version of the C standard. Note that using -ansi or one of the -std=... options may disable some non-standard extensions. Sometimes you need to write non-portable code; in that case, you can drop that option, and probably the -pedantic as well. But this program doesn't use any extensions, and doesn't need to.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
1

You have to change the pointer structure declaration for something like this:

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

Why, because you haven't already defined the structure tele_type as a direct type, you still have to point at it using struct tele_typ.

If you on the other side had done something like this:

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

You would have been able to call for the previously defined type and it would have been ok if you had written:

tele_typ *first;

Long story short, the book is wrong :P

El Developer
  • 3,345
  • 1
  • 21
  • 40
  • No need for the `__` around the struct name; structs are in a different namespace than the typedef names. – sarnold Feb 10 '12 at 02:14
  • 1
    There's sure no need though, that's the easiest way to make a difference between the struct type and the definition identifier. I guess everyone has their own style. – El Developer Feb 10 '12 at 02:16
  • 1
    Identifiers starting with double underscores are reserved. You should *never* use them in your own code. There is no need to use different identifiers for the struct tag and the typedef; `typedef struct tele_typ { /* ... */ } tele_typ;` is perfectly legal, and lets you refer to the type either as `tele_typ` or as `struct tele_typ`. But since the previous three declarations already refer to the type as `struct tele_typ`, it makes a lot more sense to refer to it as `struct tele_typ` consistently, and *don't bother with the `typedef`*. – Keith Thompson Feb 11 '12 at 23:04
  • 1
    Oh, and "you haven't already defined the structure teletype as a type" is incorrect. A struct declaration *does* define a type; in this case, that type's name is `struct tele_typ`. A typedef does not create a type; it merely creates a new name for an existing type. – Keith Thompson Feb 11 '12 at 23:07
  • THANK YOU SO MUCH! I didn't know that. I'll correct my answer. – El Developer Feb 12 '12 at 01:02
  • @ElDeveloper: Better, but your answer still has some problems. C has no concept of a "direct type" as you call it; give your suggestion, both `struct TELE_TYP` and `tele_typ` are equally valid names for the same type, and saying that `struct TELE_TYP` "point[s] at it" is misleading. There's already code referring to the type as `struct tele_typ`, and changing the struct tag breaks that code. If you insist on using a typedef, there is no good reason for the typedef name and the struct tags to differ; `typedef struct tele_typ { /* ... */ } tele_typ;` is perfectly legal. – Keith Thompson Feb 14 '12 at 06:00
1

Using the typedef is definitely the way to go.

Just a quibble: Leading double underscores are reserved; they should NOT be used by application programmers because they could cause namespace problems.

The Kernahan & Ritche book "The C Programming Language" is the best book bar none. It is a hard slog for the beginner, however. The book the person who Posted the question has is obviously wrong!

Ernest_CT
  • 62
  • 4
  • 1
    Why is a typedef "definitely the way to go"? The code already refers to the type as `struct tele_typ` on the previous three lines; a better solution is to add the `struct` keyword to the fourth line. – Keith Thompson Feb 11 '12 at 23:59