If I use scanf() to get a single integer from a user, will calling gets()
with a sufficently allocated array prompt the user for input? My situation
is this.. I am currently doing an exercise in class with scanf(), gets(),
etc. and we have been given an example program by the instructor which is
designed to show how to deal with extra characters recieved by scanf(). Here
is the program..
#include <stdio.h>
void clear_kb(void);
main()
{
int age;
char name[20];
puts("Enter your age.");
/*possibility of extra characters being entered */
scanf("%d", &age);
clear_kb();
puts("Enter your first name.");
scanf("%d", name);
printf("Your age is %d.\n", age);
printf("Your name is %s.\n", name);
}
void clear_kb(void)
{
/*my question is if it will prompt for input if no extra characters are
left in stdin stream
and if not, why? basically I just need an elaboration */
char junk[80];
gets(junk);
}
Do this instead:
char buff[128];
fgets(buff,128,stdin);
If you then want to acquire an integer from the input:
int x;
sscanf(buff,"%d",&x);
This way of accepting user input is safe and predictable.
Paul Lutus
Andy White wrote in message <36a17...@news.infowest.com>...
Use fgets as a replacement for gets &
fgets + sscanf as a replacement for scanf.
Anyway with regards to you question,
lets say the user enters his age as 15 & presses enter (i.e doesn't
doesn't leave extra chars) but still the enter is itself the extra
char. So scanf gets the 15 & gets gets the enter. So you prg won't wait
for more input.
cheers,
Shiva
comp.lang.c++ FAQ :http://www.cerfnet.com/~mpcline/c++-faq-lite/
http://members.xoom.com
In article <36a17...@news.infowest.com>,
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
I would call isdigit() on each of the characters in buff first, if the
intention is to convert only decimal digit characters. if isdigit() returns
false, then perhaps print an error message such as "Non-numeric found. Please
enter only 0-9."
if a character passed to
> sscanf(buff,"%d",&x);
>
> This way of accepting user input is safe and predictable.
>
> Paul Lutus
>
> Andy White wrote in message <36a17...@news.infowest.com>...
And using sscanf in this way:
int n = sscanf(buff,"%d",&x);
will provide a count of successfully converted numbers.
Paul Lutus
j...@parmetpc.volpe.dot.gov wrote in message
<77vjpq$ppk$1...@nnrp1.dejanews.com>...
TIA
Shirley
Paul Lutus wrote:
>
> Don't use scanf, and don't use gets. They are both quirky and dangerous.
>
> Do this instead:
>
> char buff[128];
>
> fgets(buff,128,stdin);
>
> If you then want to acquire an integer from the input:
>
> int x;
>
That is the point of specifying the maximum number of accepted characters --
the fgets routine will not accept any more characters from the input stream,
and it will never write beyond the size of the character array.
Why not compile and test the routine to satisfy yourself that it is
well-behaved? You will thereby get answers to questions not easily
expressible in a finite number of words.
Paul Lutus
Shirley Barton wrote in message <36A3BBFB...@WontWork.net>...
Respective ages are 1 2 3
However, if the user inputs 2 then 222 then 3, said user never gets a chance at
inputing age 3. The output is:
Respective ages are 1 22 2
This is the unpredicatabilty to which I was refering, at least it's
unpredicatible from the users standpoint! Sure, making the buffer is
sufficently *large* will prevent this
problem, wouldn't that same solution also prevent gets() from overflowing a
buffer??
So is it fair to say that both gets() and fgets() are unpredictable?
Just Curious
Shirley
#include <stdio.h>
int main() {
int age1, age2, age3;
char buff[3];
fprintf(stdout, "Enter age 1: ");
fgets(buff,3,stdin);
sscanf(buff,"%d",&age1);
fprintf(stdout, "Enter age 2: ");
fgets(buff, 3, stdin);
sscanf(buff,"%d",&age2);
fprintf(stdout, "Enter age 3: ");
fgets(buff, 3, stdin);
sscanf(buff,"%d",&age3);
printf("Respective ages are %d %d %d\n",
age1, age2, age3);
return 0;
}
Paul Lutus wrote:
<snip>
Not at all. fgets() is safe and predictable, and gets() is neither safe nor
predictable.
Here is your example made rational:
int main() {
int age1, age2, age3;
char buff[64];
fprintf(stdout, "Enter age 1: ");
fgets(buff,64,stdin);
sscanf(buff,"%d",&age1);
fprintf(stdout, "Enter age 2: ");
fgets(buff, 64, stdin);
sscanf(buff,"%d",&age2);
fprintf(stdout, "Enter age 3: ");
fgets(buff, 64, stdin);
sscanf(buff,"%d",&age3);
printf("Respective ages are %d %d %d\n",
age1, age2, age3);
return 0;
}
It is always possible to take a safe, predictable function and make it
fail -- but you have to try. The most important thing is to understand the
behavior of the functions you are using.
Why do you find this confusing? If your user might enter 3 characters, make
the buffer larger than 3 characters -- it must contain a terminating
character, so you must make it (at the very least) one character larger than
the largest expected input.
Paul Lutus
Shirley Barton wrote in message <36A4005D...@WontWork.net>...
<snip>
> I may be missing something here, I realize fgets() is much safer compared to
> gets()
> as it prevents buffer overflow. But let me demonstrate in a finite number of
> words
> the source of my confusion. From the example given below, if the user inputs 1
> then 2 then 3 at each prompt the output is:
>
> Respective ages are 1 2 3
>
> However, if the user inputs 2 then 222 then 3, said user never gets a chance at
> inputing age 3. The output is:
>
> Respective ages are 1 22 2
>
> This is the unpredicatabilty to which I was refering, at least it's
> unpredicatible from the users standpoint! Sure, making the buffer is
> sufficently *large* will prevent this
> problem, wouldn't that same solution also prevent gets() from overflowing a
> buffer??
> So is it fair to say that both gets() and fgets() are unpredictable?
fgets() leaves a newline in the line it reads in for one reason only -
if the last character of the string you've read in using fgets() is NOT
a newline (and EOF has not occurred), then you can be pretty much
certain that you haven't read the line in completely. So you can always
tell whether or not you've read the line in completely or not and take
action accordingly. Where's the unpredictability here????
--
{ Sunil Rao }
"From life's dawn it is drawn down,
Abel is Cain's brother and breasts they have sucked the same."
- HOPKINS, Gerard Manley, in "The Wreck of the Deutschland".
You mean there's more than one way to skin a cat?
:)
Regards,
Jon
> Paul Lutus
>
> j...@parmetpc.volpe.dot.gov wrote in message
> <77vjpq$ppk$1...@nnrp1.dejanews.com>...
> >In article <77rvt4$7dg$1...@remarQ.com>,
> > "Paul Lutus" <nos...@nosite.com> wrote:
> >> Don't use scanf, and don't use gets. They are both quirky and dangerous.
> >>
> >> Do this instead:
> >>
> >> char buff[128];
> >>
> >> fgets(buff,128,stdin);
> >>
> >> If you then want to acquire an integer from the input:
> >>
> >> int x;
> >
> >I would call isdigit() on each of the characters in buff first, if the
> >intention is to convert only decimal digit characters. if isdigit() returns
> >false, then perhaps print an error message such as "Non-numeric found.
> Please
> >enter only 0-9."
> >
> >if a character passed to
> >> sscanf(buff,"%d",&x);
> >>
> >> This way of accepting user input is safe and predictable.
> >>
Thanks for answering my original question, there is really no unpredictability
there. Once I determine the last character of the string I've read in using
fgets() is NOT a newline and EOF hasn't occurred, is there a way to clear
the unwanted characters from the IO input stream and then redo the fgets()
operation so it behaves as originally intended?
Shirley
Sunil Rao wrote:
>
> Shirley Barton wrote:
>
> > I may be missing something here, I realize fgets() is much safer compared to
> > gets()
> > as it prevents buffer overflow. But let me demonstrate in a finite number of
> > words
> > the source of my confusion. From the example given below, if the user inputs 1
> > then 2 then 3 at each prompt the output is:
> >
> > Respective ages are 1 2 3
> >
> > However, if the user inputs 2 then 222 then 3, said user never gets a chance at
> > inputing age 3. The output is:
> >
> > Respective ages are 1 22 2
> >
> > This is the unpredicatabilty to which I was refering, at least it's
> > unpredicatible from the users standpoint! Sure, making the buffer is
> > sufficently *large* will prevent this
> > problem, wouldn't that same solution also prevent gets() from overflowing a
> > buffer??
> > So is it fair to say that both gets() and fgets() are unpredictable?
> --
Tell me in which special case(s) isdigit will reject the character-coded
integer value of a numeric digit. Please include your definition of 'number'
so we're on the same page. The original code dealt with an INTEGER age.
> And using sscanf in this way:
>
> int n = sscanf(buff,"%d",&x);
>
> will provide a count of successfully converted numbers.
The Solaris man page I read says:
These routines return the number of successfully matched and
assigned input items; this number can be 0 in the event of
an early matching failure between an input character and the
control string. If the input ends before the first matching
failure or conversion, EOF is returned.
I will argue below that 'matched and assigned' is apparently somewhat
different from 'successfully converted.' I present a (perhaps) pathological
case where sscanf returns the correct value for the case provided, user may
never know what hit them.
> Paul Lutus
I posted the previous reply a little too quickly wihtout thinking about it
first.
I quickly typed in the following bit of sloppy code:
/************ BEGIN **************/
#include <stdio.h>
main (int argc, charr *argv[])
{
char buff[128];
int feed_me_an_integer,
printf("Please enter an INTEGER -> ");
fgets(buff,128,stdin);
n = sscanf(buff,"%d",&feed_me_an_integer);
printf ("N= %d, X=%d\n",n,x);
exit(0);
/*********** END *****************/
Here are the output from some sample runs:
Please enter an INTEGER -> 1
N= 1, X=1
Please enter an INTEGER -> 0
N= 1, X=0
Please enter an INTEGER -> -1
N= 1, X=-1
Please enter an INTEGER -> 0.0
N= 1, X=0
Please enter an INTEGER -> 111111111111111111111111111111111111
N= 1, X=-954437177
Please enter an INTEGER -> HI :)
N= 0, X=0
Please enter an INTEGER -> 3
N= 1, X=3
Please enter an INTEGER -> 3 and a half
N= 1, X=3
Please enter an INTEGER -> 31/2
N= 1, X=31
Please enter an INTEGER -> 1 3
N= 1, X=1
Please enter an INTEGER ->
N= -1, X=0
Please enter an INTEGER -> 0.3
N= 1, X=0
The next to the last case was me hitting the ENTER key by itself.
The last case, though, is the interesting one, to me at least. It would appear
in the last case, that there was a conversion which took place, silently. Some
might argue that the conversion was quite loud :)
sscanf reported that the number of successfully converted numbers was 1. I
will argue that the program was not successfull at informing the user of
this.
Of course, one might argue the user should obey the program and know what the
word INTEGER means, but then my entire point will have been missed wouldn't
it?
Perhaps this implementation is broken according to the ANSI spec? It's AIX, by
the way, and I don't think it's broken :) Can I know when I am porting my code
whether another implementation will produce N=0? Can I afford to purchase the
spec? Maybe.
Can I at least call isdigit to find out if the input is "valid" so that I
KNOW there won't be any side effects going on behind my back? You bet I'm
gonna play it safe :) There are several other checks (for example, attempting
to input more than 128 characters, in this case) that can be made on the
input data, but I hope my point was made.
I won't argue whether, in the last case, sscanf failed miserably. The standard
people will most likely tear my head off, claiming it did exactly what a
conforming implementation should do. The safe bet is that they're right :)
I suppose you can argue that the number 0 was successfully converted. I can't
deny that. The user entered 0.3 though. Look at the case where buff contains
"1 3". Did the user accidentally hit the space key and really mean to enter
13? isdigit() catches the space character. What did sscanf do?
I'm not saying I would go out and look for ways to break something, just to
prove a point. However, there can be much more subtle things which occur in a
program when safe coding practices aren't employed, especially where user
input is concerned! The above is a specific example of a more general method
I use when programming.
I obey two closely related laws:
1) Assume something most likley is broken (man pages, comments, one's own code
more often than not!). Beat the crap out of the code to find out what it
ACTUALLY does.
2) Be careful with a routine that someone else wrote, you don't know where
it's been :)
Regards,
Jon
Sincerely
Shirley
<< Since I don't have a copy of "Guiness Book of World Records" handy, how
am I gonna know the longest name length known to mankind? >>
This is rather argumentative, but you simply set the buffer length to a
length greater than the longest expected input, and (if necessary) you
gently scold the user for exceeding the specified length:
#include <stdio.h>
int main()
{
char buff[128];
int len;
printf("Enter a name (less than 64 characters): ");
fflush(stdout);
fgets(buff,128,stdin);
len = strlen(buff);
if(len >= 64) {
printf("No one listens to me!!!\n");
}
else if(len > 0) {
buff[len-1] = 0; /* remove terminating linefeed */
printf("You entered \"%s\".",buff);
}
return 0;
}
Paul Lutus
Shirley Barton wrote in message <36A4AAF8...@WontWork.net>...
>Hi Paul, is this way of accepting really predictable? For example, what if the
>silly user enters 129 chars at the user prompt, doesn't this cause havoc with
>the next call that tries to read a line from stdin.
There is havoc, and then there is real major havoc. With fgets() into a
fixed size buffer followed by sscanf(), invalid input will ordinarily be
recognized as invalid input and rejected by your program, if you take any
care about it. With gets(), input larger than your buffer will crash
your program, and there is nothing you can do about it either before or
after the fact. scanf() by itself can be safe, but finding where to
restart scanning after an error can be tricky.
While you're nit picking, you might stick an fflush(stdout) here.
) fgets(buff,64,stdin);
Mike
--
----
char *p="char *p=%c%s%c;main(){printf(p,34,p,34);}";main(){printf(p,34,p,34);}
This message made from 100% recycled bits.
I don't speak for Alcatel <- They make me say that.
> ) fprintf(stdout, "Enter age 1: ");
>
> While you're nit picking, you might stick an fflush(stdout) here.
>
> ) fgets(buff,64,stdin);
>
An fflush is entirely redundant. When you do input from
stdin, stdout is flushed automatically.
This is wrong. In C, these streams are asynchronous.
Please be a little more careful before making categorical statements.
--
Martin Ambuhl (mam...@earthlink.net)
Note: mam...@tiac.net will soon be inactive
try instead fgetc.
just my 2c
// anders
Shirley Barton <Spam...@WontWork.net> wrote in message
news:36A4AAF8...@WontWork.net...
>Sorry, I had this silly notion that a program should be able to
>recover and proceed no matter how many characters my user typed. I
>can foresee certain situations where it might be difficult to predict
>the amount of characters needed. Since I don't have a copy of
>"Guiness Book of World Records" handy, how am I gonna know the longest
>name length known to mankind?
*yawn*, this must be a troll.
For those of you real programming students, write a Standard C program
that reads in a line of input of arbitrary length and prints out two
lines. The first line of output should be the input line reversed.
The second line of output should be the input line not reversed. The
program cannot use any arrays, but otherwise can use any Standard C
feature. For your convenience, however, you can assume that the input
is no larger than the maximum amount of memory available to your
platform (i.e., you shouldn't need to resort to FILE I/O for storage,
but such a solution would also be acceptable).
For you C++ students, go ahead and replace /C/ above with /C++/, but
this exercise should be trivial.
--
James C. Hu <j...@cs.wustl.edu> Computer Science Doctoral Candidate
http://www.cs.wustl.edu/~jxh/ Washington University in Saint Louis
>>>>>>>>>>>>> I use *SpamBeGone* <URL:http://www.internz.com/SpamBeGone/>
My post was a poor attempt at humor, I did not intend for it to sound so
hostile, nor garner the attention it so wrongfully deserved. I sincerely
apologize to you Mr. Lutus, as always, your responses are very enlightening and
enrich my understanding of the C /C++ language. I, as well
as many others I'm sure, appreciate the time and effort you put in.
As Mr. Hu so pointedly noted, I'm not a student of any University. But I do
have a burning desire
to learn and this may may be one of the reasons I came off so harsh. As I am
really struggling grasping the IO stream functionality. I was not trying to
break the input routine, so much
as to understand why it broke and how to fix it once it got broke in the first
place. My question posted the 19th of Jan to Sunil Rao in this thread,
demonstrates further may lack of understanding as to how IO streams are
implemented.
Best Wishes
Shirley
#include <stdio.h>
void show_char(int ch)
{
if (ch == '\n' || ch == EOF)
return;
else
{
ch = fgetc(stdin);
show_char(ch);
}
if (ch)
{
fprintf(stdout, "%c", ch);
fflush(stdout);
}
}
int main()
{
show_char(0);
return 0;
Not a chance. In C++, cout is tied to cin and will therefore get flushed
automatically when input is expected, but not so in C.
No, not really. You can use ungetch() to push ONE character back onto
the input stream (this is particularly useful if you're writing a
parser), but otherwise you'd probably want to use fgets() in a
do...while loop in conjunction with a dynamically allocated buffer using
realloc() (so you can resize the allocated buffer). C++ makes this
easier if you use "string" but beware that any implementation is going
to do much the same stuff and probably more behind the scenes anyway!
Nice stab; but you're only fulfilling one half of the spec - the second
half wants you to spit the original line back out unreversed!!! Fior
this, you'll need to use dynamic memory allocation - realloc() is a
particularly useful function here!!!
> #include <stdio.h>
> void show_char(int ch)
> {
> if (ch == '\n' || ch == EOF)
> return;
> else
> {
> ch = fgetc(stdin);
> show_char(ch);
> }
>
> if (ch)
> {
> fprintf(stdout, "%c", ch);
What's wrong with good old putchar() ??? Does exactly the same thing!
> fflush(stdout);
> }
> }
> int main()
> {
> show_char(0);
> return 0;
> }
--
Then MY recommendation is that you write a custom function that accepts
input up to some limit - a sort of "data-entry" utility function.
--
<<<<<<<<<<<<<<<< Blue Skies >>>>>>>>>>>>>>>>
< Michael J. Tobler: mto...@no-spam-ibm.net >
< **remove "no-spam-" when replying** >
< http://www.webbrew.com/toblermj >
< MJTobler:Instant Messenger; 28038932:ICQ >
<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>
Mike
In article <36A53C5A...@WontWork.net>,
Shirley Barton <Spam...@WontWork.net> wrote:
)<< This is rather argumentative....>>
)
)My post was a poor attempt at humor, I did not intend for it to sound so
)hostile, nor garner the attention it so wrongfully deserved. I sincerely
)apologize to you Mr. Lutus, as always, your responses are very enlightening and
)enrich my understanding of the C /C++ language. I, as well
)as many others I'm sure, appreciate the time and effort you put in.
)
)As Mr. Hu so pointedly noted, I'm not a student of any University. But I do
)have a burning desire
)to learn and this may may be one of the reasons I came off so harsh. As I am
)really struggling grasping the IO stream functionality. I was not trying to
)break the input routine, so much
)as to understand why it broke and how to fix it once it got broke in the first
)place. My question posted the 19th of Jan to Sunil Rao in this thread,
)demonstrates further may lack of understanding as to how IO streams are
)implemented.
)
)Best Wishes
)Shirley
)
)
Very rude.
In article <36A50420...@sensor.com>, Ron Natalie <r...@sensor.com> wrote:
)Mike McCarty wrote:
)
)> ) fprintf(stdout, "Enter age 1: ");
)>
)> While you're nit picking, you might stick an fflush(stdout) here.
)>
)> ) fgets(buff,64,stdin);
)>
)
)An fflush is entirely redundant. When you do input from
)stdin, stdout is flushed automatically.
As I stated in my e-mail reply, in which I quoted the relevant portions
of the ANSI/ISO C Standard, fflush(.) is not redundant in this context.
Mike
>> char buff[128];
>>
>> fgets(buff,128,stdin);
>>
>> If you then want to acquire an integer from the input:
>>
>> int x;
>
>I would call isdigit() on each of the characters in buff first, if the
>intention is to convert only decimal digit characters. if isdigit() returns
>false, then perhaps print an error message such as "Non-numeric found. Please
>enter only 0-9."
Why bother? The suggestion to use sscanf() is a perfectly sound one,
although not quite complete. He neglected to test the return of
sscanf() for the correct number of items read.
if(sscanf(buff, "%d", &x) != 1)
/* error */
--
----- Dig the EVEN NEWER, MORE IMPROVED news sig!! -----
-------------- Shaggy was here! ---------------
http://aardvark.apana.org.au/~phaywood/
============= Ain't I'm a dawg!! ==============
>I may be missing something here, I realize fgets() is much safer compared to
>gets()
>as it prevents buffer overflow. But let me demonstrate in a finite number of
>words
>the source of my confusion. From the example given below, if the user inputs 1
>then 2 then 3 at each prompt the output is:
>
> Respective ages are 1 2 3
>
>However, if the user inputs 2 then 222 then 3, said user never gets a chance at
>inputing age 3. The output is:
>
> Respective ages are 1 22 2
>
>This is the unpredicatabilty to which I was refering, at least it's
>unpredicatible from the users standpoint! Sure, making the buffer is
>sufficently *large* will prevent this
>problem, wouldn't that same solution also prevent gets() from overflowing a
>buffer??
No. Some idiot user might just enter more than that, and that could
crash the system. Using fgets(), OTOH, at least insures that the
buffer is not overflown, even if the next fgets() call reads what's
left in the input stream. Of course, if that happens it's the idiot
user's own fault for entering that many characters. :) And a well
designed program can work around that problem to a degree, anyhow.
>So is it fair to say that both gets() and fgets() are unpredictable?
No. fgets() is predictable. You always know that it will not
overflow the buffer. Users, OTOH, are unpredictable. It's their
bonehead mistakes you have to watch out for. Using fgets() is just
part of the way to do that.
><< Why do you find this confusing? If your user might enter 3 characters, make
> the buffer larger than 3 characters -- it must contain a terminating
> character, so you must make it (at the very least) one character larger than
> the largest expected input >>
>
>Actually my user may type in 65 characters :-). Sorry, I had this silly notion
>that
>a user-friendly program should be able to recover and proceed no matter how many
>characters my user typed. I can foresee certain situations where it might be
User friendliness is one thing. Going out of your way to deal with
some fool who is trying to crash your program is quite another. What
you do is allow for a reasonable ammount of user error, but if the
user is such a dope as to enter 65 characters when asked for his age,
maybe he won't even notice the program isn't doing what it should. :)
>An fflush is entirely redundant. When you do input from
>stdin, stdout is flushed automatically.
Uh, since when? stdin and stdout could point to two entirely
defferent and unrelated devices. On most systems they both happen to
be the console or terminal, and even then one does not rely on the
other. Using stdin does not affect stdout.
>Groovy hepcat Shirley Barton was jivin' on 19 Jan 1999 15:47:28 GMT in
>comp.os.msdos.programmer.
>Re: the gets() function's a cool scene! Dig it!
>
>><< Why do you find this confusing? If your user might enter 3 characters, make
>> the buffer larger than 3 characters -- it must contain a terminating
>> character, so you must make it (at the very least) one character larger than
>> the largest expected input >>
>>
>>Actually my user may type in 65 characters :-). Sorry, I had this silly notion
>>that
>>a user-friendly program should be able to recover and proceed no matter how many
>>characters my user typed. I can foresee certain situations where it might be
>
> User friendliness is one thing. Going out of your way to deal with
>some fool who is trying to crash your program is quite another. What
>you do is allow for a reasonable ammount of user error, but if the
>user is such a dope as to enter 65 characters when asked for his age,
>maybe he won't even notice the program isn't doing what it should. :)
Right. We should always punish someone who gets distracted by a
coworker and accidently puts his elbow on the keyboard and anyone who
would use a computer with a cat in the room obviously doesn't deserve
the courtesy of reasonable error messages. :-)
As errors get more unlikely, the need for nice error messages and
recovery is reduced, but under no a production program should not
appear to work when given invalid (note that I say invalid, not
incorrect) input.
--
Michael M Rubenstein
Sometimes that "fool" is another machine :)
The input might be obtained from a user's keyboard or a another socket, it
doesn't matter. The concept of error checking an input can be made generic. It
becomes an attitude which is applied to any section of code.
I don't see any problem in making a routine handle the possibility that the
input has become corrupted. Who knows, I may have to pass that input to one
of your routines. Error checking it for you makes your code function properly
more often and gives you time to concentrate on other things.
> you do is allow for a reasonable ammount of user error, but if the
> user is such a dope as to enter 65 characters when asked for his age,
> maybe he won't even notice the program isn't doing what it should. :)
Yeah, and in a mission critical environment, hopefully someone will notice
early on in the testing phase.
*sigh*
Regards,
Jon
Note that the program has some important characteristics.
- It only consists of one function.
- It uses very short variable names
These keep the LOC down, increasing maintainability.
I could have left out all comments to further decrease the LOC, but our
style guide forbids this.
/*************************************************************
*
* Reverse.c
*
* Date written: 22 jan 99.
* Author: Martijn Lievaart
* Version 1.1
*
* Revision history:
*
* 1.0 MLI. 22 jan 98 Initial version
* 1.1 MLI. 22 jan 98 Obfuscated a bit.
*
* Copyright 1999 by Martijn Lievaart
* This program can and should be modified by everyone. Pass it on!
* Just don't tell them it came from me.
*
*/
const char *version = "reverse v1.1";
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node *prev;
int c;
};
int main(int argc, char **argv)
{
struct node *p;
switch (argc)
{
case -1:
argc = getchar();
p = (struct node *)(void *)argv[0];
if (argc==EOF || argc=='\n')
{
struct node *cur = NULL, *p2;
for (p2=p; p2; p2=p2->prev)
putchar(p2->c);
putchar('\n');
while (cur != p)
{
for (p2=p; p2->prev!=cur; p2=p2->prev)
;
putchar(p2->c);
cur=p2;
}
putchar('\n');
}
else
{
struct node n;
n.prev = p;
n.c = argc;
p = &n;
main(-1, (void *)&p);
}
break;
case 1:
p=NULL;
main(-1, (void *)&p);
if (ferror(stdin))
{
perror("error reading input");
exit(EXIT_FAILURE);
}
break;
case 2:
if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
{
puts(version);
break;
}
/* nice touch, we don't actually do anything for the help flags */
/* fallthrough */
default:
printf("usage: %s [options]\n\n"
"Reads a line of input and prints out that line in reverse and
as-is.\n\n"
"flags: -h or --help: prints this screen\n",
" -v or --version: prints version number\n",
argv[0]);
}
return EXIT_SUCCESS;
}
</TONGUE IN CHEEK>
Cheers,
Martijn
PS. Don't take this to seriously. Anyone that writes production code like
this should be shot on sight. ;^>
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
[ snip ]
>struct node
>{
> struct node *prev;
> int c;
>};
>
>int main(int argc, char **argv)
>{
> struct node *p;
> switch (argc)
> {
> case -1:
> argc = getchar();
> p = (struct node *)(void *)argv[0];
[ snip ]
> main(-1, (void *)&p);
> }
> break;
[ snip ]
You disclaimer notwithstanding, the standard does not guarantee that
your pointer tricks will work. You have cast a pointer to a pointer
to struct node to a void *. This in turn is assigned to a variable of
type pointer to pointer to char. This variable is then dereferenced
and the result case to a void * and assigned to a variable of type
pointer to struct node.
The problem is that when you dereference argv above, the value that
you are dereferencing is not guaranteed to have the same
representation as the value that was produced when you applied the &
operator on p.
I think if you want to do this portably, you will need to do it in
multiple steps.
int main (int argc, char **argv)
{
struct node *p;
char *p_ptr;
/* ... */
p = (void *) argv[0];
/* ... */
p_ptr = (void *) p;
main (-1, &p_ptr);
/* ... */
Oeps, I've been doing to much C++, the cast to struct node* is not needed in
C.
>
> /* ... */
> p_ptr = (void *) p;
> main (-1, &p_ptr);
>
> /* ... */
>}
>
Are you sure? I cast a pointer to something to a void*. The fact that this
something is itself a pointer shouldn't matter I think. (btw, I
intentionally put in the difference in indirection
there, to muddle the issue).
So you're saying that a char** can have a different representation of a
struct node**. If this is so, why is your solution better? I would say that
fails in the same way.
In C++, I know that the conversion is unsafe. A T* can be converted to a
void* and back, yielding a pointer to the original object. (T == struct
node*) If you cast this T* to a (char*)* inbetween, all bets are off as this
is a completely unrelated type. It will work on most computers, as pointers
to any data-structure (so excluding function pointers) in practice have the
same representation and alignment internally. But the C++ standard doesn't
guaranty this. I wonder what the C standard says about this.
Then again, I may be completely wrong, as I have been often before.
There is still another point you've missed I think, but that could also be a
C++ issue that is allowed in C. Anyone for a puzzle?
Martijn (who's C gets a bit rusty these days)
>>>int main(int argc, char **argv)
>>>{
>>> struct node *p;
>>> p = (struct node *)(void *)argv[0];
>>
>>[ snip ]
>>
>>> main(-1, (void *)&p);
>>int main (int argc, char **argv)
>>{
>> struct node *p;
>> char *p_ptr;
>>
>> /* ... */
>> p = (void *) argv[0];
>
>> /* ... */
>> p_ptr = (void *) p;
>> main (-1, &p_ptr);
>>
>> /* ... */
>>}
>Are you sure? I cast a pointer to something to a void*. The fact that this
>something is itself a pointer shouldn't matter I think. (btw, I
>intentionally put in the difference in indirection
>there, to muddle the issue).
>
>So you're saying that a char** can have a different representation of a
>struct node**. If this is so, why is your solution better? I would say that
>fails in the same way.
Your way:
address of operator applied to struct node *
--> struct node **
--> void *
--> char **
--> dereferenced to char *
--> char *
--> void *
--> struct node *
Suppose &p in your scenario yields 0x001010.
When converted to void *, it could be 0xA01010.
When converted to char **, it could be 0xB01010.
When this is dereferenced, you are not dereferencing the value that
you obtained after the & operator was applied.
My way:
struct node *
--> void *
--> char *
--> address of operator applied to char *
--> char **
--> dereferenced to char *
--> char *
--> void *
--> struct node *
In my way, I am dereferencing the same value that was generated by the &
operator applied before.
This looks decidedly dodgy... the standard certainly doesn't guarantee
that this will work. You could get around it by splitting the statement
up, I guess, but I'm not sure if it's worth the bother!!! :)
Hmmm, I disagree.
Martijns way:
struct node** => void* => char **
equivalent to:
T* => void* => Y*
James Hu's way:
struct node* => void* => char*
equivalent to:
T* => void* => Y*
I fail to see the difference. Either both are allowed or neither are imho.
Martijn
Much the same. char * and void * are guaranteed to have the same
representation, though.
Do you mean that you can't call main() recursively in ANSI C++?
Paul Lutus
Martijn Lievaart wrote in message <78hkin$8...@news3.euro.net>...
>Then again, I may be completely wrong, as I have been often before.
>
>There is still another point you've missed I think, but that could also be
a
>C++ issue that is allowed in C. Anyone for a puzzle?
>
>Martijn (who's C gets a bit rusty these days)
That's right. The fix is trivial, though...
Paul Lutus wrote in message <78imbu$rdj$1...@remarQ.com>...
><< There is still another point you've missed I think, but that could also
>be a
>C++ issue that is allowed in C. Anyone for a puzzle? >>
>
>Do you mean that you can't call main() recursively in ANSI C++?
>
Ahh, someone found it! And I thought it would be obvious. I still would like
to know if C allows this or forbids it.
Actually I'm not absolutely sure the C++ standard forbids it, but a C++
compiler has to treat main specially so it is *not* an ordinary C++
function. Can any C++ guru answer this?
Martijn
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
It does. In fact it does more, it forbids any explicit call to main at all.
I've been watching the exchange but haven't had time to try my hand at this
problem, until today.
Here's my entry in the reverse-forward sweepstakes -- it uses a
double-linked list. It also makes use of one of my favorite techniques --
recursion ( :) ):
#include <stdio.h>
struct link {
int c;
struct link* prev;
struct link* next;
};
void proc(struct link *p)
{
struct link q;
struct link *a,*b;
q.prev = p;
q.next = NULL;
q.c = getc(stdin);
if(q.c != EOF) {
if(p != NULL) {
p->next = &q;
}
proc(&q);
}
else {
a = q.prev;
while(a != NULL) { /* print list in reverse */
putc(a->c,stdout);
b = a;
a = a->prev;
}
putc('\n',stdout);
while(b != NULL) { /* print list forward */
putc(b->c,stdout);
b = b->next;
}
putc('\n',stdout);
}
}
int main()
{
proc(NULL);
return 0;
}
James Hu wrote in message ...
>On 19 Jan 1999 15:57:20 GMT, Shirley Barton <Spam...@WontWork.net> wrote:
>
>>Sorry, I had this silly notion that a program should be able to
>>recover and proceed no matter how many characters my user typed. I
>>can foresee certain situations where it might be difficult to predict
>>the amount of characters needed. Since I don't have a copy of
>>"Guiness Book of World Records" handy, how am I gonna know the longest
>>name length known to mankind?
>
>*yawn*, this must be a troll.
>
>For those of you real programming students, write a Standard C program
>that reads in a line of input of arbitrary length and prints out two
>lines. The first line of output should be the input line reversed.
>The second line of output should be the input line not reversed. The
>program cannot use any arrays, but otherwise can use any Standard C
>feature. For your convenience, however, you can assume that the input
>is no larger than the maximum amount of memory available to your
>platform (i.e., you shouldn't need to resort to FILE I/O for storage,
>but such a solution would also be acceptable).
>
>For you C++ students, go ahead and replace /C/ above with /C++/, but
>this exercise should be trivial.
>
But you can do useless stuff like redeclare its name, but you cannot
declare an overload in the global namespace. i.e.
int main(); //well-formed
int main( int ); // ill-formed, even if you don't define it
You can also have:
struct main
{
};
enum main { junk };
Now according to my reading of the standard
the following examples are well-formed since the
standard says that
you can call entities in other namespaces main.
namespace
{
int main( int ) { return 1; } // This overload is well-formed.
}
void f()
{
int i = main(3); // does not 'use' int ::main() so we're fine
}
And this is well-formed too:
namespace A
{
int main(char*) { return 1; }
}
using namespace A; // well-formed
// But this should be ill-formed
using A::main; // ill-formed
fun, huh?
-hope that was helpful
-fais
>[ comp.std.c++ added as I added a question on what the C++ standard allows ]
>Paul Lutus wrote in message <78imbu$rdj$1...@remarQ.com>...
>>
>>Do you mean that you can't call main() recursively in ANSI C++?
>Ahh, someone found it! And I thought it would be obvious. I still would like
>to know if C allows this or forbids it.
>Actually I'm not absolutely sure the C++ standard forbids it, but a C++
>compiler has to treat main specially so it is *not* an ordinary C++
>function. Can any C++ guru answer this?
In C, "main" is just a function. The only things special about it
are that it is the program entry point, and has a predefined form.
You can take its address or call it, in particular.
In C++, "main" has many more restrictions. Quoting from the standard,
section 3.6.1, "Main function":
--------------------------------
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a return type of type int, but
otherwise its type is implementation-defined. All implementations shall
allow both of the following definitions of main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
...
The function main shall not be used (3.2) within a program. The linkage
(3.5) of main is implementation-defined. A program that declares main
to be inline or static is ill-formed. ...
--------------------------------
Other provisions of the standard allow equivalent forms, so that
int main(int count, char** strings) { /* ... */ }
must be allowed as well, for example.
Notice also the absolute requirement that main have a return
type of int.
Section 3.2 defines what it means for something to be "used":
-------------------------------
An expression is potentially evaluated unless either it is the operand
of the sizeof operator (5.3.3), or it is the operand of the typeid
operator ...
An object or non-overloaded function is used if its name appears in
a potentially-evaluated expression.
-------------------------------
The restrictions on "using" mean that you cannot take the
address of main or call it as a function in C++.
The reasons for the restriction are to allow implementations to
recognize main uniquely as the program entry point, and be free
to do special program initialization or cleanup as part of main.
That is, a compiler might want to emit some special extra code
in main. It can safely do so, because no valid program can
call main internally.
It is easy to work around the restrictions on main. The limitation
is merely syntactical, not fundamental. Given a main function that
you would like to call, just rename it to, for example, my_main,
and do this:
int my_main(int, char**); // the original main
int main(int argc, char** argv)
{
return my_main(argc, argv);
}
This trick is sometimes used when you have a main program written
in C and you want to include C++ functions in the program. For
maximum portability, the main program should be compiled by
the C++ compiler. If you don't want to modify main to make it
valid C++, you can leave it in C but change its name. Then you
write the C++ main program as a wrapper around it, as above.
Since in this new example main would be a C function, you need
to declare it as a C function in the C++ code:
extern "C" int my_main(int, char**); // the original C main
int main(int argc, char** argv)
{
return my_main(argc, argv);
}
--
Steve Clamage, stephen...@sun.com
---
In C main is like any other function, it can be called recursively and
you can take its address.
In C++ you are prohibited from either calling main() or taking its
address. If you need to import a C program that uses this mechanism you
have to rename all occurences of main() as something like mymain and
then write main() to forward to mymain()
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
I don't have a copy of the C89 standard, so what I'm about to say may be
specific to the draft C9X standard.
C doesn't specifically allow it, but neither does it forbid calling
main(). It does, however contain two places where it is implied that
you're permitted to call main():
Section 5.1.2.2.3 "Program termination" in the draft C9X standard says
that "... a return from the initial call to the main function is". This
seems to imply that there can be more than one call to main(). Section
7.19.3 "Files" says that "If the main function returns to its original
caller, ...", which also seems to imply that main() can have more than
one caller.
> Actually I'm not absolutely sure the C++ standard forbids it, but a C++
> compiler has to treat main specially so it is *not* an ordinary C++
> function. Can any C++ guru answer this?
Section 3.6.1 "main function" in the C++ Standard says quite explicitly
that "The function main shall not be used (3.2) within a program."
[ ... ]
> >Do you mean that you can't call main() recursively in ANSI C++?
> >
>
> Ahh, someone found it! And I thought it would be obvious. I still would like
> to know if C allows this or forbids it.
C allows main to be recursive. I don't recall a specific statement to
this effect related to main, but it simply says that main is a
function, and says that any function can be called recursively, either
directly or indirectly.
> Actually I'm not absolutely sure the C++ standard forbids it, but a C++
> compiler has to treat main specially so it is *not* an ordinary C++
> function. Can any C++ guru answer this?
Section 3.6.1/3 says "The function main shall not be used within a
program." IOW, you can't call main recursively in C++.
#include <stdio.h>
struct Link { char ch; struct Link *prev; };
void print(struct Link *link)
{
putchar(link->ch);
if (link->prev) print(link->prev);
else putchar('\n');
putchar(link->ch);
}
void read(struct Link *prev)
{
struct Link link[1];
link->prev = prev;
if ((link->ch = getchar()) == EOF) print(link);
else read(link);
}
int main(void) { read(0); return 0; }
Paul Lutus <nos...@nosite.com> wrote in article
<78m8f8$nbu$1...@remarQ.com>...
Paul Lutus
Gene Ressler wrote in message
<01be49bf$7992d640$6802...@ze8827nb.ndu.edu>...
(Warning: Viewing this site may be hazardous to mental health ;^>)
Have fun,
I think this is a case of what is not forbidden is allowed.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
Ok, I have one more to give out. Like Paul's, this is another doubly
linked list one. This one shows tail-ended recursion for printing the
list out. For no good reason whatsoever, the code is obfuscated.
#include <stdio.h>
typedef struct l{char c;struct l const*l[2];}L;
static const L l_0,l_n={'\n',{0,0}};
static int p(const L*l,int i){putchar(l->c);
return(l->l[i]==0&&++i>1)?0:p(l->l[i],i);}
static int r(L*l,L l_O,int c){l_O.c=c,l_O.l[0]=l,l->l[1]=&l_O;
return(c=='\n'||c==EOF)?((l->c=='\n')?0:p(l,0)):r(&l_O,l_0,getchar());}
int main(void){do{L n=l_n;r(&n,l_0,getchar());}while(!feof(stdin));
return 0;}
There is a (small) problem with this program...... Try a nul byte file as
input to see what I mean.
Wow...... I especially like how you allocate new list nodes. Brilliant!
[ BTW, I got some unexpected behaviour under MSVC6, try a[^Z][Enter]b[Enter]
as input. The EOF (^Z) is not detected, and the next Enter is skipped! This
looks like a bug in MSVC, but it could be a "feature" of the OS. Trying
"copy con t" didn't duplicate this strange behaviour. Yep, looks like (yet
another) bug in MSVC 6. ]
>[ BTW, I got some unexpected behaviour under MSVC6, try a[^Z][Enter]b[Enter]
>as input. ... ]
Here's a fixed version:
#include <stdio.h>
typedef struct l{char c;struct l*l[2];}L;
static const L l_0={0,{0,0}},l_n={'\n',{0,0}};
static int p(const L*l,int i){putchar(l->c);
return(l->l[i]==0&&++i>1)?0:p(l->l[i],i);}
static int r(L*l,L l_O,int c){l_O.c=(c!=EOF?c:'\n'),l_O.l[0]=l,l->l[1]=&l_O;
return(l_O.c=='\n')?((l->c=='\n')?0:p(l,0)):r(&l_O,l_0,getchar());}
int main (void){do{L n=l_n;r(&n,l_0,getchar());}while(!feof(stdin));
return 0;}
--
#include <stdio.h>
struct Link { char ch; struct Link *prev; };
void print(struct Link *link)
{
if (link) { putchar(link->ch); print(link->prev); putchar(link->ch); }
else putchar('\n');
}
void read(struct Link *prev)
{
struct Link link;
link.prev = prev;
if ((link.ch = getchar()) == EOF) print(prev);
else read(&link);
}
int main(void) { read(0); return 0; }
Martijn Lievaart <nob...@orion.nl> wrote in article
<78ph5n$b...@news3.euro.net>...
> Gene Ressler wrote in message
> <01be49bf$7992d640$6802...@ze8827nb.ndu.edu>...
> >/* Much more interesting recursion! */
> >
> >#include <stdio.h>
> >
> >struct Link { char ch; struct Link *prev; };
> >
> >void print(struct Link *link)
> >{
> > putchar(link->ch);
> > if (link->prev) print(link->prev);
> > else putchar('\n');
> > putchar(link->ch);
> >}
> >
> >void read(struct Link *prev)
> >{
> > struct Link link[1];
> > link->prev = prev;
> > if ((link->ch = getchar()) == EOF) print(link);
> > else read(link);
> >}
> >
> >int main(void) { read(0); return 0; }
> >
> >
>
>
> There is a (small) problem with this program...... Try a nul byte file as
> input to see what I mean.
>
I generally try to make every function and variable a member of
some class; I generally abhor free functions and variables. (This
approach is consistent with the Java and Eiffel object models.)
To this end, I usually code my ::main() function like this:
int main(int argc, char **argv)
{
Program pgm;
return pgm.main(argc, argv);
}
Class 'Program' then deals with all the details that a main function
would normally deal with. It has the added advantage of being
a member of a class, so things like command line options and such
can be members of the class (instead of global variables).
This also makes it possible to instantiate multiple Program objects,
which can come in handy in multi-conversational programs.
And since Program::main() is not a special function, it can call
itself recursively if necessary.
-- David R. Tribble, dtri...@technologist.com --
>> User friendliness is one thing. Going out of your way to deal with
>>some fool who is trying to crash your program is quite another. What
>>you do is allow for a reasonable ammount of user error, but if the
>>user is such a dope as to enter 65 characters when asked for his age,
>>maybe he won't even notice the program isn't doing what it should. :)
>
>Right. We should always punish someone who gets distracted by a
>coworker and accidently puts his elbow on the keyboard and anyone who
>would use a computer with a cat in the room obviously doesn't deserve
>the courtesy of reasonable error messages. :-)
No. As I said, user friendliness is one thing. By all means allow
for some degree of distractedness/pet ownership/whatever, but if a
user needs more than 65 characters to enter their age, either they
have exceded the bounds of normal human error into total blind
stupidity or they probably remember when the earth was first formed
(if they can still remember anithing at that age). ;)
--
----- Dig the EVEN NEWER, MORE IMPROVED news sig!! -----
-------------- Shaggy was here! ---------------
http://aardvark.apana.org.au/~phaywood/
============= Ain't I'm a dawg!! ==============
if you want to prevent a buffer-underun why don't use
scanf("%64s", ptr_to_string);
''
JH
It's not they they *need* so many characters. It's not likely to be
deliberate (though it can be).
>either they have exceded the bounds of normal human error
>into total blind stupidity
But total blind stupidity is well within the bounds of normal human error.
There's a great deal of evidence to suggest that users *and* programmers can
be afflicted by it.
>or they probably remember when the
>earth was first formed (if they can still remember anithing at
>that age). ;)
Age doesn't seem to be a factor in total blind stupidity. It can strike at
any time.
Seriously though, if you are creating a piece of software of any real
significance then you need to assume that the users will do some incredibly
stupid things - either deliberately or by accident. The more you allow for
this, the more robust your software will be. It's almost impossible to cover
*everything* but making your software as *user proof* as possible will lead
to a more successful product.
--
Bob Jacobs re_j...@bigfoot.com
It is the mark of an instructed mind to rest satisfied with the degree of
precision which the nature of a subject admits, and not to seek exactness
when only an approximation of the truth is possible ...
--------------- Aristotle (330 B.C.) -------------