Help...

Chris Torek chris at mimsy.UUCP
Wed Oct 11 04:48:28 AEST 1989


>>>main ()
>>>{
>>>    char      h[];
>>>    scanf ("%s", h);

Someone writes:
>>    I don't know [ ... ] you can get the same
>>result from char *h, and not get too many problems.

Dr. Lint has already posted his opinion of the above program.
I daresay it would be no better for `char *h'.

In article <RANG.89Oct9215608 at derby.cs.wisc.edu> rang at cs.wisc.edu (Anton Rang)
writes:
>[ This is not a flame, just a clarification, OK? ]

(It would be OK if it were right.)

>There is no difference between "char h[]" and "char *h" in a
>declaration; they do exactly the same thing.

This is false.  `char h[]' can only be used in three places: after
the word `extern', declaring h as an external array, size unknown,
of char; statically or globally, before an initialiser, declaring
h as a global or static array of size determined by the initialiser,
type char; or in a formal parameter declaration, declaring h as a
pointer to char.  (ANSI may add local automatic aggregate initialisers
to this list, modifying the second clause.)

Only in the last case---as a parameter declaration---is `char h[]'
rewritten by the compiler as `char *h'.

>This program fails because there is no storage allocated for the string.

This much is correct.

>  The "char h[]", or "char *h", declares a *pointer* to a character
>array.

`char h[]', as a local variable, declares h as an array of zero
characters, not as a pointer.  This is not legal C, although many
compilers do not diagnose it.

`char *h' always declares a pointer.

>It doesn't allocate any storage space for the array, though.

Assuming the compiler meekly accepts `char h[0]' (here spelled
`char h[]'), this is quite right.

>"scanf" happily uses the random contents of the pointer,

The referent here is missing: `the' pointer.  There are actually
three pointers, for the call

	scanf("%s", h)

is a three-part expression, all parts of which resolve to pointers.

First we have

	scanf <function call context>

which implicitly declares scanf() as a function of unknown arguments
returning int, locates scanf somehow, and resolves to an rvalue
expression of type `pointer to function of unknown returning int',
whose value is the location (in some nebulous fashion) of scanf.
I shall write this as <value, ptr to fn (?) ret int, points to scanf>.

Next we have

	"%s"

in a normal expression context.  (Double quoted strings have a special
meaning in an initialiser context when being used to initialise an
array of char.)  This generates (somewhere---likely in read-only
memory) the three-character sequence '%','s','\0' and names this
object.  It is thus an <object, array 3 of char, value `%s\0'>; being
in an expression (rvalue) context, we apply the rule for C arrays in
such contexts and change this to <value, ptr to char, points to `%s\0'>.

Finally, we have

	h

also in an expression context.  H is (assuming our compiler has
accepted it) <object, array 0 of char, value `'> and we apply the
same rule, obtaining <value, ptr to char, points to zero chars>.

The two <value, ptr to char ...> values are packaged up, mailed to the
function indicated by the <value, ptr to fn ...> value, and scanf
gets control.

All we know of scanf is its description in some standards text or
manual.  In this case, we expect it to read one string (by its first
argument) and stuff the `char's of the string in the location given by
its second argument.  That second argument, however, points to zero
`char's, so if scanf stuffs even a single character, it will have
overrun the actual space provided.

When scanf returns, the result is a <value, int, ?>.  To fill in the
question mark we need not only the description of scanf, but also
knowledge about whatever scanf scanned from stdin.  That was not
specified, so there is nothing we can add here.

>In the best case, this would generate a run-time error.

Right.  (Well, actually, the best case is a compile-time error,
since h is array-of-zero-char.  Make it h[1] and then the best case
is a run-time error.)

>You need to either allocate an array:
>
>	char h[80];
>
>or allocate a pointer, and then space for an array:
>
>	char *h, *malloc();
>
>	h = malloc(80);
>
>Either one of these techniques will work.

Both will, however, be limited to some fixed number of characters (80
above, and that 80 includes the '\0' stuffed by scanf to mark the end
of however many characters it stuffs).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list