roper@uw-june.UUCP (Michael Roper) (05/04/87)
Can anyone please explain the behavior of the following few lines of code? It compiles without errors, and as written produces these two output lines: <arg.U> <arg.+> where 'arg' is the first string entered on the command line, and '+' is the printable representation of ^L (the symbol for female). The two output lines should be identical. If the source line in main is changed from "strcat (s, ".U");" to "strcat (s, ".X");", the expected output is produced: <arg.X> <arg.X> What am I missing? -------- #include <stdio.h> #include <string.h> do_nothing (arg_string) char *arg_string; { char *dont_care_str; printf ("<%s>\n", arg_string); dont_care_str = strdup ("don't care"); printf ("<%s>\n", arg_string); } main (argc, argv) int argc; char *argv[]; { char *s; s = strdup (argv[1]); strcat (s, ".U"); do_nothing (s); } -- ---Michael Roper--- * * "Calvin, do you believe in God?" ARPA: roper@june.cs.washington.edu * UUCP: ihnp4!uw-beaver!uw-june!roper * "Well...SOMEBODY is out to get me."
farren@hoptoad.uucp (Mike Farren) (05/04/87)
In article <2454@uw-june.UUCP> roper@uw-june.UUCP (Michael Roper) writes: >Can anyone please explain the behavior of the following few lines of code? [which doesn't work] > >main (argc, argv) >int argc; >char *argv[]; >{ > char *s; > > s = strdup (argv[1]); > strcat (s, ".U"); > do_nothing (s); >} Note that you are defining s (and, later, do_nothing_str) as a pointer to char, but you are never creating an array that the pointers will point to. As a result, the strcat and strdup routines, which expect that the pointers they receive WILL point to such arrays, go ahead and blindly copy the strings they have received as arguments to the place that the pointers point to, which is the address represented by whatever happened to be in the pointers when the routine was entered. It's amazing that the routine works as well as it does - give it "fred" as an argument, and it even works correctly - but this is just chance. Remember - pointers point to things, arrays hold things, and never the twain should meet! -- ---------------- "... if the church put in half the time on covetousness Mike Farren that it does on lust, this would be a better world ..." hoptoad!farren Garrison Keillor, "Lake Wobegon Days"
kanevsky@tom.columbia.edu (Paul Kanevsky) (05/04/87)
In article <2088@hoptoad.uucp> farren@hoptoad.UUCP (Mike Farren) writes: >In article <2454@uw-june.UUCP> roper@uw-june.UUCP (Michael Roper) writes: >> >>main (argc, argv) >>int argc; >>char *argv[]; >>{ >> char *s; >> >> s = strdup (argv[1]); >> strcat (s, ".U"); >> do_nothing (s); >>} > >Note that you are defining s (and, later, do_nothing_str) as a pointer to >char, but you are never creating an array that the pointers will point to. [the rest of the message...] >hoptoad!farren Garrison Keillor, "Lake Wobegon Days" This is not strictly true. In fact, strdup function will allocate space enough to fit the argument string. The mistake here is in the strcat(s, ".U") which attempts to add to the end of the allocated space. Since space was allocated only to accept the original string, anything added to it will be writing to the outside memory that might belong to other variables. - Paul Paul Kanevsky Columbia University, NY kanevsky@tom.columbia.edu
perry@inteloa.intel.com (Perry The Cynic) (05/05/87)
In article <2454@uw-june.UUCP> roper@uw-june.UUCP (Michael Roper) writes: >Can anyone please explain the behavior of the following few lines of code? > [...showing a sample program containing the following lines of code:] > s = strdup (argv[1]); > strcat (s, ".U"); *strdup* allocates exactly enough memory to hold a copy of its argument plus the zero byte terminator. Your *strcat* tries to write *beyond* this area, effectively corrupting the heap area. The next allocation (strdup) that you (dynamically) make clobbers the byte holding the "U" (the "." replaces the zero byte and is `safe' :-). -- perry ------------------------------------------------------------------------ << Perry The Cynic >> =>> perry@inteloa.intel.com <<= ...!tektronix!ogcvax!omepd!inteloa!perry (Peter Kiehtreiber) ...!verdix!omepd!inteloa!perry
geoffs@gssc.UUCP (Geoff Shapiro) (05/06/87)
In article <2088@hoptoad.uucp> farren@hoptoad.UUCP (Mike Farren) writes: >In article <2454@uw-june.UUCP> roper@uw-june.UUCP (Michael Roper) writes: >>Can anyone please explain the behavior of the following few lines of code? >[which doesn't work] >> >> char *s; >> >> s = strdup (argv[1]); >> strcat (s, ".U"); >> do_nothing (s); > >Note that you are defining s (and, later, do_nothing_str) as a pointer to >char, but you are never creating an array that the pointers will point to. >As a result, the strcat and strdup routines, which expect that the pointers >they receive WILL point to such arrays, go ahead and blindly copy the strings >they have received as arguments to the place that the pointers point to, >which is the address represented by whatever happened to be in the pointers >when the routine was entered.... Mike Faren's explanation would be a sufficient cause of the problem if the explanation were correct, but I believe that Mike Faren has been led a little bit astray in his understanding of what strdup expects. Strdup takes a pointer to an existing string and returns a pointer to a duplicate of the passed in string; it internally calls malloc to allocate enough memory to hold the cloned string. What I do see as a possible problem, is that strdup probably only allocates enough bytes to hold a string of the length of the passed-in string. Therefore, when Mike Roper uses strcat to append extra characters onto the end of the dup'ed string, he may be overwriting memory not belonging to the string! Your guess is as good as mine as to what effect this has. Geoffs Graphic Software Systems Beaverton, Or. (503) 641-2200