[comp.lang.c] Pointer Stew

blm@spec0.UUCP (Bharat Lal Madhyani) (05/05/89)

/*************/
/* program1.c*/
/*************/

/*
   consider the following small c_program
   path :  is an array of pointers to characters, 
	   which has been initialized
p_path :   is a pointer to path, i.e it is a 
	   pointer to pointer to character

The program basically travels the array path and prints the character string
associated with the pointer at that time.

*/
char *path[]  = {

		"/usr/pgmr/blm/citoh/shit",     
		"/usr/pgmr/junk",   	
		"/usr/lib/news/history",
		"/usr/bin/vi",
		"Testing Initialization",
		0
};

char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}


/***************/
/* program2.c  */
/***************/
/* 
     In this program , I have defined a new variable
     bad_address -- which is a pointer to character. And
     while initializing the path array of pointers to characters
     I am getting the following error :

	"program2.c", line 30: illegal initialization


	why it is so ? bad_address is also an address(pointer), which also
	points to character string. And as we all know that two
	dimensional array are implemented through pointers, i.e
	char a[10][20] means :

		a is an array of 10 pointers, and each element of
		array a is an array of  20 characters.

*/
	
char *bad_address = "Testing Initialization";
char *path[]  = {

		"/usr/pgmr/blm/citoh/shit",     
		"/usr/pgmr/junk",   	
		"/usr/lib/news/history",
		"/usr/bin/vi",
		bad_address,
		0
};
char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}


/***************/
/* program3.c  */
/***************/
/* 
     Still consider another program, where I have define 5 different
     character arrays, and I am Initializing the *path[] with these
     arrays, and the program works fine.

*/
char a1[]="/usr/pgmr/blm/citoh/shit";     
char a2[]="/usr/pgmr/junk";   	
char a3[]="/usr/lib/news/history";
char a4[]="/usr/bin/vi";
char bad_address[] = "Testing Initialization";
char null[]="" ;
char *path[6] = {
		a1,
		a2,
		a3,
		a4,
		bad_address,
		null
		};

char **p_path = path ; /* pointer to path */
main()
{
	/*path[0] = a1, path[1] = a2, path[2]=a3, path[3]=a4 ;*/
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}

/***************/
/* program4.c  */
/***************/
/* 
     Still consider another program, where I have define 5 different
     character pointers, and I am Initializing the *path[] with these
     pointers, and the program works fine.

*/
char *a1="/usr/pgmr/blm/citoh/shit";     
char *a2="/usr/pgmr/junk";   	
char *a3="/usr/lib/news/history";
char *a4="/usr/bin/vi";
char *bad_address = "Testing Initialization";
char *null="" ;
char *path[6] = {
		a1,
		a2,
		a3,
		a4,
		bad_address,
		null
		};

char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}
/* I am getting the following errors:

"program3.c", line 18: illegal initialization
"program3.c", line 19: illegal initialization
"program3.c", line 20: illegal initialization
"program3.c", line 21: illegal initialization
"program3.c", line 22: illegal initialization
"program3.c", line 24: illegal initialization

*/


Questions :

.	What subtle difference program3.c & program4.c has ?

.	Why character arrays can be used to initialize the array
	of pointers to character & character pointers cannot be
	used to initialize the array of pointers to characters ?


--
blm!spec0
Bharat Madhyani

blm@spec0.UUCP (Bharat Lal Madhyani) (05/06/89)

Please ignore my previous posting. This is the most recent posting. There were
some type-errors in the previous one. Sorry :-)

/*************/
/* program1.c*/
/*************/

/*
   consider the following small c_program
   path :  is an array of pointers to characters, 
	   which has been initialized
p_path :   is a pointer to path, i.e it is a 
	   pointer to pointer to character

The program basically travels the array path and prints the character string
associated with the pointer at that time.

*/
char *path[]  = {

		"/usr/pgmr/blm/citoh/shit",     
		"/usr/pgmr/junk",   	
		"/usr/lib/news/history",
		"/usr/bin/vi",
		"Testing Initialization",
		0
};

char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}


/***************/
/* program2.c  */
/***************/
/* 
     In this program , I have defined a new variable
     bad_address -- which is a pointer to character. And
     while initializing the path array of pointers to characters
     I am getting the following error :

	"program2.c", line 30: illegal initialization


	why it is so ? bad_address is also an address(pointer), which also
	points to character string. And as we all know that two
	dimensional array are implemented through pointers, i.e
	char a[10][20] means :

		a is an array of 10 pointers, and each element of
		array a is an array of  20 characters.

*/
	
char *bad_address = "Testing Initialization";
char *path[]  = {

		"/usr/pgmr/blm/citoh/shit",     
		"/usr/pgmr/junk",   	
		"/usr/lib/news/history",
		"/usr/bin/vi",
		bad_address,           /* Here is illegal initialization */
		0
};
char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}


/***************/
/* program3.c  */
/***************/
/* 
     Still consider another program, where I have defined 5 different
     character arrays, and I am Initializing the *path[] with these
     arrays, and the program works fine.

*/
char a1[]="/usr/pgmr/blm/citoh/shit";     
char a2[]="/usr/pgmr/junk";   	
char a3[]="/usr/lib/news/history";
char a4[]="/usr/bin/vi";
char bad_address[] = "Testing Initialization";
char null[]="" ;
char *path[6] = {
		a1,
		a2,
		a3,
		a4,
		bad_address,
		null
		};

char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}

/***************/
/* program4.c  */
/***************/
/* 
     Still consider another program, where I have defined 5 different
     character pointers, and I am Initializing the *path[] with these
     pointers, and the program does not compile due to illegal 
     initialization.

*/
char *a1="/usr/pgmr/blm/citoh/shit";     
char *a2="/usr/pgmr/junk";   	
char *a3="/usr/lib/news/history";
char *a4="/usr/bin/vi";
char *bad_address = "Testing Initialization";
char *null="" ;
char *path[6] = {
		a1,
		a2,
		a3,
		a4,
		bad_address,
		null
		};

char **p_path = path ; /* pointer to path */
main()
{
	while ( **p_path ) 
		printf("%s\n", *p_path++ );
}
/* I am getting the following errors:

"program3.c", line 19: illegal initialization
"program3.c", line 20: illegal initialization
"program3.c", line 21: illegal initialization
"program3.c", line 22: illegal initialization
"program3.c", line 23: illegal initialization
"program3.c", line 24: illegal initialization

*/


Questions :

.	What subtle difference program3.c & program4.c has ?

.	Why character arrays can be used to initialize the array
	of pointers to character & character pointers cannot be
	used to initialize the array of pointers to characters ?


--
spec0!blm
Bharat Madhyani

guy@auspex.auspex.com (Guy Harris) (05/07/89)

 >/* 
 >     In this program , I have defined a new variable
 >     bad_address -- which is a pointer to character. And
 >     while initializing the path array of pointers to characters
 >     I am getting the following error :
 >
 >	"program2.c", line 30: illegal initialization
 >
 >
 >	why it is so ? bad_address is also an address(pointer), which also
 >	points to character string. And as we all know that two
 >	dimensional array are implemented through pointers, i.e
 >	char a[10][20] means :
 >
 >		a is an array of 10 pointers, and each element of
 >		array a is an array of  20 characters.

Uh, speak for yourself here, not for "us all".  Many of us know no such
thing, because it's simply not true; "char a[10][20]" means "a is an
array of 10 arrays of 20 characters" - period.   Arrays are not
pointers.

The problem with the initialization in question, however, has nothing to
do with this.  "bad_address" is, indeed, a variable of type "pointer to
char", and therefore its value is of the right type to stuff into a
member of "path", since "path" is an array of pointers to "char". 
However, it is a *variable*, not a *constant*, and therefore it can't be
used in an initialization of a static variable such as "path".

>/***************/
>/* program3.c  */
>/***************/
>/* 
>     Still consider another program, where I have define 5 different
>     character arrays, and I am Initializing the *path[] with these
>     arrays, and the program works fine.

That's because "a1", "a2", etc.  are arrays of "char", unlike
"bad_address", which is a variable of type "pointer to char".  In most
(but *NOT* all) contexts, an expression of type "array of <type>" gets
converted to an expression of type "pointer to <type>" which points to
the first element of the array in question, so in those contexts "a1",
which is an expression of type "array of char", gets converted to an
expression of type "pointer to char" that points to the first element of
"a1", and the same is true for "a2", "a3", "a4", "bad_address", and
"null". 

Since "a1", etc. are static variables, the expression resulting from
that conversion is a constant expression, and thus can be used in the
initialization of a static variable such as "path".

This means that

	char bad_address[] = "Testing Initialization";

and

	char *bad_address = "Testing Initialization";

are *NOT* equivalent.  The first defines an array of "char", named
"bad_address"; that array is big enough to hold the string "Testing
Initialization", complete with the trailing '\0', and is initialized to
that string.  The second creates an array of "char", with no name, which
is big enough to hold the string "Testing Initialization", complete with
the trailing '\0', and which is initialized to that string; it defines a
pointer to "char", named "bad_address", which is initialized to a
pointer to the aforementioned unnamed array.

>/* 
>     Still consider another program, where I have define 5 different
>     character pointers, and I am Initializing the *path[] with these
>     pointers, and the program works fine.

Same problem as before; "a1", "a2", etc. are *not* constant expressions,
so they cannot be used to initialize static variables such as "path".

>.	Why character arrays can be used to initialize the array
>	of pointers to character & character pointers cannot be
>	used to initialize the array of pointers to characters ?

Because a character array of static storage duration, when converted to
a pointer in those contexts where such a conversion is performed, is a
constant expression (said array is, after all, assigned a fixed address
at compile, link, or possibly execute time), while a character pointer
variable is *not* a constant expression.  Only constant expressions can
be used to initialize objects of static storage duration. 

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/08/89)

In article <386@spec0.UUCP> blm@spec0.UUCP (Bharat Lal Madhyani) writes:
>	why it is so ? bad_address is also an address(pointer), which also
>	points to character string.

No, it doesn't.  It points to a character (the first member of the array
generated for the string literal).

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/08/89)

In article <387@spec0.UUCP> blm@spec0.UUCP (Bharat Lal Madhyani) writes:
>char *bad_address = "Testing Initialization";
>char *path[]  = {
>		bad_address,           /* Here is illegal initialization */
>};

Yes, because such initializers have to be known at compiler/link time,
not run time, the initializers must be constant expresions, not
contents of storage locations.

rkl@cbnewsh.ATT.COM (kevin.laux) (05/08/89)

In article <386@spec0.UUCP>, blm@spec0.UUCP (Bharat Lal Madhyani) writes:

	[stuff deleted]

> 	   				And as we all know that two
> 	dimensional array are implemented through pointers, i.e
> 	char a[10][20] means :
> 
> 		a is an array of 10 pointers, and each element of
> 		array a is an array of  20 characters.
> 
> */

	[stuff deleted]

	No!  Array a is *NOT* an array of 10 pointers and does *NOT* mean it
either.  Array a is a two-dimensional array of chars, period.

	When you write:

	char *path[10];

	*That* is an array of 10 pointers to chars.

--rkl

throopw@dg-rtp.dg.com (Wayne A. Throop) (05/13/89)

> blm@spec0.UUCP (Bharat Lal Madhyani)

Everybody pointed out that the type (int [N][M]) is NOT implemented
as an array of pointers.  But nobody seemed to see the problem in the
first program (shown here abbreviated):

> char *path[]  = {
> 	"/usr/pgmr/junk",   	
>	[...]
>	0   };
> char **p_path = path ; /* pointer to path */
> main() { while ( **p_path ) printf("%s\n", *p_path++ ); }

Does nobody see anything wrong with the condition of that while
loop?  Anybody?  Yes, you in the back with the plastic pocket protector?
That's right, it dereferences the null pointer.  It may work on some
machines, but it is NOT portable at all.

Later examples in the same posting get this right, by replacing
the zero with an empty string.  The other way to correct it is to
make the test on (*p_path) instead of (**p_path).

--
"You'd be surprised... they're all separate little countries down there."
                                        --- Ronald Wilson Reagan
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

jwl@sag4.ssl.berkeley.edu (Jim Lewis) (06/16/91)

In article <33641@usc.edu> burzin@skat.usc.edu (Burzin N. Engineer) writes:
>Hi,
>	I just gave an interview which had a C quiz and there was this program
>that really confused me. I have compiled the program and can still not figure
>out what is going on. Any reference or help will be appreciated.
>---
>char *c[] = {
>  "ENTER",
>  "NEW",
>  "POINT",
>  "FIRST"
>  };
>char **cp[] = { c+3, c+2, c+1, c};
>char ***cpp = cp;
>main()
>{
>  printf("%s", *++cpp);
>  printf("%s", *--*++cpp+3);
>  printf("%s", *cpp[-2]+3);
>  printf("%s\n", cpp[-1][-1]+1 );
>}
>
>When run it produces:
>ERSTEW

Part of the reason this quiz question didn't make much sense is because
it has a bug in it.  The first string printed should be **++cpp, not *++cpp.
The output will then be "POINTERSTEW".  Without the missing pointer dereference,
it's taking a piece of memory that holds a pointer, and trying to print
that sequence of bytes as a string.  On your architecture, the first byte
of the pointer was probably zero, which is the end-of-string marker, so
the first printf was a no-op.  Under a different byte ordering, you
might have seen some garbage characters, or perhaps a core dump.

I won't spoil the puzzle for you...you should go back to your C reference
and re-read the sections on arrays and pointers until you see what's
going on.

It's good to be able to understand what's going on with these programs,
but I'd be pretty leery of an employer that relied heavily on
these kinds of quiz questions to test someone's knowledge of C.  (I could
see one or two questions like this to seperate the truly outstanding
candidates from the merely competent, but a whole test like that? *shudder*!)

Both problems (including the POINTER STEW bug)  came from "The C Puzzle
Book" by Alan R. Feuer.   This isn't the first time they've been mentioned
on the net by people who ran across them at interviews....maybe the companies
who are using this book to test programmers should wise up and switch to
winners (or losers!) of recent Obfuscated C contests!

-- Jim Lewis,  U.C. Berkeley
   Center for EUV Astrophysics

scs@adam.mit.edu (Steve Summit) (06/18/91)

In article <1991Jun15.223427.13656@agate.berkeley.edu> jwl@sag4.ssl.berkeley.edu (Jim Lewis) writes:
>Both problems (including the POINTER STEW bug)  came from "The C Puzzle
>Book" by Alan R. Feuer.   This isn't the first time they've been mentioned
>on the net by people who ran across them at interviews...

I would never work for such a company.

                                            Steve Summit
                                            scs@adam.mit.edu

snk@garage.uucp (Samuel Kamens) (06/19/91)

In article <1991Jun18.163802.25891@athena.mit.edu> scs@adam.mit.edu writes:
>In article <1991Jun15.223427.13656@agate.berkeley.edu> jwl@sag4.ssl.berkeley.edu (Jim Lewis) writes:
>>Both problems (including the POINTER STEW bug)  came from "The C Puzzle
>>Book" by Alan R. Feuer.   This isn't the first time they've been mentioned
>>on the net by people who ran across them at interviews...
>
>I would never work for such a company.
>

Actually, I understand that this practice is illegal.  Using anything
but an instrumented test for employment purposes in discrimination,
and is therefore against the law (my source for this is a recent class
I took in interviewing practices at work....).

[ boy is this *not* comp.lang.c-appropriate.  Sorry.....]


-------------------------------------------------------------------------------
Sam Kamens					Bell Communications Research
snk@bae.bellcore.com				Phone: (908) 699-7381
444 Hoes Lane  Room RRC 1C-205
Piscataway, NJ 08854


-- 

-------------------------------------------------------------------------------
Sam Kamens					Bell Communications Research
snk@bae.bellcore.com				Phone: (908) 699-7381