tad@killer.UUCP (Tad Marko) (08/10/86)
[line eater fodder] Hey, everybody, I discovered a "new" (new to me) way of coding such static things as descriptions, helps, and the like. It goes like this: #include <stdio.h> char *help[] = { "You do it this way, dummy:", "", "so on and so forth...", NULL }; char *description[] = { "I do this...", "no much of anything...", NULL }; main() { say(help); printf("\n"); say(description); } say(dp) char *dp[]; { while (*dp != NULL) printf("%s\n", *dp++); } Here's the question: Should help and description be declared char *help[] or char **help? Should say() be declared void, or is there some sort of error checking I should implement? Are there any other suggestions or comments? How about any other neat "tricks" anyone has discovered lately? Tad -- Tad Marko ..!ihnp4!killer!tad || ..!ihnp4!alamo!infoswx!ntvax!tad UNIX Connection BBS AT&T 3B2 North Texas State U. VAX 11/780 If it's not nailed down, it's mine; If I can pick it up, it's not nailed down.
guy@sun.uucp (Guy Harris) (08/11/86)
> Here's the question: Should help and description be declared char *help[] > or char **help? Since you've already shown a declaration for them, and since you've done it correctly, I'm not sure why you're asking. Since "help" would be an array of pointers to characters, which is in no way equivalent to a pointer to a pointer to a character, you obviously declare it as such - "char *help[]". Try it the other way ('char **help = { "foo", "bar", ... };') and the compiler will let you know, in no uncertain terms, that it's not correct. > Should say() be declared void, or is there some sort of error checking I > should implement? That depends on whether you can do anything useful if you detect an error. For example, it's rarely useful to check for errors on an "fprintf" to "stderr" - if it fails, what can you do, print a message to "stderr" indicating you can't print a message to "stderr"? (The VMS routine that prints error messages never returns a failure indication, probably for much the same reason.) Even if you have something useful to do on an error, you may want to do it entirely within "say". -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
gary@darth.UUCP (Gary Wisniewski) (08/12/86)
Distribution: In article <248@killer.UUCP> tad@killer.UUCP writes: >Hey, everybody, I discovered a "new" (new to me) way of coding such static >things as descriptions, helps, and the like. It goes like this: > [At this point, the author includes code which builds a table of char *'s which are preinitialized and terminated with a NULL ptr, then builds a function say(char *) which prints out the entire list.] > >Here's the question: Should help and description be declared char *help[] >or char **help? Should say() be declared void, or is there some sort of >error checking I should implement? Are there any other suggestions or >comments? How about any other neat "tricks" anyone has discovered lately? > > Tad >-- >Tad Marko The technique you've discovered is actually a small part of a much more general facility in C. For more interesting ideas about ways to create complex pre-initialized structures and tables, look at K&R, page 124. As far as your question about "char *help[]" and "char **help": the two forms are IDENTICAL to virtually every C compiler (that's worth its salt). Arrays in C are merely special cases of pointers. In other words, both forms are correct. Section 5.3 of K&R explain this more fully. Happy C-ing. Gary J. Wisniewski Pittsburgh, PA Usenet: {allegra, bellcore, cadre}!pitt!darth!gary
chris@umcp-cs.UUCP (Chris Torek) (08/16/86)
In article <138@darth.UUCP> gary@darth.UUCP (Gary Wisniewski) writes: >As far as your question about "char *help[]" and "char **help": the two >forms are IDENTICAL to virtually every C compiler (that's worth its >salt). Arrays in C are merely special cases of pointers. In other >words, both forms are correct. NO! Ai! This has been asserted far too often. Arrays and pointers are not at all the same thing in C! >Section 5.3 of K&R explain this more fully. Indeed it does, and I suggest you read it rather more carefully. The correspondence between indexing and pointer arithmetic is evidently very close. ... The effect is that an array name *is* a pointer expression. (p. 94) This does not say that arrays and pointers are *the same*. There is one difference between an array name and a pointer that must be kept in mind. Aha! See p. 94 for that difference. As formal parameters in a function defintion, char s[]; and char *s; are exactly equivalent.... (p. 95) Here they *are* the same---but note the qualifier: `As formal parameters'. In the (unquoted) original example, the array was a global variable. There is one other thing which, I guess, adds to this confusion. Both of the following are legal global declarations in C: char msg0[] = "Hello, world"; char *msg1 = "Hello, world"; Given both declarations, printf("%s\n", msg0); and printf("%s\n", msg1); produce the same output. Yet msg0 and msg1 are not the same: printf("%d %d\n", sizeof (msg0), sizeof (msg1)); prints 13 4 on a Vax; for msg0 is an array, and msg1 is a pointer. The code generated for the two declarations is different: /* edited assembly output from ccom */ .data # Switch to data segment. .globl _msg0 # The array ... _msg0: .asciz "Hello, world" # and here it is. .data 2 # Switch to alternate data segment. L12: .asciz "Hello, world" # The object to which msg1 will point. .data # Back to regular data segment. .globl _msg1 # The pointer ... _msg1: .long L12 # which points to the object. String constants comprise two special cases in the compiler. The first case is when the constant appears anywhere *except* as an initialiser for a `char' array. Here the compiler uses the alternate data segment to suddenly `create' a new array, initialised to the string text; it then generates a pointer to that array. In the second case the string constant is generated in the primary data segment, and `is' the array being initialised: the constant is `unwrapped' into an aggregate initialisation. The second case is actually the more `conventional' of the two; other aggregates cannot be created at run time: int a[] = { 0, 1, 2, 3 }; is legal only outside functions. What seems surprising to some is that the same is true of char s[] = "foo"; because, unwrapped, this is equivalent to char s[] = { 'f', 'o', 'o', '\0' }; ---even though char *s = "foo"; is legal anywhere a declaration is legal. Ah, if only C had aggregate initialisers! -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
mac@tflop.UUCP (Mike McNamara) (08/20/86)
In article <248@killer.UUCP> tad@killer.UUCP writes: > Should say() be declared void, or is there some sort of > error checking I should implement? Progammer's Maxim # 17 : Never test for an error condition if you don't know what to do with it. -- ---------------------------------+-------------------------------------------- | Michael Mc Namara | Let the words by yours, I'm done with mine. | UUCP: dual!vecpyr!tflop!mac | May your life proceed by its own design. | ARPA: tflop!mac@ames.arpa | ---------------------------------+--------------------------------------------
throopw@dg_rtp.UUCP (Wayne Throop) (08/20/86)
> chris@umcp-cs.UUCP (Chris Torek) >> gary@darth.UUCP (Gary Wisniewski) >>> [ Original poster asks (among other things): >>> char *a[] = {"foo","bar"}; works... >>> will char **p = {"foo","bar"}; ? ] >>As far as your question about "char *help[]" and "char **help": the two >>forms are IDENTICAL to virtually every C compiler (that's worth its >>salt). Arrays in C are merely special cases of pointers. In other >>words, both forms are correct. > > NO! > > Ai! This has been asserted far too often. Arrays and pointers are > not at all the same thing in C! Naturally, Chris is correct here, and points out that a reasonably careful reading of K&R reveals the truth of the matter. However, I'd like to expand on the assertion that "virtually every C compiler [treats char *x[] and char **x identically]". In fact, I doubt that there are very many such compilers. I even think it is likely that the compiler Gary uses does *NOT* treat these cases identically. Which brings me to the point. TEST YOUR ASSERTIONS ABOUT THE C COMPILER BEFORE POSTING! Let's see what we get when we try to compile this: char *a[] = {"foo","bar"}; char **p = {"foo","bar"}; Lint says (2) **** cannot recover from this error **** Not very informative, but should give you the idea that the declaration of p is wrong, and the declaration of a is OK. A local typechecker says 2 too many values in initialization 2 wrong type initializer Ah. A little more informative. We are trying to initialize a single pointer value with multiple pointers. And they have type mismatch problems (we are trying to initialize a (char **) with a (char *)). Last, let's see what the compiler says. char **p = {"foo","bar"}; ^ You supplied p more initial values than there were variables or fields to initialize. The compiler ignored the excess elements. The compiler didn't diagnose the type mismatch problems because typechecking isn't part of its job. The point? In this specific case, every C-understanding tool I applied to the example Gary said would work for "every C compiler worth its salt" found problems with it. So, since they are easy to check, CHECK THESE CLAIMS BEFORE YOU POST. It helps to carefully read the standards. But every assertion posted about implementations of these standards ought to be backed up with an example that has actually been fed to the compiler/tool/whatnot in question. -- You can't tell how deep a puddle is until you step in it. --- Miller's Law -- Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw
karl@haddock (08/22/86)
>["type *" and "type []"] are IDENTICAL to virtually every C compiler ... >Arrays in C are merely special cases of pointers. You are wrong, but you've got a lot of company. I almost wish the language had kept arrays and pointers completely separate, requiring "&a[0]" to change an array into a pointer, and "*(p+n)" to index from a pointer. Or maybe "p@[n]", where "@" is some postfix operator that converts a pointer into an array of unknown size. Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint
tad@killer.UUCP (Tad Marko) (08/23/86)
In my original article, I wasn't asking if this was legal: char **thing = {"stuff","and more stuff"}; I was asking if I should use foo(parm) char **parm; {...} or foo(parm) char *parm[]; {...} and I *DID* test both of them, and they both worked. C'mon, give me at least a *little* credit...sheeeesh! -- Tad Marko ..!ihnp4!killer!tad || ..!ihnp4!alamo!infoswx!ntvax!tad UNIX Connection BBS AT&T 3B2 North Texas State U. VAX 11/780 flames to: /dev/your_ear