🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

6 total messages Started by Philippe Maurisset Wed, 17 Apr 1996 15:46
Q: char **foo, char *foo[], and char foo[][] ?
#5028
Author: Philippe Maurisset
Date: Wed, 17 Apr 1996 15:46
41 lines
1495 bytes
Considering the 3 following declarations:

1 - char **foo;
2 - char *foo[];
3 - char foo[][];

I know that there is a (big !) difference in memory reservation, but I do not know
if foo IS or IS NOT of the same type in these three cases.

To summarize my question :
Is the first one securely usable for casting a variable of the third kind, when
calling a function where it is defined as the second kind ?

Follwing is a description (the 2 functions are in differents sources files) :

myexample()
{
	char foo[MAX_X][MAX_Y];
	...
	myfunc( (char **)foo );
}

void myfunc( char *foo[MAX_X] )
{
...
}

Can anybody help me ? Is it system-dependent ?

Many thanks in advance,

Philippe.

-- 
+-----------------------------+-----------------------------+
| Philippe MAURISSET          |                             |
| Lectra Systemes             | Phil@RD.Lectra.fr           |
| Chemin de Marticot, BP 34   | tel   :     +33 57.97.80.00 |
| 33611 CESTAS Cedex          | direct:     +33 57.97.81.13 |
| FRANCE                      | fax   :     +33 57.97.82.32 |
+-----------------------------+-----------------------------+
Re: Q: char **foo, char *foo[], and char foo[][] ?
#5030
Author: J. Kanze
Date: Thu, 18 Apr 1996 08:59
39 lines
1737 bytes
In article <4l33ok$oo2@Sherlock.lectra.fr> phil@rd.lectra.fr (Philippe
Maurisset) writes:

|> Considering the 3 following declarations:

|> 1 - char **foo;
|> 2 - char *foo[];
|> 3 - char foo[][];

|> I know that there is a (big !) difference in memory reservation, but I do not know
|> if foo IS or IS NOT of the same type in these three cases.

They are definitly not the same type, however...

|> To summarize my question :
|> Is the first one securely usable for casting a variable of the third kind, when
|> calling a function where it is defined as the second kind ?

|> Follwing is a description (the 2 functions are in differents sources files) :

|> myexample()
|> {
|> 	char foo[MAX_X][MAX_Y];
|> 	...
|> 	myfunc( (char **)foo );
|> }

|> void myfunc( char *foo[MAX_X] )
                ^^^^^^^^^^^^^^^^

Because it appears as a function parameter, this is actually a
declaration of a char**, and not a char*[].

So in fact, you have no type incompatibility to deal with.
-- 
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
                            -- Beratung in industrieller Datenverarbeitung
Re: Q: char **foo, char *foo[], and char foo[][] ?
#5031
Author: James Carlson
Date: Thu, 18 Apr 1996 12:05
93 lines
4831 bytes
In article <4l33ok$oo2@Sherlock.lectra.fr>, phil@rd.lectra.fr (Philippe Maurisset) writes:
|> Considering the 3 following declarations:
|> 
|> 1 - char **foo;
|> 2 - char *foo[];
|> 3 - char foo[][];
|> 
[...non-working example deleted...]
|> Can anybody help me ? Is it system-dependent ?

No, it's not system-dependent, but it is context-specific.

There are some rules you can follow.  When you define a simple array
(all []'s, like foo[3][9]), you can refer to it in prototypes either as
fully-dimensioned (all []'s with constant values, like foo[3][9]), or
with the first dimension elided (all but first [] with constant, like
foo[][9]), or even as a simple pointer (like *foo or foo[]), although
the dimensioning will be lost and the elements will appear as a single-
dimension array (27 elements in this case).  You may not refer to it as
"*foo[]", either as an argument declarator or in an "extern" in a
separate file.

When you create an array of pointers (like *foo[3][2]), you can refer to
it in prototypes either as the same type of pointer (*foo[3][2] again),
or with the first dimension elided (*foo[][2]), or even as a simple
pointer (**foo), though, again, you drop back to single-dimension.

The pattern here is that the first set of brackets ([]) translate into
one level of "*" in the function argument declaration, but additional
levels of brackets do NOT add "*"s to the function argument.  Thus,
char foo[1000] and char foo[10][10][10] are stored in exactly the same
internal format, and can be referred to in a function argument list as
foo[1000], foo[], foo[][10][10], foo[10][10][10], or *foo.

One more wrinkle to consider is that when declaring a variable, *foo is
different from (and incompatible with) foo[], but when passed as an
argument, they are identical.  Thus, when making "extern" statements to
refer to a variable (rather than passing as an argument list), do not
follow the above rules, but rather declare variable exactly as
originally defined.  The only exception to that rule is that you may
still elide the first dimension in an extern (like foo[][9]), but,
again, you cannot choose to call this "*foo" in the extern.

Instead of trying to argue about the abstract types, let's instead look
at a hypothetical example on an imaginary machine.

	char **var1;
	char *var2[5];
	char var3[3][2];

These three declarations could produce the following assembly code for
our hypothetical machine (assuming 32-bit architecture, nice, simple
system):

		.bss	var1,4		# single char** pointer, 4 bytes
		.bss	var2,20		# five char* pointers, 20 bytes
		.bss	var3,6		# array of 3x2 chars, 6 bytes

Note that these are extremely different.  The first case declares a
single simple pointer, which happens to be a pointer-to-a-pointer.  The
second declares a contiguous array of 5 pointers, each of which happens
to be a pointer-to-a-char.  The last example just creates a block of 6
bytes, no pointers.

Because the types are different, the compiler knows to generate
different code for accessing each case.  Let's carry this a little
further and fetch var3[2][1], var2[2][1], and var1[2][1].  These look
like (two register machine, "ptr" and "acc"):

		move	(var3+5),acc	# move offset 2*2+1 into accum.

		move	(var2+8),ptr	# move offset 2*4 into pointer
		move	1(ptr),acc	# move offset 1 into accumul.

		move	var3,ptr	# fetch var3 (pointer)
		move	8(ptr),ptr	# move offset 2*4 into pointer
		move	1(ptr),acc	# move offset 1 into accumul.

In the first case, the compiler uses the "var3" symbol as the location
of the beginning of the array, and simply needs to offset out to the
6th location to fetch the desired character.  In the second case, the
compiler can locate var2[2] immediately; it's the second element in the
var2 array (pointers of 4 bytes each), but then it must use the value at
that location as a pointer to the actual array of characters, and then
fetch offset 1 from there.  In the last case, the compiler must fetch
the contents of var3, treat it as a pointer to fetch the 2nd pointer
value (again 4 bytes each), and then fetch offset 1 from that value.

-- 
James Carlson <carlson@xylogics.com>            Tel:  +1 617 272 8140
Annex Interface Development / Xylogics, Inc.          +1 800 225 3317
53 Third Avenue / Burlington MA  01803-4491     Fax:  +1 617 272 2618
Re: Q: char **foo, char *foo[], and char foo[][] ?
#5033
Author: Jerry Coffin
Date: Thu, 18 Apr 1996 19:10
16 lines
956 bytes
In article <4l33ok$oo2@Sherlock.lectra.fr>, phil@rd.lectra.fr says...
> Considering the 3 following declarations:
> 
> 1 - char **foo;
> 2 - char *foo[];
> 3 - char foo[][];
> 
> I know that there is a (big !) difference in memory reservation, but I do
> not know if foo IS or IS NOT of the same type in these three cases.
[ ... ] 

In declaring a parameter to a function, any declaration of an array is treated 
as a declaration of a pointer.  In all other situations, the two are separate 
and distinct.
    Later,
    Jerry.
Re: Q: char **foo, char *foo[], and char foo[][] ?
#5036
Author: James Carlson
Date: Fri, 19 Apr 1996 12:20
39 lines
1902 bytes
In article <KANZE.96Apr18105949@gabi.gabi-soft.fr>, kanze@gabi-soft.fr (J. Kanze) writes:
|> In article <4l33ok$oo2@Sherlock.lectra.fr> phil@rd.lectra.fr (Philippe
|> Maurisset) writes:
[...]
|> 
|> |> myexample()
|> |> {
|> |> 	char foo[MAX_X][MAX_Y];
|> |> 	...
|> |> 	myfunc( (char **)foo );
|> |> }
|> 
|> |> void myfunc( char *foo[MAX_X] )
|>                 ^^^^^^^^^^^^^^^^
|> 
|> Because it appears as a function parameter, this is actually a
|> declaration of a char**, and not a char*[].

True.

|> So in fact, you have no type incompatibility to deal with.

Not true.  The original definition of foo in myexample() was as a two-
dimensional array, which, in C, is implemented in storage as a
unidimensional array of size MAX_X*MAX_Y*sizeof(char), not as an array
of pointers-to-characters.  If you try to access this as a pointer-to-a-
pointer, you will be attempting to dereference character data as a
pointer.  (If you've got a real operating system, then this just results
in a core fault.  If you're running on a toy, the results could be far
worse.)

(Of course, the type of the formal argument is compatible with the
cast given in the call, but the cast itself is bogus.)

-- 
James Carlson <carlson@xylogics.com>            Tel:  +1 617 272 8140
Annex Interface Development / Xylogics, Inc.          +1 800 225 3317
53 Third Avenue / Burlington MA  01803-4491     Fax:  +1 617 272 2618
Re: Q: char **foo, char *foo[], and char foo[][] ?
#5037
Author: Larry Jones
Date: Fri, 19 Apr 1996 20:20
37 lines
1683 bytes
In article <KANZE.96Apr18105949@gabi.gabi-soft.fr>, kanze@gabi-soft.fr (J. Kanze) writes:
> In article <4l33ok$oo2@Sherlock.lectra.fr> phil@rd.lectra.fr (Philippe
> Maurisset) writes:
> |> myexample()
> |> {
> |> 	char foo[MAX_X][MAX_Y];
> |> 	...
> |> 	myfunc( (char **)foo );
> |> }
> 
> |> void myfunc( char *foo[MAX_X] )
>                 ^^^^^^^^^^^^^^^^
> 
> Because it appears as a function parameter, this is actually a
> declaration of a char**, and not a char*[].
> 
> So in fact, you have no type incompatibility to deal with.

Yes, you do.  While the cast in the call to myfunc matches the
prototype, the cast itself is erroneous.  The type of foo is actually
char (*)[MAX_Y]: a pointer to an array of characters.  Converting a
pointer to an array into a pointer to a pointer is essentially
meaningless and will not generally work.  The corrected example is:

	myexample()
	{
		char foo[MAX_X][MAX_Y];
		...
		myfunc( foo );
	}
	void myfunc( char (*foo)[MAX_X] )

Even K&R I discusses this in 5.7 Multi-Dimensional Arrays.
----
Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH  45150-2789  513-576-2070
larry.jones@sdrc.com
In a minute, you and I are going to settle this out of doors. -- Calvin
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads