SERRER@NRCM3.NRC.CA (Martin Serrer) (11/17/90)
Hello c'ers, I am trying to define and access a data structure 'zero' which contains an array of structures 'one' , the size of which is not know until run time. No problem right? When I compile this code I get warnings about 'illegal zero sized structure member'. The code runs properly but I'm worried about the warnings. What rules am I breaking?? (see the evidence below) Please be gentle as I am still learning about c. Thanks in advance... Martin BTW. this is on a 4D50/GT IRIX 3.2 -------------------------------evidence----------------------------------------- % cat t.c #include <stdio.h> typedef struct { int a; int b; } TINY; typedef struct { TINY two; int c; } SMALL; typedef struct { SMALL *one[]; int f; } BIG; BIG *zero; main() { zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) ); zero->f = 1; zero->one[0].c = 2; printf("--- %i\n",zero->f); printf("--- %i\n",zero->one[0].c); } % cc t.c ccom: Warning: t.c, line 18: illegal zero sized structure member: one } BIG; --^ ccom: Warning: t.c, line 28: struct/union or struct/union pointer required zero->one[0].c = 2; ---------------^ ccom: Warning: t.c, line 29: struct/union or struct/union pointer required printf("--- %i\n",zero->one[0].c); -------------------------------^ % t --- 1 --- 2 +-----------------------------------------------------------------------------+ | Martin Serrer Systems Lab., Bldg. M2, Montreal Rd.| | 613-993-9442 National Research Council of Canada,| | serrer@syslab.nrc.ca Ottawa, Ontario, Canada K1A-0R6 | +------------------- Software Rusts, Rust never Sleeps -----------------------+
karron@KARRON.MED.NYU.EDU (11/18/90)
> I am trying to define and access a data structure 'zero' which contains an >array of structures 'one' , the size of which is not know until run time. No If I understand these things correctly ( and I may still not have it right) your reference SMALL *one[] is the same as SMALL **one . You have double indirection, and in non static code, the meaning of what you actually allocate is a pointer to a pointer array pointing to an allocation of small. This is pointed out in the K & R ansi c book, page 107 and following. Get my point ? When you allocate zero, *zero will point to an allocation consisting of { a pointer to a pointer of SMALL, int f}. You have not allocated storage for small. You need another malloc statment like this: zero->one=calloc(n,sizeof(SMALL)); Now you have allocated some space for the thing pointed to at one. int n is the number of adjacent elements of SMALL you allocate. You would reference them as zero->one[m].two.a; I use calloc to make certain that the allocated area is zero filled, and you don't need to cast the return value. >problem right? When I compile this code I get warnings about 'illegal zero >sized structure member'. The code runs properly but I'm worried about the >warnings. What rules am I breaking?? (see the evidence below) I don't know how the compiler can know this at compile time, but it sometimes is smarter than I am. I have had some problem with the . structure element offset operator and the -> pointer operator. I think that somthing is wrong in my understanding or the compiler, but the two are almost interchangable in too many contexts. > > Please be gentle as I am still learning about c. >Thanks in advance... Martin > I am still figuring this out. I have to wrangle the code to get it to pass the compiler in ways I am not certain of. >-------------------------------evidence---------------------------------------- - >% cat t.c >#include <stdio.h> > >typedef struct { int a; int b; } TINY; >typedef struct { TINY two; int c; } SMALL; >typedef struct { SMALL *one[]; int f; } BIG; >BIG *zero; > >main() >{ zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) ); This is bad practice. Your code only works by accident, as best as I can see. You need two pointers, not one. You need a pointer for zero, and a pointer for one. I don't see how you think you can get both allocated at once and not know the address for the other. > zero->f = 1; > zero->one[0].c = 2; > printf("--- %i\n",zero->f); > printf("--- %i\n",zero->one[0].c); >} > >% cc t.c >ccom: Warning: t.c, line 18: illegal zero sized structure member: one > } BIG; > --^ Here, if you only specified a size for one, then you would allocate space for it with the first malloc. In this setting, perhaps *one[] is NOT the same as **one, and that may or may not be the issue. if you put in *one[10], you would allocate an array consisting of 10 slots for pointers to one. If you want to do it at run time, then you need two mallocs as I show in here. I am not certain of the syntax differences in different settings for **one vs *one[]. >ccom: Warning: t.c, line 28: struct/union or struct/union pointer required > zero->one[0].c = 2; > ---------------^ I get this error message a lot. It us usually fixed by replacing the . operator with the -> operator. My feeling is that the .c should resolve the lvalue of the pointer one[0] to a real value, but the compiler does not aggree with my feeling. DBX allows you to use . and -> interchangeably. This issues needs a higher authority. ccom: Warning: t.c, line 29: struct/union or struct/union pointer required > printf("--- %i\n",zero->one[0].c); > -------------------------------^ Again, see my note above. > >% t >--- 1 >--- 2 I don't know how you get an address for 2, even though it works. Is is not referencing what you think, although you can still store/read its value without a segmentation error. If you used calloc, you probably will get one because your allocated region would be zero filled. A good way to debug this stuff is to step through it with dbx, and look at the addresses and what is stored at the address. It is very educational. > >+-----------------------------------------------------------------------------+ >| Martin Serrer Systems Lab., Bldg. M2, Montreal Rd.| >| 613-993-9442 National Research Council of Canada,| >| serrer@syslab.nrc.ca Ottawa, Ontario, Canada K1A-0R6 | >+------------------- Software Rusts, Rust never Sleeps -----------------------+ > These issues are really important when you have to allocate all of your data structure in shared memory or Arenas. I hope that this help, and that someone can help me with the questions I raised in your code. +-----------------------------------------------------------------------------+ | karron@nyu.edu (mail alias that will always find me) | | Dan Karron | | . . . . . . . . . . . . . . New York University Medical Center | | 560 First Avenue \ \ Pager <1> (212) 397 9330 | | New York, New York 10016 \**\ <2> 10896 <3> <your-number-here> | | (212) 340 5210 \**\__________________________________________ | | Please Note : Soon to move to dan@karron.med.nyu.edu 128.122.135.3 (Nov 1 )| +-----------------------------------------------------------------------------+
moss@brl.mil (Gary S. Moss (VLD/VMB) <moss>) (11/19/90)
In article <032D013E619F0000A3@NRCNET.NRC.CA>, SERRER@NRCM3.NRC.CA (Martin Serrer) writes: |> #include <stdio.h> |> |> typedef struct { int a; int b; } TINY; |> typedef struct { TINY two; int c; } SMALL; |> typedef struct { SMALL *one[]; int f; } BIG; |> BIG *zero; |> |> main() |> { zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) ); |> zero->f = 1; |> zero->one[0].c = 2; |> printf("--- %i\n",zero->f); |> printf("--- %i\n",zero->one[0].c); |> } |> |> % cc t.c |> ccom: Warning: t.c, line 18: illegal zero sized structure member: one |> } BIG; |> --^ You are declaring "one" as an array of unspecified, therefore zero size, declare it as "SMALL **one;" instead. In this context, there is a big difference between the two declarations; the compiler knows how big a "SMALL **" is. |> ccom: Warning: t.c, line 28: struct/union or struct/union pointer required |> zero->one[0].c = 2; |> ---------------^ You must use "->" rather than ".": In the declaration "SMALL *one[];", one is an array of pointers to SMALL types. Therefore, one[0] is a pointer and requires a "->" after it, not a ".". |> ccom: Warning: t.c, line 29: struct/union or struct/union pointer required |> printf("--- %i\n",zero->one[0].c); |> -------------------------------^ Same thing as above. You will also need to allocate storage for "one" separately from "zero": if( (zero = (BIG *) malloc( sizeof(BIG) )) == NULL || (zero->one = (SMALL *) malloc( sizeof(SMALL) * 2 )) == NULL ) { /* ALWAYS check success of malloc(3). */ (void) fprintf( stderr, "No memory available!\n" ); return 1; } Of course, you *could* declare storage for zero like this: BIG zero; Rather than the first call to malloc, and leave your "."s as they are. -Gary