yxz1684@hertz.njit.edu (Ying Zhu ee) (03/01/91)
The following is a small program from "Mastering C pointers" by Robert J. Traister. I am confusing with the pointer here. Since the r[100] is an automatic variable, after calling the "combine" the r[100] will be deallocated. Then the p will point to an unsafe place. Actually, runing this program on VAXII/GPX(ULTRIX) and Sparc( BSD UNIX ) here have different answers. Any one familiar with C can help me? Thank you! main() { char a[10], b[10], *p, *combine(); strcpy( a, "horse" ); strcpy( b, "fly" ); p=combine(a, b); printf("%s\n", p ); } char *combine(s,t) char *s, *t; { int x,y; char r[100]; strcpy(r,s); y=strlen(r); for ( x=y; *t != '\0'; ++x ) r[x] = *t++; r[x]='\0'; return(r); }
gordon@osiris.cso.uiuc.edu (John Gordon) (03/02/91)
yxz1684@hertz.njit.edu (Ying Zhu ee) writes: >main() >{ > char a[10], b[10], *p, *combine(); > strcpy( a, "horse" ); > strcpy( b, "fly" ); > p=combine(a, b); ^^^^^^^^^^^^^^^^ -> This is wrong. 'p' has not yet been correctly initialized. pointers need to be initialized before you can set them equal to something. You could change p's declaration to char p[256] and then do a strcpy(p, combine(a, b)); . --- John Gordon Internet: gordon@osiris.cso.uiuc.edu #include <disclaimer.h> gordon@cerl.cecer.army.mil #include <clever_saying.h>
torek@elf.ee.lbl.gov (Chris Torek) (03/02/91)
In article <2488@njitgw.njit.edu> yxz1684@hertz.njit.edu (Ying Zhu ee) writes: >The following is a small program from "Mastering C pointers" by Robert J. >Traister. [example deleted] ... Since the r[100] is an automatic variable, >after calling the "combine" the r[100] will be deallocated [and] p will >point to an unsafe place. Correct. If the example in this book appears exactly as shown in <2488@njitgw.njit.edu>, I would suggest either discarding the book entirely (reselling it merely pushes the bogus information on someone else) or---if this is atypical, and merely one mistake out of a great deal of correct code---advising the author and/or publisher, and marking the example in the book to note its error or repair it. (One `static' will repair this particular sample, for instance.) Note that the only excuse these days for buggy examples is when the publisher do their own re-typesetting, since book examples should be typeset by direct insertion of working code into the typesetting system. There are many C books available these days, and a large fraction of them are inexcusably bad. Do not trust any single source (except perhaps a copy of the ANSI C standard X3.159-1989). -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
scs@adam.mit.edu (Steve Summit) (03/02/91)
In article <2488@njitgw.njit.edu> yxz1684@hertz.njit.edu (Ying Zhu ee) writes: >The following is a small program from "Mastering C pointers" by Robert J. >Traister. I am confusing with the pointer here. Since the r[100] is an >automatic variable, after calling the "combine" the r[100] will be deallocated. >Then the p will point to an unsafe place. You are the innocent victim of a cruel hoax. You assumed that a book entitled "Mastering C Pointers" might have been written by someone who was, himself, a master in the use of C pointers. Evidently this is anything but the case. You would be well advised to throw this book very far away; clearly you already know more about correct pointer use than does its author. I can't quite believe that the code sample presented was actually published, but my friendly neighborhood technical bookstore has closed for the evening, so I'll have to take the complainant's word for it. In fact, returning a pointer to auto storage which is no longer valid is only the worst of the code's several problems. Let's take another look at it, shall we? (Put your rubber gloves on first, and preferably a clothespin on your nose, too.) >main() >{ > char a[10], b[10], *p, *combine(); > > strcpy( a, "horse" ); > strcpy( b, "fly" ); > > p=combine(a, b); > > printf("%s\n", p ); >} The strings a and b are initialized rather oddly, and main() neither returns a value nor calls exit(), but these are minor. The "combine" routine is far more interesting: >char *combine(s,t) >char *s, *t; >{ > int x,y; > char r[100]; > > strcpy(r,s); > y=strlen(r); > for ( x=y; *t != '\0'; ++x ) > r[x] = *t++; > r[x]='\0'; > > return(r); >} First of all, the returned result array r is, as mentioned, an automatic array, a pointer to which should not be returned. The array's size is fixed, and would be exceeded by easily imaginable calling patterns. Overflow is not checked. None of the variables have very good names. A variable named "x" is used as an index; this is somewhat unusual, especially since this is an algorithm (copying characters hither and yon) which no C programmer worthy of the title would code using an array subscript. A pointer solution is far more likely, especially in a book entitled "Mastering C Pointers." (Perhaps a second example in the book showed how to convert the routine to use all pointers.) A variable named "y" is used once, as the length of the first of the two strings to be combined; it is unneded, as the call to strlen might as well appear in the loop initialization expression. It is unfortunate that the first string has to be traversed a second time (by the call to strlen) to determine its length, when that could have been determined as a side effect of the initial copy, but the side effect is buried inside strcpy. The use of standard library routines to do part of a job is generally commendable, though (as long as the job is worth doing -- see below), so we'll let this point pass. We could rewrite the routine taking the above observations into account, but wait a minute. The middle four lines of the "combine" routine could be replaced with a call to the standard library routine strcat. Clearly, calling upon standard library routines is not considered objectionable in this code, as strcpy and strlen have been used already. Before rewriting "combine" to use only strcpy and strcat, however, we might note that "combine" is almost identical to strcat, except that strcat appends the second string to the first and returns its first argument, while "combine" tries to build a third string. But that's the part it gets most wrong. Rather than hauling in this useless "combine" routine, the author would have been much better advised to demonstrate simple implementations of the standard library routines such as strlen, strcpy, and strcat. (It would be wise to call them my_strlen, my_strcpy, and my_strcat, so that the student would not abuse a reserved identifier when compiling his own version, and to permit regression testing.) I have often though that it would be wonderful if Kernighan and Plaugher could come out with a third edition of their classic Elements of Programming Style, incorporating C examples instead of PL/I and Fortran. I thought that perhaps there were not enough published bad examples to serve as the base for such a book. Silly me. Mastering C Pointers would clearly be a mother lode. Whoops, someone else just tried to answer the original question. Let's take a look: In article <1991Mar1.235912.25133@ux1.cso.uiuc.edu> gordon@osiris.cso.uiuc.edu (John Gordon) writes: >> p=combine(a, b); > ^^^^^^^^^^^^^^^^ -> This is wrong. 'p' has not yet been correctly > initialized. pointers need to be initialized > before you can set them equal to something. Mr. Gordon needs to learn more about pointers and initialization. The only thing wrong about p's initialization here is that the pointer value that "combine" returns is bogus; this is combine's fault, not p's. Yes, pointers need to be initialized before they can be used, but what better way to initialize one than by sticking it on the left hand side of an equals sign and putting an expression of type "pointer to char" on the right? The suggestion that we > could change p's declaration to char p[256] and > then do a strcpy(p, combine(a, b)); . wouldn't hurt, although it would make the identifier "p" an array, not a pointer (see the FAQ!), which is a bit misleading. (It's also silly, in this case, since "combine" was trying to return a pointer to valid storage, although no more silly than the original code's declaring a[] and b[] and strcpying into them.) Steve Summit scs@adam.mit.edu
art@pilikia.pegasus.com (Art Neilson) (03/03/91)
In article <2488@njitgw.njit.edu> yxz1684@hertz.njit.edu (Ying Zhu ee) writes: >The following is a small program from "Mastering C pointers" by Robert J. >Traister. I am confusing with the pointer here. Since the r[100] is an >automatic variable, after calling the "combine" the r[100] will be deallocated. >Then the p will point to an unsafe place. Actually, runing this program >on VAXII/GPX(ULTRIX) and Sparc( BSD UNIX ) here have different answers. Any >one familiar with C can help me? Thank you! You are right, it is unsafe as storage for automatic r within function combine is released upon return to main. >main() >{ > char a[10], b[10], *p, *combine(); > > strcpy( a, "horse" ); > strcpy( b, "fly" ); > > p=combine(a, b); Why not use strcat(3) instead of the combine() function ? (of course you'd have to declare a[20]) p=strcat(a, b); I guess it'd defeat the purpose of the excersize. > printf("%s\n", p ); >} > >char *combine(s,t) >char *s, *t; >{ > int x,y; > char r[100]; > > strcpy(r,s); > y=strlen(r); > for ( x=y; *t != '\0'; ++x ) > r[x] = *t++; > r[x]='\0'; > > return(r); >} -- Arthur W. Neilson III | INET: art@pilikia.pegasus.com Bank of Hawaii Tech Support | UUCP: uunet!ucsd!nosc!pilikia!art