xmjschm@hscfvax.harvard.edu (MJSchmelzer) (02/08/89)
Given that gets() is unsafe because it doesn't check its input, what form of scanf() should be used? The problem I'm having is this: scanf("%s", buffer); where buffer is char[255] and the scanf statement is in a loop, the \n gets passed to the next scanf call. Another problem is if I enter, say: foo bar to this scanf-in-a-loop, it cycles through the stdin buffer twice to yield: foo bar I know I'm not saying this very well, sorry. But I figure this is a pretty basic dilemma that most folks have encountered. I mean, gets() in such a loop does just fine, ie it would return "foo bar", but I have yet to kludge up a functionally equivalent scanf(). Does this mean gets() is indispensable ? Thanks for any help/insights. -- ============== xmjschm@harvspha.BITNET ============= Mike Schmelzer xmjschm@hscfvax.harvard.edu Quotes are stupid. =====================================================
barmar@think.COM (Barry Margolin) (02/09/89)
In article <721@hscfvax.harvard.edu> xmjschm@hscfvax.harvard.edu (MJSchmelzer) writes: [Describes problems using scanf() in place of gets().] >Does this mean gets() is indispensable ? I don't think so. The simplest, safe replacement for gets() is fgets(). You'll have to specify stdin explicitly, and you'll have to strip off the trailing newline if you don't want it, but otherwise it's just what you want. Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
henry@utzoo.uucp (Henry Spencer) (02/09/89)
In article <721@hscfvax.harvard.edu> xmjschm@hscfvax.harvard.edu (MJSchmelzer) writes: >Given that gets() is unsafe because it doesn't check its input, >what form of scanf() should be used? The replacement for gets() is fgets(), not scanf(). In general it is both safer and more satisfactory to read a line into a buffer with fgets() and then pick it apart by whatever means is appropriate, which might possibly include sscanf() although it isn't really satisfactory, than to try to use scanf() directly on the input. Printf() was an experiment that worked; the same cannot be said of scanf(), at least not with anywhere near the same level of enthusiasm. -- Allegedly heard aboard Mir: "A | Henry Spencer at U of Toronto Zoology toast to comrade Van Allen!!" | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
jeenglis@nunki.usc.edu (Joe English) (02/09/89)
xmjschm@hscfvax.harvard.edu (MJSchmelzer) writes: >Given that gets() is unsafe because it doesn't check its input, >what form of scanf() should be used? [...] >Another problem is if I enter, say: >foo bar >to this scanf-in-a-loop, it cycles through the stdin buffer twice to yield: >foo >bar >I know I'm not saying this very well, sorry. But I figure this is a pretty >basic dilemma that most folks have encountered. I mean, gets() in such a >loop does just fine, ie it would return "foo bar", but I have yet to >kludge up a functionally equivalent scanf(). The truth is, scanf is pretty lousy for string input. It's better to use fgets(), and if that's not quite what you want, it's a trivial job to write your own getline() function. Here's mine (It doesn't do any error checking, but that's easy to add. I never write utility functions with the assumption that I'm going to shoot myself in the foot by passing a null pointer or something like that, and I usually trust that getc() is not going to fail): #include <stdio.h> /* int fgetline(FILE *fp, int size, char *buf) Reads characters from fp into buf, '\0'-terminates buf. stops when a newline is encountered or size-1 characters have been read. Does not store final newline. size includes terminating '\0', so size must be at least 2. Returns: number of characters read (not counting \n), or -1 if at end of file before reading. */ int fgetline(FILE *fp,int size, char *buf) { int n = 0,ch; if (feof(fp)) return -1; ch = getc(fp); while ((ch != EOF) && (ch != '\n') && (++n < size)) { *buf++ = (char) ch; ch = getc(fp); } *buf = '\0' return n-1; } --Joe English jeenglis@nunki.usc.edu
xmjschm@hscfvax.harvard.edu (MJSchmelzer) (02/09/89)
Thanks to everyone who suggested using fgets() instead of gets(). (There, that was my summary of all the answers mailed to me.) fgets() hadn't even occurred to me because I naively assumed it was like fscanf() and fprint() in that it only differed by adding a stream parameter. Fortunately, fgets() takes 3 parameters, including the all-important buffer-size parameter. Here is the prototype (K&R2, p. 165): char * fgets(char * s, int n, FILE * iop); One final question: No one mentioned scanf("%255s", buffer). This _does_ seem wrong to me, but I can't quite pin it down. Comments? Thanks again! -- ============== xmjschm@harvspha.BITNET ====== There are two kinds of people: Mike Schmelzer xmjschm@hscfvax.harvard.edu They call each other "boring" ============================================== and "weird." -Me
guy@auspex.UUCP (Guy Harris) (02/09/89)
>I mean, gets() in such a loop does just fine, ie it would return "foo >bar", but I have yet to kludge up a functionally equivalent scanf(). > >Does this mean gets() is indispensable ? No, it means no such thing. Look under "f", as in "fgets()" in your reference manual. Yes, it leaves a '\n' at the end of the line, but it's not *that* big of a pain to remove it.
lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (02/09/89)
In article <1989Feb8.223554.27192@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >Printf() was an experiment that worked; The printf we have today is not the same as the original (pre K&R) printf, its first argument was a file descriptor. I think the file descriptor was dropped from printf when fprintf and FILEs were invented. -- Larry Cipriani, att!cbnews!lvc or lvc@cbnews.att.com swtch(); /* no deposit, no return */
henry@utzoo.uucp (Henry Spencer) (02/10/89)
In article <3909@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes: >>Printf() was an experiment that worked; >The printf we have today is not the same as the original (pre K&R) printf, >its first argument was a file descriptor. I think the file descriptor was >dropped from printf when fprintf and FILEs were invented. Uh, can you cite references for that? Printf certainly did not take a file descriptor as of Fifth Edition Unix, aka V5, released around the end of 1974 -- I remember V5. I remember the arrival of fprintf and FILEs, and the arrival of K&R; there was no change to printf on either occasion. Well, actually, printf did pick up features in its format string at times, but it hasn't taken a descriptor argument since I've known it. This lack was considered really annoying by a lot of people, and most everybody was happy to see stdio arrive with fprintf. (There was an earlier "portable" library that may have included such a thing -- I don't remember it too clearly -- but it had other problems and wasn't really suitable for general use.) -- The Earth is our mother; | Henry Spencer at U of Toronto Zoology our nine months are up. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
karl@haddock.ima.isc.com (Karl Heuer) (02/14/89)
In article <722@hscfvax.harvard.edu> xmjschm@hscfvax.UUCP (R00100@MJSchmelzer) writes: >One final question: No one mentioned scanf("%255s", buffer) [as a gets() >replacement]. This _does_ seem wrong to me, but I can't quite pin it down. >Comments? I guess my mail didn't get through. %s is wrong because it scans a token rather than a line, but I did mention scanf("%254[^\n]%*c", buffer) as a possible solution. (I used 254 since you said the buffer was char[255], and we need one byte for the trailing \0.) This no longer crashes on long lines, but it still fails to detect them. (This could be fixed via char ch; if (scanf("%254[^\n]%c", buffer, &ch) != 2 || ch != '\n') error(); , but fgets() seems cleaner.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint