Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!rutgers!gatech!mcnc!rti!dg_rtp!throopw From: throopw@dg_rtp.UUCP Newsgroups: comp.lang.c Subject: Re: static char (*b)[6]; /* an unusual declaration */ Message-ID: <2117@dg_rtp.UUCP> Date: Mon, 15-Jun-87 18:38:57 EDT Article-I.D.: dg_rtp.2117 Posted: Mon Jun 15 18:38:57 1987 Date-Received: Wed, 17-Jun-87 05:38:57 EDT References: <761@bsu-cs.UUCP> Lines: 126 > dhesi@bsu-cs.UUCP (Rahul Dhesi) Others have already responded, but I'll throw in a slightly different viewpoint, covering the same material from my own perspective, under the principle that "You can't explain too much about pointers and arrays in C." > What is the meaning of the following declaration? > static char (*b)[6]; Static pointer to an array of six characters. The same memory layout (though *not* the same type) can be had by the declarations: char q[6]; static char *r = q; The b from the first example and the r from the second are pointing at memory which has the same layout, though operations (such as indirection or arithmetic) on these two pointers (a and r) will give very different results. Note that the array of characters in the first example does *not* have static scope (and is in fact not even allocated). The pointer b has static scope. > main() > { > static char (*b)[6]; /* an unusual declaration */ > static char a[] = "Hello"; > char *c = a; > char **d = &c; > b = d; /* So b == d ... Watch. */ > printf ("%s\n", *d); /* prints "Hello" */ > printf ("%s\n", *b); /* prints 0 */ > } > > Other code fragments omitted. The columnist continues, "...This means > that *b is a constant and while (b) can be modified, *b never will > change its original value. Thus, setting b = d does not mean that > *b == *d. Also, while *b is treated as a constant (unchangeable), the > value of b can vary." The part of the first quoted sentence after the "thus" is correct, but the rest of the quoted material is flat wrong. First, let's see why what follows the "thus" is correct. b and d point to different types, similar to the situation where b is of type (float *) and d is of type (int *). Let's say that we have this code fragment: { float *b; int i=1, *d = &i; b = d; ... } Now, at the point of the omitted code indicated by "..." above, can we be sure that *b == *d, just because we set b = d? No, we cannot. A similar situation exists where { char (*b)[6], *p = "str", **d = &p; b = d; ... } This says that b points to an array, while d points to a pointer. References to *b, the array pointed to by b, attempt to interpret the pointer that d points to as an array of characters. Next, let's see why the rest is bogus. First of all, *b is not a constant. It is true that cannot be assigned to, but that does *not* mean that it is a constant. It is, according to draft X3J11, an unmodifiable lvalue, but it is *not* a constant. Second, it is true that b can be modified, but it is *not* true that *b will never change its original value. In fact, the value of *b will (potentially) change whenever the value of b changes. (It might not change when b changes... b might point to an identical array, for example.) It all comes from thinking that pointers and arrays are the same thing, which they most emphatically are *NOT*. A local typechecker had this to say about the above example: 8 Use of undeclared identifier "printf" 7 inconsistent types discovered (= (:IDENTIFIER b :STATIC ... ) (:IDENTIFIER d :AUTO ... )) Types are: (:POINTER_TO (:ARRAY_OF (:CHAR) 6 ())) and: (:POINTER_TO (:POINTER_TO (:CHAR))) 1 missing return statement at bottom of function (:IDENTIFIER main :EXTERN ... ) 3 errors While lint had this to say: (10) warning: main() returns random value to invocation environment function returns value which is always ignored: printf We can see that both tools caught the fact that main didn't return anything, and both mentioned something about printf (though they are not really catching quite the same problem). The most glaring point is that lint totally missed the big error in this program, the assigning of a pointer to a pointer onto a variable of incompatible type. See Guy Harris's posting in this subject line for a description of why lint doesn't catch this bug. The moral: tools don't always know what they purport to know, but it helps to run a variety of checking tools early and often. (Many folks disagree with this moral, of course...) An alternative way to fix the example to make it type-correct under draft X3J11: #include main() { static char a[] = "Hello"; char (*b)[6], *c, **d; b = &a; c = a; d = &c; /* both of these should now print "Hello" */ printf ("%s\n", *d); printf ("%s\n", *b); return( 0 ); } Sadly, many current tools, including lint and some PCCs, will complain or botch the assignment to b, or taking the address of a, or both. -- You can't put too much coolant in a nuclear reactor. --- Ed Asner in a sketch on SNL -- Wayne Throop !mcnc!rti!dg_rtp!throopw