sbigham@dukeac.UUCP (Scott Bigham) (03/23/89)
My annual C question: Is there a particularly glaring reason that the following code should make the compiler unhappy? ------------------- Quick, Robin! The BAT-scissors! ------------------- typedef char **Block; Block b1 ={"this","that"}, b2={"yes","no"}, B[]={b1,b2}; ------------------------------------------------------------------------- It curses at me thusly: "test.c", line 6: warning: illegal pointer combination, op = "test.c", line 6: initialization alignment error "test.c", line 6: warning: illegal pointer combination, op = Fatal error in /lib/comp Status 0210 I thought of changing the first line to "typedef char **Block", but that gave me worse: "test.c", line 4: warning: illegal pointer combination, op = "test.c", line 4: initialization alignment error "test.c", line 4: warning: illegal pointer combination, op = "test.c", line 4: initialization alignment error "test.c", line 5: warning: illegal pointer combination, op = "test.c", line 5: initialization alignment error "test.c", line 5: warning: illegal pointer combination, op = "test.c", line 5: initialization alignment error "test.c", line 6: illegal initialization "test.c", line 6: illegal initialization I'm sure it's quite obvious to everyone but me what's wrong with this. I guess that's what I get for trying to understand C after midnight. Thank you very much for unbefuddling me. sbigham -- Scott Bigham "The opinions expressed above are Internet sbigham@dukeac.ac.duke.edu (c) 1989 Hacker Ltd. and cannot be USENET sbigham@dukeac.UUCP copied or distributed without a ...!mcnc!ecsgate!dukeac!sbigham Darn Good Reason."
sbigham@dukeac.UUCP (Scott Bigham) (03/23/89)
In article <1309@dukeac.UUCP> I wrote: > >typedef char **Block; > >Block > b1 ={"this","that"}, > b2={"yes","no"}, > B[]={b1,b2}; I meant to write: typedef char *Block[]; etc... The second "typedef char **Block;" is right. I really shouldn't be trying to think at this hour. Excuse me, I'm going to go to bed. sbigham -- Scott Bigham "The opinions expressed above are Internet sbigham@dukeac.ac.duke.edu (c) 1989 Hacker Ltd. and cannot be USENET sbigham@dukeac.UUCP copied or distributed without a ...!mcnc!ecsgate!dukeac!sbigham Darn Good Reason."
chris@mimsy.UUCP (Chris Torek) (03/23/89)
In article <1309@dukeac.UUCP> sbigham@dukeac.UUCP (Scott Bigham) writes: >typedef char **Block; > >Block > b1 ={"this","that"}, > b2={"yes","no"}, > B[]={b1,b2}; It does not work because b1, b2, and B[any] have type `pointer to pointer to char' and the first two { ... } lines are not valid initialisers for pointer-to-pointer-to-char, and indeed are not valid initialisers for anything but array-of-pointer-to-char. (The third initialiser would be correct if the first two were not rejected earlier.) The following rerun makes various salient points. From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.lang.c Subject: Re: C Coding Question Date: 16 Aug 86 00:58:44 GMT In many articles many USENET posters assert that >... 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 1st ed. has this to say about it: 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'. The array must not be a global or static 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 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
tim@crackle.amd.com (Tim Olson) (03/24/89)
In article <1309@dukeac.UUCP> sbigham@dukeac.UUCP (Scott Bigham) writes: | My annual C question: | | Is there a particularly glaring reason that the following code should make the | compiler unhappy? | | ------------------- Quick, Robin! The BAT-scissors! ------------------- | | typedef char **Block; | | Block | b1 ={"this","that"}, | b2={"yes","no"}, | B[]={b1,b2}; | ------------------------------------------------------------------------- Unfortunately, there are no anonomous arrays in C, except for strings. You are attempting to create anonomous arrays of character pointers and assign their addresses to the variables b1 and b2. There are a couple of ways to do what you want: If b1 and b2 will always point to the initialized contents, then you should declare them as: typedef char *Static_Block[]; Static_Block b1 = {"this, "that"}, . . If b1 and b2 may point to other data in the future, then you must give a name to the initialized array contents: typedef char **Block; typedef char *Static_Block[]; Static_Block init1 = {"this", "that"}, init2 = {"yes", "no"}; Block b1 = init1, b2 = init2; ________________________________________ That addresses your first problem. Your second problem is the declaration: Block B[] = {b1, b2}; Here you are violating the requirement that initialization values must be constants. I'm not quite sure what you are trying to do with the array B. If you simply want it to hold the same *initial* contents as b1 and b2, then you can use: Block B[] = {init1, init2}; If you want B to "track" the changing values of b1 and b2, then you have to use one more level of indirection: Block *B[] = {&b1, &b2}; The addresses of b1 and b2 are constants, so they can be used in the initialization. -- -- Tim Olson Advanced Micro Devices (tim@amd.com) -- Tim Olson Advanced Micro Devices (tim@amd.com)