dhesi@bsu-cs.UUCP (06/12/87)
The April 1987 issue of DEC Professional magazine has this interesting
example of possible obfuscation in C.
What is the meaning of the following declaration?
static char (*b)[6];
The compiler and lint checker used by the magazine columnist seem to
treat the declaration of b as equivalent to char ** but the following
strange things happen.
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."
He goes on to ask if other C compiles do the same thing, and wonders
if Ritchie had this in mind when he defined the language.
On our 4.3BSD system, the above code printed the character sequence
"Hello\n^H^T\n" (without quotes). On my UNIX PC (software revision 3.0)
it printed "Hello\n\n".
--
Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
davew@whuxm.UUCP (WONNACOTT) (06/12/87)
In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > The April 1987 issue of DEC Professional magazine has this interesting > example of possible obfuscation in C. > > What is the meaning of the following declaration? > > static char (*b)[6]; > Parenthesis can be used in declarations to alter the meaning of the declaration. Baiscly, you read the part of the declaration in parenthesis first, followed by whats outside of the parenthesis. For example: char *argv[6]; /* [] has higher precedence than *, so argv is an array of 6 pointers to char */ char (*b)[6]; /* now the * is in parenthesis, so we read the * first b is a pointer to an array of 6 chars */ char *gets(); /* () has higher precedence than *, so gets is a function returning pointer to char */ char (*fp)(); /* now the * is in parethesis, so we read it first fp is a pointer to a function returning char */ The compiler and lint seem to > treat the declaration of b as equivalent to char ** but the following > strange things happen. "seem to" is right -- just as char *ptr and char array[6] "seem to" be the same to many c novices -- but ptr allocates a pointer and array allocates space for 6 characters. > > main() > { > static char (*b)[6]; /* an unusual declaration */ b should be used to point to an array of 6 characters. > static char a[] = "Hello"; > char *c = a; > char **d = &c; > b = d; /* So b == d ... Watch. */ b is used here to point to a pointer to a character -- not to an array of 6 characters, as it should be used. Perhaps C compilers should catch this sort of abuse of pointers... b = &a; would be better in some sense, but most C compilers assume that you really meant &a[0] if you write &a, and ignore the &, and you get b = a; instead, which is an illegal pointer combination, so you have to put in an explicit cast: b = (char (*)[6]) a; which works (it casts a from type char * into the type of b: pointer to an arrya of 6 chars). Many people find the above code (mine and the original) too ugly to read, and take to using typedef to clarify the situation (a vary good idea, in my opinion): typedef char (* pointer_to_array_of_6_chars)[6]; static pointer_to_array_of_6_chars b; b = (pointer_to_array_of_6_chars) a; In any case, back to what happened in the original and why: > > printf ("%s\n", *d); /* prints "Hello" */ yes -- d is a pointer to a pointer to a character, so *d is a pointer to a character (the H in Hello, to be specific) > printf ("%s\n", *b); /* prints 0 */ The variable b is a pointer to an array of 6 chars, so *b is an array of 6 bytes starting where b points (that is, at the address of c). Arrays in C are passed by passing the address of the first element of the array. So -- since *b is an array of 6 characters starting with the first byte of the pointer c, C will pass the address of the variable c, not the address of the variable a. b------b c------c a------a | | / | |<-- | H | | | | | | | | e | | |----->| | |--+---->| l | | | | | | | | l | b------b | c------c | | o | | d------d | | \0 | | | | | a------a \ | | | | |--' | | d------d I've done my best to draw this with the limited capabilities of an ASCII terminal: Assuming 4 byte pointers, and that c and d happen to be contiguous on the stack. Try to look at the above paragraph and the diagram at the same time (they'll both fit on the screen together). b and d point to the same address -- the beginning of c. But *d is a character pointer located there, and *b is a 6 byte array located there. *d (which == c) will print the string "Hello". *b (the array of 6 bytes encompassing the variable c and some of the bytes of d), will not print anything sensible. You would get the same printout from printf("%s\n", &c); > > 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. just as you cannot assign a new value to an array name. > 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." note that the above is true in other cases as well: int *b; float f = 1.234; float *d = &f; b = d; /* illegal on modern compilers without a cast, but similar to the example above in spirit */ /* in this case, *b != *d */ > > He goes on to ask if other C compiles do the same thing, and wonders > if Ritchie had this in mind when he defined the language. Other C compilers do the same thing -- its consistent with the C treatment of arrays. The trick to understanding it is to remember that b is a pointer to an array of 6 characters, not a pointer to a pointer. > > -- > Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi I hope this has helped the original poster and any others who didn't understand what was going on in the original article. -- David Wonnacott "They said Van Gogh was crazy, didn't they?" whuxm!davew or rz3bb!davew AT&T Corporate Education The above opinions are not necessarily those of AT&T, or of anyone else anywhere
rjnoe@uniq.UUCP (Roger J. Noe) (06/12/87)
In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > What is the meaning of the following declaration? > static char (*b)[6]; > The compiler and lint checker used by the magazine columnist seem to > treat the declaration of b as equivalent to char ** . . . But it's obviously NOT equivalent. You could make a pretty good case that lint (if not the compiler as well) should complain about the "b = d;" pointer assignment statement, but that does not excuse the programmer from understanding the difference between b and d. (Try passing b to a function which expects a "char **" argument and see what happens. You should see lint complain about a parameter inconsistency and it should compile and execute correctly.) As for the example program: > 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 */ > } change the final printf() call to "printf("%s\n", *(char **)b);" and everything should work just as you'd expect. If b is not "char **" and you dereference it, you're not going to get a "char *", which is what you'd need to see this do what is desired. > . . . . 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." Incorrect. The values of b and d are identical, but the programmer has told the compiler that they do not point to the same types. The use of the static (internal) storage class has much less to do with what is going on here. All that it does is prevent b from being automatic while still restricting its scope to main(). The problem is that "*b", as the program was written, denotes an aggregate array of 6 characters, not a pointer to them. The array cannot be passed as a function parameter. > He goes on to ask if other C compiles do the same thing, and wonders > if Ritchie had this in mind when he defined the language. Yes, I suspect most compilers will do the same thing. I think a C compiler that worked as the columnist seemed to anticipate would have to be a broken compiler, or it implements something other than C language. As far as I can tell the compiler, lint, and DMR are all correct as far as this issue is concerned. I think the referenced publication should look for a programmer who knows his/her/its C better than this one. Or maybe change their name to "Unprofessional". -- long tloc = 507314353L; Roger Noe ihnp4!uniq!rjnoe Uniq Digital Technologies rjnoe@uniq.UUCP 28 South Water Street +1 312 879 1566 Batavia, Illinois 60510 41:50:56 N. 88:18:35-
decot@hpisod2.UUCP (06/13/87)
> What is the meaning of the following declaration? > > static char (*b)[6]; b has static storage and is a pointer to a (pseudo-named) array of 6 characters (not to the first character of an array, mind you, but to something which may be used in any context where a name of an array is allowed). Initially, b is a null-pointer. sizeof(*b) is 6*sizeof(char). For instance, ++b increases the pointer address by six characters. *b is equivalent to the name of a particular array, and since it has no initial value, it never will. > The compiler and lint checker used by the magazine columnist seem to > treat the declaration of b as equivalent to char ** but the following > strange things happen. Not really, since sizeof(*b) is not sizeof(char *), although (*b)[0] is a character. > main() > { > static char (*b)[6]; /* an unusual declaration */ > static char a[] = "Hello"; > char *c = a; > char **d = &c; > b = d; /* So b == d ... Watch. */ This statement should have encountered an error, since b and d are not of compatible types. > 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." This is accurate. Dave Decot hpda!decot
msb@sq.UUCP (06/14/87)
Rahul Dhesi (dhesi%bsu-cs@iuvax.UUCP) writes: > What is the meaning of the following declaration? > > static char (*b)[6]; b is what is commonly called a "pointer to array of 6 chars", but better described as "pointer to arrays of 6 chars" (each). b is static. When C sees a function definition beginning like this: func(x, b) char x[], b[][6]; { the declaration is translated* (only because these are function parameters and therefore not allowed to really be arrays) to char *x, (*b)[6]; The object you describe is of the same type, but static. > The compiler and lint checker used by the magazine columnist seem to > treat the declaration of b as equivalent to char ** which is isn't. > main() > { > static char (*b)[6]; /* an unusual declaration */ > static char a[] = "Hello"; > char *c = a; > char **d = &c; So far so good, c and *d are both pointers-to-character (or as I prefer, pointers-to-characters) indicating the H in "Hello". > b = d; /* So b == d ... Watch. */ The two sides are incompatible pointer types, so there really should be a cast here, but I'll get back to that later. Anyway, what this is saying is that the value in d, which is the address of the pointer c, is to be stuffed into b. Well, what happens when you then try *b? It treats the 6 bytes beginning at the variable c as if they were an array of characters! No wonder different values are printed on different machines. What the coder presumably meant is: b = *d; NOW *b and *d are pointing to the same place -- but to a different number of characters. *d points to the H, *b to the whole array "Hello". Further indexing through either pointer does produce a char, so they are similar in that respect, but not identical just the same. Remember that *x is the same as x[0], and consider: d is a pointer to pointer to char(s) which points to c d[0] is a pointer to char(s), equal to c d[0][0] is the char 'H', same as c[0] d[0][1] is the char 'e', same as c[1] d[1] would be garbage obtained by treating the memory location following d as a pointer b is a pointer to array(s) of 6 chars b[0] is an array of 6 chars containing "Hello" b[0][0] is the char 'H' b[0][1] is the char 'e' b[1] would be garbage obtained by treating the memory location following the "Hello" bytes as an array b[1][0] would be the char after the closing null in "Hello" (if there is one, rather then running off memory) The printf of *b is legitimate, or would be if b had a reasonable value; since *b has an array-of-chars type it is converted to pointer-to-char(s) on being passed to a function. Now about that cast. In ANSI C as currently drafted, it is a requirement that assignments involving pointer conversion be explicitly specified by cast. (That is, the "(type)" syntax.) Some modern compilers at least warn about such assignments now. Here, *d has type "pointer to char", while b is what I said above; therefore b = *d involves a conversion and should really be written b = (char (*)[6]) *d; > 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." This starts to make no sense. It is true that for a particular value of b, it is impossible to assign to *b, but only because *b has array type. (Assigning to *d would be assigning to c, on the other hand). But it is certainly possible to assign to b again, or to **b while b is held constant. If the columnist is in the habit of confusing d and *d, I would suggest that the column probably isn't worth reading. (But I haven't seen it myself). Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb #define MSB(type) (~(((unsigned type)-1)>>1)) *For my opinions on this alleged syntactic sugar, see Karl Heuer's article. I agree with him that it should be eliminated in the new syntax. But that's another story.
guy@sun.UUCP (06/14/87)
> > b = d; /* So b == d ... Watch. */ > > This statement should have encountered an error, since b and d are not > of compatible types. In fact, if you fix a bug in the type-checking code, PCC will issue an error for this. The compiler running on my machine (basically the SunOS 3.2 compiler) prints "foo.c", line 7: warning: illegal pointer combination The problem is that the routine "chkpun" in "mip/trees.c" is extremely bogus. It certainly checks for something, but that something certainly isn't any reasonable form of type-equality - for one thing, it treats pointers and arrays as equivalent. (And no, that isn't necessary; array-valued expressions are converted to pointer-valued expressions, according to the ANSI C standard, and this isn't too bad a description of what C does according to K&R. By the time you get to "chkpun", the conversion has already been performed, so you don't even have to treat them as equivalent at the outermost level of the declaration; treating them as equivalent at any other level is, of course, completely wrong.) Here's the fix. The "diff -c" comes from our compiler, so I don't guarantee that the fix applies exactly as is to other flavors of PCC (or PCC2, QCC, RCC, etc.), but it shouldn't be too far off. Note that there are zillions of other similar things wrong with the PCC front end (many of which are still wrong in PCC's successors); properly checking for errors and properly reporting errors didn't seem to be considered important, which I guess isn't too surprising since PCC was an experiment with code-generation technology, not parsing technology. *** /tmp/geta5443 Sun Jun 14 13:31:34 1987 --- /tmp/getb5443 Sun Jun 14 13:31:39 1987 *************** *** 717,747 **** } } else { ! d1 = p->in.left->fn.cdim; ! d2 = p->in.right->fn.cdim; ! for( ;; ){ ! if( t1 == t2 ) {; ! if( p->in.left->fn.csiz != p->in.right->fn.csiz ) { ! werror( "illegal structure pointer combination" ); ! } ! return; } ! if( ISARY(t1) || ISPTR(t1) ){ ! if( !ISARY(t2) && !ISPTR(t2) ) break; ! if( ISARY(t1) && ISARY(t2) && dimtab[d1] != dimtab[d2] ){ ! werror( "illegal array size combination" ); ! return; } ! if( ISARY(t1) ) ++d1; ! if( ISARY(t2) ) ++d2; } - else break; - t1 = DECREF(t1); - t2 = DECREF(t2); } ! werror( "illegal pointer combination" ); } - } #ifdef VAX --- 711,748 ---- } } else { ! /* ! * type is "ptr to (...)" or "array of (...)"; walk through ! * the type constructors in the TWORD and check dimensions ! * of any array parts. They have to be the same in order ! * for the types to be equivalent. ! * ! * NOTE: this code assumes that a reference to an item of ! * array type has already mapped into a value of pointer ! * type. Also, note that within a composite type constructor, ! * PTR and ARY are NOT equivalent. ! */ ! if( t1 == t2 ) { ! if( p->in.left->fn.csiz != p->in.right->fn.csiz ) { ! werror( "illegal structure pointer combination" ); } ! d1 = p->in.left->fn.cdim; ! d2 = p->in.right->fn.cdim; ! for( ;; ){ ! if( ISARY(t1) ){ ! if( dimtab[d1] != dimtab[d2] ){ ! werror( "illegal array size combination" ); ! return; ! } ! ++d1; ! ++d2; } ! else if( !ISPTR(t1) ) break; ! t1 = DECREF(t1); } } ! else werror( "illegal pointer combination" ); } } #ifdef VAX -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
daveb@geac.UUCP (Dave Brown) (06/15/87)
In article <2550018@hpisod2.HP.COM> decot@hpisod2.UUCP writes: >> What is the meaning of the following declaration? >> >> static char (*b)[6]; > An old-fashioned trick for reading C declarations is to read the implementation out in words, from the inside out: there is a word called b which points to an array of 6 characters, and is static. Reading it left-to-right usually causes confusion: a static char star b of 6 ... uh... er... Huh? --dave
karl@haddock.UUCP (Karl Heuer) (06/15/87)
>In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: >>[after declaring char (*b)[6]; char **d;] >> b = d; /* So b == d ... Watch. */ In article <535@whuxm.UUCP> davew@whuxm.UUCP (WONNACOTT) writes: >[explains why this is a type mismatch, then says] > b = &a; >would be better in some sense, but most C compilers assume that you >really meant &a[0] if you write &a, and ignore the & ... Fortunately, X3J11 has recognized this translation as bogus. In ANSI C, "&a" means what it says: the address of "a" (with type "pointer to one or more arrays", not "pointer to first element of array"). (A side effect of the bogus translation is that, given char a[M][N], "&a[i]" doesn't work in most pre-ANSI compilers -- you must instead write "a+i".) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
throopw@dg_rtp.UUCP (06/16/87)
> 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 <stdio.h> 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 <the-known-world>!mcnc!rti!dg_rtp!throopw
mick@auspyr.UUCP (06/16/87)
>> In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: Rahul started this all off. If you are not familiar with it, hit 'n' now. Here is one response: >in article <304@uniq.UUCP>, rjnoe@uniq.UUCP (Roger J. Noe) says: > still restricting its scope to main(). The problem is that "*b", as the > program was written, denotes an aggregate array of 6 characters, not a > pointer to them. The array cannot be passed as a function parameter. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Think again, squire. > I think the referenced publication should look for a programmer who knows > his/her/its C better than this one. Or maybe change their name to > "Unprofessional". > Roger Noe ihnp4!uniq!rjnoe > Uniq Digital Technologies rjnoe@uniq.UUCP I read the original article in April DEC Professional magazine, and thought it was an excellent discussion of C pointers. It was a little terse at times, but if you didn't understand it the first time, then re-read it until you do. Now then, Roger, did you read the article, or are you taking the clippings in the original posting out of context? When I saw Rahul's posting, I knew we were in for another round of "leap before you look postings" (isn't it wonderful what you read in this newsgroup?), but I just couldn't let this one pass by. Recommendations: 1) (to all) Read the article if you can get a copy. 2) (to Roger) Consider a name change. -- ---- Mick {sdencore,necntc,cbosgd,amdahl,ptsfa,dana}!aussjo!mick {styx,imagen,dlb,gould,sci,altnet}!auspyr!mick
rjnoe@uniq.UUCP (06/17/87)
In article <6658@auspyr.UUCP>, mick@auspyr.UUCP (Mick Andrew) writes: > >in article <304@uniq.UUCP>, rjnoe@uniq.UUCP (Roger J. Noe) says: > > . . . The array cannot be passed as a function parameter. > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > Think again, squire. Until some real standard becomes established and generally accepted the next best thing we have to a definition of the C language is found in Kernighan and Ritchie, 1978. From section 1.8 "Arguments - Call by Value" (bottom of page 24): "When the name of an array is used as an argument, the value passed to the function is actually the location or address of the beginning of the array. (There is *no* copying of array elements.)" [emphasis in the original] Similarly in section 5.3 "Pointers and Arrays" (pp. 94-95). Also in section 10.1 "External function definitions" (p. 205): "Also, since a reference to an array in any context (in particular as an actual parameter) is taken to mean a pointer to the first element of the array, declarations of formal parameters declared `array of ...' are adjusted to read `pointer to ...'." Even when enums were added in 1978 and restrictions on structs were relaxed to permit assignment, return by function and passing as arguments, there was no change in C to pass arrays as function arguments. Perhaps some C pro- grammers are accustomed to compilers which do allow this but they are very nonstandard C compilers. I should think that every novice C programmer would know you cannot pass an array as a function argument. All you can do is pass a pointer to one of its elements. So when you've got "char (*b)[6];" and you try to pass "*b" to a function, the compiler knows it cannot pass an actual "char [6]" but has to take the address of it and pass the pointer. In effect what happens is to pass "&(*b)" or just "b". This is why the value of "b" is passed whether one writes "b" or "*b" as the actual parameter. It's much like having "char x[6];" and passing "x" as an argument. > > I think the referenced publication should look for a programmer who knows > > his/her/its C better than this one. Or maybe change their name to > > "Unprofessional". > Now then, Roger, did you read the article, or are you taking the clippings > in the original posting out of context? It must be one of Murphy's laws that whenever you omit a ":-)" from an article, somebody will get very offended and flame back at you. I did not read the original article in The DEC Professional until after I posted mine. What prompted me to add a bit of sarcasm was the exceedingly opaque and almost completely false quote from Rahul Dhesi's posting: > In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > . . . . 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." What's wrong with this is that these words are not those of the columnist, Rex Jaeschke, but of the "college level" teacher of C who wrote to Jaeschke in the first place. My snide remark, based on the posting that started all this in comp.lang.c, was misplaced and undeserved as far as Jaeschke and The DEC Professional are concerned. I retract the statement and apologize to anyone who was offended by it. HOWEVER, had a publication of this caliber employed a writer for a column of the same nature as "Let's C Now", holding himself forth to be a professional C programmer, and had he made the statement above, I would not retract the comment I made in response. If such a situation were to occur, the remark would be deserved. I'm glad Jaeschke doesn't identify the writer of the letter; I truly do not want to know where this person teaches "college level" C language. > When I saw Rahul's posting, I knew we were in for another round of > "leap before you look postings" . . . It's funny, Mick, but yours was the first such posting I saw. It's also the first one that failed to make any technical contribution to the issue. > Recommendations: > 1) (to all) Read the article if you can get a copy. I concur. It's not always easy to get a copy, but Jaeschke's articles on C have been and continue to be worthwhile. > 2) (to Roger) Consider a name change. > ---- > Mick In fact I considered a name change. I thought either Mick or even Andrew might be interesting choices, but I was afraid people would think I was an idiot. :-) I had the courtesy not to mention the name of the publication when being sarcastic. Courteous netters don't make disparaging remarks *at* other netters, especially not in a "technical" newsgroup. And they do apologize when they make mistakes. Consider it, Mick Andrew. -- long tloc = 507314353L; Roger Noe ihnp4!uniq!rjnoe Uniq Digital Technologies rjnoe@uniq.UUCP 28 South Water Street +1 312 879 1566 Batavia, Illinois 60510 41:50:56 N. 88:18:35 W.
dhesi@bsu-cs.UUCP (06/18/87)
In article <306@uniq.UUCP> rjnoe@uniq.UUCP (Roger J. Noe) writes: >What prompted me to add a bit of sarcasm was the exceedingly opaque and >almost completely false quote from Rahul Dhesi's posting: > >> In article <761@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: [...exceedingly opaque and almost completely false quote omitted...] > >What's wrong with this is that these words are not those of the columnist, >Rex Jaeschke, but of the "college level" teacher of C who wrote to Jaeschke >in the first place. Roger Noe is correct. I was quoting the columnist quoting somebody else. -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
peter@sugar.UUCP (Peter DaSilva) (06/19/87)
I'm holding the line-eater for ransom somewhere in lower slobbovia! In article <2117@dg_rtp.UUCP>, throopw@dg_rtp.UUCP (Wayne Throop) writes: > > 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; except that static char (*b)[6] doesn't actually allocate the 6 bytes. Better would be typedef char mytype[6]; static mytype *b;
throopw@xyzzy.UUCP (Wayne A. Throop) (06/27/87)
> peter@sugar.UUCP (Peter DaSilva) >> throopw@xyzzy.UUCP (Wayne Throop) >> [ static char (*b)[6]; is a ] >> 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; > except that static char (*b)[6] doesn't actually allocate the 6 bytes. Well, now, I had already said this in the text immediately following, which Peter removed. To quote myself: Note that the array of characters in the first example does *not* have static scope (and is in fact not even allocated). > Better would be > typedef char mytype[6]; > static mytype *b; But this misses the entire point. Peter has defined a type that is exactly the same as the original declaration of b with type (char (*)[6]). The point was to show that a simple (char *) could indicate the same memory layout, while (obviously) not being the same type. Again, the typedef just above does indeed indicate the same memory layout. But it is *exactly* the same type, and does nothing to clarify the standard confusion, in particular the erronious opinion that (char **) and (char (*)[6]) indicate the same memory structure. It is important to note that they do NOT. -- Adam and Eve had many advantages, but the principal one was, that they escaped teething. --- Pudd'nhead Wilson's Calendar (Mark Twain) -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw