[comp.lang.c] Difference between "char *arr" and "char arr[]"

kuan@iris.ucdavis.edu (Frank [Who me?] Kuan) (09/22/90)

In file "a.c", I declare:
char targ[128];

In file "b.c" I do:
extern char *targ;

Result: I got massive errors. When I source debugged it, it told me
that the char pointer "targ" was 0x000000. 

By chance, I tried redeclaring it as "extern char targ[]" and
the problem was fixed.

Now, I always thought that "targ[]" and "char *targ" were equivalent.
I have several places in my program where I use those two notations
interchangeably, and this was the first time I've ever had a problem
with it. 

Could a C wizard explain to me what I'm doing wrong and what the
correct practice is so I don't run into these horrible bugs again?

Thanks in advance.

- f

eyal@echo.canberra.edu.au (Eyal Lebedinsky) (09/22/90)

In article <8103@aggie.ucdavis.edu> kuan@iris.ucdavis.edu (Frank [Who me?] Kuan) writes:
>
>In file "a.c", I declare:
>char targ[128];
>
>In file "b.c" I do:
>extern char *targ;
>
>Result: I got massive errors. When I source debugged it, it told me
>that the char pointer "targ" was 0x000000. 
>
>By chance, I tried redeclaring it as "extern char targ[]" and
>the problem was fixed.
>
>Now, I always thought that "targ[]" and "char *targ" were equivalent.
>I have several places in my program where I use those two notations
>interchangeably, and this was the first time I've ever had a problem
>with it. 
>
>Could a C wizard explain to me what I'm doing wrong and what the
>correct practice is so I don't run into these horrible bugs again?

No wizard, but here it is. The compiler will allow you to mix the array/pointer
notation and will get it right. To do this it needs to know what the reality
is. In other words, once you declare the array/pointer correctly, you cac then
access it either way. The generates assembler to access a pointer is not the
same as accessing an array. C has some 'promotion rules' which define the
behaviour of the expression array[index] and pointer[index]: the name of
an array is promoted to 'a pointer to the first element'. Anyway, the short
answer is YOU MUST DECLARE IT CORRECTLY, CANNOT MIX POINTER/ARRAY IN THE
DECLARATION.
BTW, in function arguments there is another promotion rule which allows you
to mix pointer/array here.

Any clearer now ? hope so.>
>Thanks in advance.
>
>- f


-- 
Regards
	Eyal

cpcahil@virtech.uucp (Conor P. Cahill) (09/22/90)

In article <8103@aggie.ucdavis.edu> kuan@iris.ucdavis.edu (Frank [Who me?] Kuan) writes:
>Now, I always thought that "targ[]" and "char *targ" were equivalent.
>I have several places in my program where I use those two notations
>interchangeably, and this was the first time I've ever had a problem
>with it. 

They are equivalent (with respect to referencing data) for just about all
cases EXCEPT for global variables.

The reason that they are equivalent for function calls is that the array is
acutally converted to (and passed as) a pointer.  

For global variables "targ" will represent a location in memory assigned
by the linker.  Any mention of the variable "targ" will be replaced by
an absolute memory location by the linker.  The contents of this memory
location will differ depending upon the declaration of targ.

	If it is declared as "char * targ;",
		the compiler will expect a character pointer at this location
	If it is declared as "char targ[xx];"
		the compiler will expect a character arrry starting at this
		location

>correct practice is so I don't run into these horrible bugs again?

The correct practice is that global declarations and references much 
match exactly (except initializations of course).

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

jdarcy@encore.com (Jeff d'Arcy) (09/23/90)

In case nobody else has mentioned it (I came in late on this one), there
is a difference between *x and x[] besides allocation and semantics for
globals: sizeof().  A lot of times I've been tempted to write

	static char *message = "hello";
	/* ... */
	write(fd,message,sizeof(message));

within a routine.  Obviously this won't work, but

	static char message[] = "hello";

will.  It's amazing how easy it is to forget this little detail and how
many times I've seen it done.  Usuaully it's much more insidious than
this example.
--

Jeff d'Arcy, Generic Software Engineer - jdarcy@encore.com
      Nothing was ever achieved by accepting reality

throopw@sheol.UUCP (Wayne Throop) (09/23/90)

> From: kuan@iris.ucdavis.edu (Frank [Who me?] Kuan)
> Now, I always thought that "targ[]" and "char *targ" were equivalent.

As an aside, I took a survey a while back about this.  It turns out
that the reason for this frequent misconception is (essentially)
poor teaching and poor reference materials.  Essentially teachers
TEACH people this, sometimes inadvertantly.

My main suggestion to Frank Kuan is to read the "Frequently Asked
Questions" posting when it comes around again.  You will find the
answer to the [] vs * question, along with a slew of other things
that teachers (apparently) often mis-teach students.

> From: cpcahil@virtech.uucp (Conor P. Cahill)
> They are equivalent (with respect to referencing data) for just about all
> cases EXCEPT for global variables.

And automatic variables.  And objects in the malloc/free heap.  And
variables with static visibility/persistence.

I think that Conor may be taking "equivalent" to mean that the two
objects can appear in lexically identical references.  Which is correct.
But the semantics which apply to the two cases are distinct.

The fact is, there is only ONE place where the two are semantically
equivalent, and that is as definitions of formal parameters.  Again, see
the FAQ for details, but code generated for subscripting, "sizeof"
results, and in essence *everything* is different for these two
declarations, with only the one exception. 

So, while Conor is technically correct, I think it is much more
important to emphasize the differences here, rather than the similarities.
The similarities are superficial, and the differences important,
fundamental, and often overlooked.
--
Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org

tih@barsoom.nhh.no (Tom Ivar Helbekkmo) (09/23/90)

In a fit of pure idiocy, I wrote:

>	global unsigned long avail[A,B,C];

and as several people have pointed out already, that's not how you declare
a multi-dimensional array in C.  *blush*

What can I say?  I'd just resurfaced after a lot of FORTRAN programming
involving arrays, though...  Still, I must have been temporarily blind.

Thanks to all who took the time to point this out to me!  :-)

-tih
-- 
Tom Ivar Helbekkmo, NHH, Bergen, Norway.  Telephone: +47-5-959205
tih@barsoom.nhh.no, thelbekk@norunit.bitnet, edb_tom@debet.nhh.no

enag@ifi.uio.no (Erik Naggum) (09/24/90)

Let me venture a concise explanation to this difference:

	extern char *arr	declares an object, containing a
				pointer to a character

	extern char arr[]	declares a constant pointer to a
				character

Hope this helps.
--
[Erik Naggum]		Naggum Software; Gaustadalleen 21; 0371 OSLO; NORWAY
	I disclaim,	<erik@naggum.uu.no>, <enag@ifi.uio.no>
  therefore I post.	+47-295-8622, +47-256-7822, (fax) +47-260-4427

chris@mimsy.umd.edu (Chris Torek) (09/24/90)

In article <ENAG.90Sep23231057@hild.ifi.uio.no>
enag@ifi.uio.no (Erik Naggum) writes:
>Let me venture a concise explanation to this difference:
>
>	extern char *arr	declares an object, containing a
>				pointer to a character
>
>	extern char arr[]	declares a constant pointer to a
>				character

Concise, yes; correct, no.  Both declare objects; the latter declares
an object that is an array.  It IS an array; it is NOT a pointer.  The
confusion occurs because objects that are arrays are *converted into*
VALUES that are pointers, whenever the value is called for.

In other words, if `x' is an array, one might try to describe the
`value' of x as the values of all elements of x.  (Mathematically, `the
value of x' would be `the set of all values x[i] such that x[i]
exists.')  If `x' is a large array, that would be an awful lot of
values.  Most computers can only work on one or two or maybe a dozen
or a hundred values at a time, and x could easily contain several
thousand values.  So the C language does not provide a way to talk
about this kind of `value of x'.

Instead, when you ask for the `value' of x (where x is some array),
the language gives you a convenient place to start if you wanted to
go about finding all of the (possibly many thousands of) values x[i].
Indeed, it tells you where the very first such value is stored.  In
other words, it changes an

	<object, array 8000 of int, x>

into a

	<value, pointer to int, &x[0]>

and you can then go about fetching all 8000 values yourself, using
this pointer.

Since it changes the <object, array N of T> into a <value, pointer to T>,
the result is not something you can change---you cannot, after the fact,
change the place the system decided to store the array, at least not in
the C language proper (assembly language hacking is another matter)---and
this leads people to (incorrectly) decide that an array `is' a constant.
It is nothing of the sort: an array IS an array.  It is not something you
can change, but it is also not a constant, as the (nonportable) program

	#include <stdio.h>
	void f(v) int v; {
		int arr[1000];
		printf("%lx\n", (long)arr);
		if (v) f(0);
	}
	int main() { f(1); return 0; }

will demonstrate on those systems that do not remove the tail recursion.
(You will get two different numbers.)

(N.B.: By switching from one meaning to another, you *can* say that an
array `is a constant'.  In C, as in many languages, `constant' is a
language concept meaning `a value that never changes'.  But the
location of an array *can* change, at least if that array is
automatic.  You, as a programmer, may not change it; the system can.
If you decide that you want the word `constant' to mean `I, as a
programmer, may not change this', then of course the location is *that*
sort of `constant'.  But you will confuse everyone else---as I probably
just did with this whole aside.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

enag@ifi.uio.no (Erik Naggum) (09/25/90)

In article <ENAG.90Sep23231057@hild.ifi.uio.no>, Erik Naggum (I) wrote:

> Let me venture a concise explanation to this difference:
>
>	extern char *arr	declares an object, containing a
>				pointer to a character
>
>	extern char arr[]	declares a constant pointer to a
>				character

In article <26680@mimsy.umd.edu>, Chris Torek (you) write:

> Concise, yes; correct, no.  Both declare objects; the latter declares
> an object that is an array.  It IS an array; it is NOT a pointer.  The
> confusion occurs because objects that are arrays are *converted into*
> VALUES that are pointers, whenever the value is called for.

Rather, "char arr[14]" declares an array, but "extern char arr[]" only
declares that "arr" is some constant pointer the value of which is to
be resolved by the linker.  "char *arr" declares an object, and
"extern char *arr" declares that "arr" is some object the address of
which is to be resolved by the linker.

I think you overlooked the "extern" up there.  I follow your arguments
for locally declared objects down to the finest details.

Strictly speaking, I have to correct my own explanation: Neither
declares objects, but instead object names with types and values of
that type to be resolved by the linker (or later, anyhow).

I hope this gets a "concise, no; correct, yes" response, at least.

--
[Erik Naggum]		Naggum Software; Gaustadalleen 21; 0371 OSLO; NORWAY
	I disclaim,	<erik@naggum.uu.no>, <enag@ifi.uio.no>
  therefore I post.	+47-295-8622, +47-256-7822, (fax) +47-260-4427

karl@haddock.ima.isc.com (Karl Heuer) (09/25/90)

In article <ENAG.90Sep25005953@hild.ifi.uio.no> enag@ifi.uio.no (Erik Naggum) writes:
>Rather, "char arr[14]" declares an array, but "extern char arr[]" only
>declares that "arr" is some constant pointer the value of which is to
>be resolved by the linker.

I disagree.  Both are *declarations*; the one without "extern" happens to also
serve as a *definition*.  So I would say that "char arr[14]" declares an array
and (being a definition) also causes storage to be allocated for it (probably
by a linker), while "extern char arr[]" declares an array and causes the name
"arr" to be associated with the same storage that was allocated under that
name in some other compilation unit.

There are no pointers (in the C sense) involved here, at least not until such
time as the name "arr" is used in an rvalue context.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

bengsig@oracle.nl (Bjorn Engsig) (09/25/90)

In article <26680@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) once again
explained why 'extern char *arr' and 'extern char arr[]' isn't the same thing.

I admire you, Chris, for having so much patience.  The answer I had expected was
RTFM or RTFFAQ.
-- 
Bjorn Engsig,	Domain:		bengsig@oracle.nl, bengsig@oracle.com
		Path:		uunet!mcsun!orcenl!bengsig
		From IBM:	auschs!ibmaus!cs.utexas.edu!uunet!oracle!bengsig

eyal@echo.canberra.edu.au (Eyal Lebedinsky) (09/26/90)

Following the discussion, I feel that two issues are beeing mixed:
1 - an object is either an array OR a pointer with no ambiguity.
2 - a reference to an object can mix array/pointer notation.

If an object is declared/defined so as to lead the compiler to see it as an
array then all references will follow this notion, same with pointer.
So: a[4] can be used to refer to 'a' (regardless if 'a' is arr/point) and the
appropriate code will be emitted depending on THE TYPE of a. '*(a+4)' will do
the same. The C syntax/semantics defines this clearly.
-- 
Regards
	Eyal

seanf@sco.COM (Sean Fagan) (09/27/90)

In article <ENAG.90Sep25005953@hild.ifi.uio.no> enag@ifi.uio.no (Erik Naggum) writes:
>Rather, "char arr[14]" declares an array, but "extern char arr[]" only
>declares that "arr" is some constant pointer the value of which is to
>be resolved by the linker.  

*NO NO NO NO*!

'extern char arr[]' does *not* declare, in any way, shape, or form, a
pointer.

What it *does* declare is the label of a block of memory (size currently
unknown), which will be (hopefully) resolved at link time.

The difference between

	extern char arr[];

and

	extern char *ptr;

is that the first one is not indirected to get the address; the other one
is.  That is, ptr is actually a double-indirect variable:  one indirection
to get its value, and another one to dereference it.  arr, on the other
hand, is just indirected once, to get it's value (which is arr[0]).

-- 
-----------------+
Sean Eric Fagan  | "Never knock on Death's door:  ring the bell and 
seanf@sco.COM    |   run away!  Death really hates that!"
uunet!sco!seanf  |     -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor")
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

enag@ifi.uio.no (Erik Naggum) (10/03/90)

In article <7920@scolex.sco.COM> seanf@sco.COM (Sean Fagan) writes:

   In article <ENAG.90Sep25005953@hild.ifi.uio.no> enag@ifi.uio.no (Erik Naggum) writes:
   >Rather, "char arr[14]" declares an array, but "extern char arr[]" only
   >declares that "arr" is some constant pointer the value of which is to
   >be resolved by the linker.  

   *NO NO NO NO*!

   'extern char arr[]' does *not* declare, in any way, shape, or form, a
   pointer.

I'm sorry for all the confusion my severely overloaded use of
"constant" has caused.  I have been corrected by what seems like all
the ANSI C programmers in the known and not-so-known universe, and
they all point out that we have a "char * const ptr" construct, which
I have always thought was a horrible abomination, and thus totally
forgot that people could think I meant.

Other than this unfortunate choice of words, we all agree.  Relax,
all.  My mailbox is off limits, already.

Next time I want to overload, I'll post to comp.lang.c++.

--
[Erik Naggum]		Naggum Software; Gaustadalleen 21; 0371 OSLO; NORWAY
	I disclaim,	<erik@naggum.uu.no>, <enag@ifi.uio.no>
  therefore I post.	+47-295-8622, +47-256-7822, (fax) +47-260-4427