home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!cs.utexas.edu!hellgate.utah.edu!dog.ee.lbl.gov!horse.ee.lbl.gov!torek
- From: torek@horse.ee.lbl.gov (Chris Torek)
- Newsgroups: comp.lang.c
- Subject: char *foo[] (was Computer terms, etc)
- Date: 13 Aug 1992 04:58:38 GMT
- Organization: Lawrence Berkeley Laboratory, Berkeley
- Lines: 172
- Message-ID: <25451@dog.ee.lbl.gov>
- References: <cee1.713424953@Isis.MsState.Edu> <19479@fritz.filenet.com> <20900024@inmet>
- Reply-To: torek@horse.ee.lbl.gov (Chris Torek)
- NNTP-Posting-Host: 128.3.112.15
-
- In article <cee1.713424953@Isis.MsState.Edu> cee1@ra.msstate.edu
- (Charles Evans) asks for definitions of a bunch of IBM PC specific
- terms (which should generally be kept to other newsgroups) and for
- explanations about:
-
- *foo[]
- **foo
-
- and
-
- >char *foo = "abc";
- >char *foo[] = "abc";
- >char foo[] = "abc";
- >char foo[4] = "abc"; <--- is the '\0' automatcially added?
-
- So far I have seen three answers, two containing errors and one short
- but correct. (I am not going to quote the correct one here.)
-
- In article <19479@fritz.filenet.com> scotth@felix.filenet.com (Scott Hopson)
- >*foo[] is a pointer to an array
- >**foo is a pointer to a pointer
-
- The latter is correct; the former is not. Given a declaration of the
- form
-
- T *x[];
-
- (where T is some type), x will probably have this type:
-
- declare x as array UNKNOWN_SIZE of pointer to T
-
- But if this is a format parameter declaration---we are obviously missing
- some context, so we do not know whether this is the case---then x will
- have this type instead:
-
- declare x as pointer to pointer to T
-
- The reason is, as usual, an outgrowth of The Rule about arrays in C.
- This Rule states that:
-
- Whenever an object of type `array N of T' appears in a value
- context, it is converted to a value of type `pointer to T',
- pointing to the first element of that array, i.e., the one with
- subscript 0. (N must be some integer constant or the special
- `unknown size' marker, and T must be some valid type.)
-
- So if we write:
-
- extern int i[];
-
- void f(a) char a[]; { ... }
-
- then `i' is declared as an `array UNKNOWN_SIZE of int', but `a' is not
- an array at all. All actual function arguments are, by definition,
- *values*, not objects---if you try, in C, to pass an object to a
- function, you simply pass the value of that object. But a formal
- parameter declaration, such as that for `a' here, declares an object,
- not a value.
-
- Well, obviously there is a conflict here: we claim `a' is an object of
- type `array UNKNOWN_SIZE of char', but it must come directly from some
- value, and The Rule guarantees that there are no array values. Dennis
- Ritchie decided that the answer to this dilemma was to adjust the type
- of `a', silently, in the compiler. The compiler *knows* `a' cannot be
- an array, so it changes `array N of T' to `pointer to T' and then carries
- on as if you had written that in the first place.
-
- Thus, the compiler adjusts the type, changing `array UNKNOWN_SIZE of char'
- to `pointer to char', and this is *exactly the same* as if we wrote
- instead:
-
- void f(a) char *a; { ... }
-
- Thus, there are places (formal parameter declarations) where `T *foo[]'
- and `T **foo' are identical in meaning. I advise against using the
- array notation in these cases. It generally adds more confusion than
- clarity. Note that formal parameters are the ONLY place where these
- are equivalent: at all other times, confusing `array N of T' with
- `pointer to T' will get you in trouble.
-
- In article <20900024@inmet> richw@inmet.camb.inmet.com writes:
- >> char *foo = "abc";
- >> char *foo[] = "abc";
- >> char foo[] = "abc";
- >> char foo[4] = "abc";
-
- >First, let me give these "foo"s unique names:
-
- (this is a good idea)
-
- > char *fooA = "abc";
- > char *fooB[] = "abc";
- > char fooC[] = "abc";
- > char fooD[4] = "abc";
- >
- >Here's a way of rewriting these which might make things clearer:
- >
- > static char literal [] = { 'a', 'b', 'c', '\0' };
- >
- > /* "literal" is now a constant which equals the address */
- > /* of the first element of an initialized, 4-element */
- > /* "char" array */
- >
- > char *fooA = literal;
- > char *fooB[] = (char **) literal;
- > #define fooC literal
- > #define fooD literal
- >
- >Thus, "fooC" and "fooD" are identical; both are constants which equal the
- >address of the "literal" array's first element.
-
- This is mostly right. The initialization for fooB[], however, is
- illegal (as it was in the original example). If the original version
- is repaired (by adding {} around "abc"), one correct translation is:
-
- char *fooB[] = { &literal[0] };
-
- In addition, it is somewhat misleading to use the same `literal' for
- all four, but it is just as misleading to use a different one for each:
- The C language does not say which, if any, identical string contants
- live at the same address and which do not. (It also obscures details
- as to whether string constants are read-only; this again is up to the
- compiler.) That is, given:
-
- char *p1 = "abc", *p2 = "abc";
-
- the C language leaves unspecified whether p1==p2 or p1!=p2. Either
- is acceptable. If p1==p2, and if string constants are writable, then
- changing *p1 will also change *p2. If string constants are read-only,
- the possibility of p1==p2 is less important.
-
- >Note that the "4" in the "char fooD[4]" declaration is entirely unnecessary;
- >what's interesting are these cases:
- >
- > fooD[3] = "abc"; /* Illegal ! "fooD" is too small */
- >
- > fooD[5] = "abc"; /* "fooD" is the constant address */
- > /* of the first element of a 5- */
- > /* element "char" array whose 5-th */
- > /* element is uninitialized */
-
- (I assume the word `char' is supposed to appear in front of each of these.)
- In ANSI C,
-
- char s[3] = "abc";
-
- is explicitly legal, and it makes s[] contain the three characters
- 'a', 'b', 'c', omitting the final '\0'. In Classic C it is illegal.
- In both Classic and New C, when
-
- char s[5] = "abc";
-
- is legal, it makes s contain the five characters 'a', 'b', 'c', '\0',
- '\0'. (The initialization is legal in Classic C only if `s' has static
- duration, while in ANSI C it is always legal.) That is, the fifth
- element of s (or fooD), s[4] (or fooD[4]), *is* initialized, to '\0'.
-
- Note that this is *not* what you get if you use strcpy(). Strcpy()
- and explicit initialization are different.
-
- >Finally, note that "char *fooB[]" represents a pointer to an array, where
- >each element of the array is itself a pointer to "char". This is a
- >*different* type than the type of "abc", i.e. a pointer to "char". I'm
- >surprised my C compiler accepted for "fooB" declaration. In any case,
- >I would never write such a declaration...
-
- Nearly right: fooB is not a pointer to an array; it is an object of
- type `array 1 of pointer to char'. The initialization is indeed
- illegal, and a compiler that silently accepts it is non-conformant.
- --
- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
- Berkeley, CA Domain: torek@ee.lbl.gov
-