Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!gem.mps.ohio-state.edu!wuarchive!udel!haven!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Re: Help... Message-ID: <20098@mimsy.UUCP> Date: 10 Oct 89 18:48:28 GMT References: <731@carroll1.UUCP> <39902@bu-cs.BU.EDU> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 129 >>>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@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 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 . 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 ; being in an expression (rvalue) context, we apply the rule for C arrays in such contexts and change this to . Finally, we have h also in an expression context. H is (assuming our compiler has accepted it) and we apply the same rule, obtaining . The two values are packaged up, mailed to the function indicated by the 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 . 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@cs.umd.edu Path: uunet!mimsy!chris