Some Newb Problem with "int", please help.

A

Apotheosis

The problem professor gave us is:

Write a program which reads two integer values. If the first is less
than the second, print the message "up". If the second is less than
the first, print the message "down" If the numbers are equal, print
the message "equal" If there is an error reading the data, print a
message containing the word "Error" and perform exit( 0 );


And this is what I wrote:

main()
{
int x;
int y;

printf("Enter the first integer: ");
scanf("%d", &x);

printf("Enter the second integer: ");
scanf("%d", &y);

if (x > y)
{
printf("Up");
}
else
{
if (x < y)
{
printf("Down");
}
else
{
if (x = y)
{
printf("Equal");
}
else
{
printf("Error");
getch();
exit (0);
}
}
}
}



Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?
 
J

James Hu

[ code using scanf snipped ]


Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?

Don't use scanf. Read the answer to question 12.20 in the C-faq
to find out why.

http://www.eskimo.com/~scs/C-faq/top.html

-- James

Dude, you're reading the C-faq!
 
C

CBFalconer

Apotheosis said:
The problem professor gave us is:

Write a program which reads two integer values. If the first is less
than the second, print the message "up". If the second is less than
the first, print the message "down" If the numbers are equal, print
the message "equal" If there is an error reading the data, print a
message containing the word "Error" and perform exit( 0 );

And this is what I wrote:

main()
{
int x;
int y;

printf("Enter the first integer: ");
scanf("%d", &x);

printf("Enter the second integer: ");
scanf("%d", &y);
.... snip ...

Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?

Basically you have failed to detect the errors resulting from the
scanf calls. Those are both returning a single value, so they
should be of the form:

if (1 != scanf("%d", &x)) erroraction();
else {
....
}

Never use scanf without checking the return value. Also, main
returns an int. Say so. You should be using:

int main(void)
{
....
return 0;
}
 
J

Joona I Palaste

Apotheosis said:
The problem professor gave us is:
Write a program which reads two integer values. If the first is less
than the second, print the message "up". If the second is less than
the first, print the message "down" If the numbers are equal, print
the message "equal" If there is an error reading the data, print a
message containing the word "Error" and perform exit( 0 );
And this is what I wrote:

main()
{
int x;
int y;
printf("Enter the first integer: ");
scanf("%d", &x);
printf("Enter the second integer: ");
scanf("%d", &y);
if (x > y)
{
printf("Up");
}
else
{
if (x < y)
{
printf("Down");
}
else
{
if (x = y)

Everyone other failed to spot this. You want == here, not =. = first
assigns y's value to x and then tests if x's value is anything other
than 0. This means that if execution gets this far, any value entered
to y at all, as far as it isn't 0, will print "Equal" regardless of
x's value. Because you already tested for x > y and x < y, this would
otherwise not matter, but it's going to break if you type 0 for both
x and y. In this case your program won't print anything at all.
 
P

pete

James said:
[ code using scanf snipped ]


Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?

Don't use scanf. Read the answer to question 12.20 in the C-faq
to find out why.

I disagree.

/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>

#define LENGTH 100
#define str(x) # x
#define xstr(x) str(x)
#define VSIZE (sizeof variables / sizeof *variables)

int main(void)
{
int x, y, n, rc;
long temp;
char array[LENGTH + 1], *nptr;
struct V {
int *address;
char *string;
} variables[]= {{&x, "first"}, {&y, "second"}};

for (n = 0; VSIZE > n; ++n) {
printf("Enter the %s integer: ", variables[n].string);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getchar();
}
if (rc != 1) {
puts("Error");
exit(0);
}
nptr = array;
while (isspace(*nptr)) {
++nptr;
}
if (*nptr == '+' || *nptr == '-') {
++nptr;
}
if (!isdigit(*nptr)) {
puts("Error_2");
exit(0);
}
errno = 0;
temp = strtol(array, NULL, 10);
if (errno != 0 || INT_MIN > temp || temp > INT_MAX) {
puts("Error_3");
exit(0);
}
*variables[n].address = (int)temp;
}
if (y > x) {
puts("Up");
} else {
if (x > y) {
puts("Down");
} else {
puts("Equal");
}
}
return 0;
}

/* END new.c */
 
N

Nicolas Pavlidis

rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);

For portability reasons a propper #define for the linebreak would be
IMHO fine.

Kind regards,
Nicolas
 
F

Felipe Magno de Almeida

Apotheosis said:
The problem professor gave us is:

Write a program which reads two integer values. If the first is less
than the second, print the message "up". If the second is less than
the first, print the message "down" If the numbers are equal, print
the message "equal" If there is an error reading the data, print a
message containing the word "Error" and perform exit( 0 );


And this is what I wrote:

main()
{
int x;
int y;

printf("Enter the first integer: ");
scanf("%d", &x);

printf("Enter the second integer: ");
scanf("%d", &y);

if (x > y)
{
printf("Up");
}
else
{
if (x < y)
{
printf("Down");
}
else
{
if (x = y)
here you should replace for x == y
{
printf("Equal");
}
else
{
printf("Error");
getch();
exit (0);
}
}
}
}



Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?


--
Felipe Magno de Almeida
UIN: 2113442
email: felipe.almeida@ic unicamp br, felipe.m.almeida@gmail com
I am a C, modern C++, MFC, ODBC, Windows Services, MAPI developer
from synergy, and Computer Science student from State
University of Campinas(UNICAMP).
To know more about:
Unicamp: http://www.ic.unicamp.br
Synergy: http://www.synergy.com.br
current work: http://www.mintercept.com
 
C

Christopher Benson-Manica

Apotheosis <[email protected]> spoke thus:

Your indentation is suboptimal, to put it mildly.

main() returns int. You should say so, and must do so under C99.
else
{
if (x = y)
{
printf("Equal");
}
else
{
printf("Error");
getch();
exit (0);
}
}
}

You are missing a return statement; you must explicitly return an
integer under C89. Notice that your call to exit() does not always
occur.
 
E

Edmund Bacon

The problem professor gave us is:

Write a program which reads two integer values. If the first is less
than the second, print the message "up". If the second is less than
the first, print the message "down" If the numbers are equal, print
the message "equal" If there is an error reading the data, print a
message containing the word "Error" and perform exit( 0 );


And this is what I wrote:

main()
{
int x;
int y;

printf("Enter the first integer: ");
scanf("%d", &x);

printf("Enter the second integer: ");
scanf("%d", &y);
[ rest of code snipped ]
}
}



Works fine at first, but whenever I enter invalid characters such as
!, A, %, :, etc. It never asks me for the second integer and skip to
printf("Down");
Can anyone be kind enough to explain to me why that happened?

No, but perhaps if you can answer these questions you might figure it
out:

1) what does scanf() do if the input doesn't match the requested
conversion?

2) does scanf have a return value? If so, what is it, and how might
you use that to help you with this problem?
 
P

pete

Nicolas said:
pete said:
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);

For portability reasons a propper #define for the linebreak would be
IMHO fine.

I don't understand what you mean.
Is there something there which is not portable?
What linebreak?
 
P

pete

pete said:
struct V {
int *address;
char *string;
} variables[]= {{&x, "first"}, {&y, "second"}};

That should be

struct V {
char *string;
int *address;
} variable[]= {{"first"}, {"second"}};

variable[0].address = &x;
variable[1].address = &y;

instead, since x and y are automatic variables.
 
N

Nicolas Pavlidis

pete said:
Nicolas said:
pete said:
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);

For portability reasons a propper #define for the linebreak would be
IMHO fine.

I don't understand what you mean.
Is there something there which is not portable?
What linebreak?

I ment the '\n' character. AFAIK Windows for example breaks lines with a
sequence carriage return + line feed, but maybe this has changed.

Kind regards,
Nicolas
 
P

pete

Nicolas said:
pete said:
Nicolas said:
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);

For portability reasons
a propper #define for the linebreak would be IMHO fine.

I don't understand what you mean.
Is there something there which is not portable?
What linebreak?

I ment the '\n' character.
AFAIK Windows for example breaks lines with a
sequence carriage return + line feed, but maybe this has changed.

I don't know in what context, what Window does, matters.

"there need not be a one-to-one correspondence between the
characters in a stream and those in the external representation"

C defines a stream line as ending in newline character.

N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined. Characters may have to be added,
altered, or deleted on input and output to conform to
differing conventions for representing text in the host
environment. Thus, there need not be a one-to-one
correspondence between the characters in a stream and those
in the external representation.

Try this on a Windows box and see if the code is broken:

/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>

#define LENGTH 65
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
int rc;
char string[LENGTH + 1];

fputs("Enter a string with spaces:", stdout);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
if (!feof(stdin)) {
getchar();
}
while (rc == 1) {
printf("Your string is:%s\n\n"
"Hit Enter key to end,\n or enter "
"another string to continue:", string);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
if (!feof(stdin)) {
getchar();
}
}
return 0;
}

/* END new.c */
 
N

Nicolas Pavlidis

pete said:
"there need not be a one-to-one correspondence between the
characters in a stream and those in the external representation"

C defines a stream line as ending in newline character.

Ok, sorry.

Kind regards,
Nicolas
 
A

Arthur J. O'Dwyer

pete said:
Nicolas said:
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);

For portability reasons a [proper] #define for the linebreak would
be IMHO fine.

I don't understand what you mean.
Is there something there which is not portable?
What linebreak?

I [meant] the '\n' character. AFAIK Windows for example breaks
lines with a sequence carriage return + line feed, but maybe
this has changed.

It has not. But it's not relevant to Windows programming, as someone
has already explained, because all decent DOS/Windows implementations
translate the two bytes 0D.0A to '\n' (for text streams) long before
the user's program ever sees them. So pete's code behaves perfectly
correctly on Windows systems, as well as on *nix.

There may be problems (and usually are, IME), however, when you
compile pete's code on a Unix or Linux implementation and then try to
feed it a text file generated on a DOS or Windows system. Unix
implementations tend not to understand 0D.0A, and /will/ pass the
extra byte along to the user's program (usually as '\r'). I don't
think the reverse is generally true: I think most Windows compilers
do understand that 0A without 0D is still '\n'.

So if you want your program to be as portably user-friendly as possible,
you ought to consider handling '\r\n' (and its Mac analogue '\r')
gracefully. But that's not a situation where a #define would help,
AFAIK. One really needs to make some fundamental design decisions to
support '\r\n' sensibly, and IMHO 'scanf' doesn't mix well with those
decisions.

HTH,
-Arthur
 
P

pete

Arthur said:
pete said:
Nicolas Pavlidis wrote:

rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
So if you want your program to be as portably user-friendly as
possible, you ought to consider handling '\r\n'
(and its Mac analogue '\r') gracefully.

I don't know about the Mac analogue case, but the scanf call above
with a \r\n terminated line, would still get you a string.
Parsing the string, is a job for another part of the code.
 
D

Dan Pop

There may be problems (and usually are, IME), however, when you
compile pete's code on a Unix or Linux implementation and then try to
feed it a text file generated on a DOS or Windows system.

You're invoking undefined behaviour in this case: you're opening in text
mode a file which is not a text file (on the platform opening it). The
things are even more obvious if the text file was generated on a VMS
system or some typical mainframe OS, because the differences are far more
impressive (each line is a record in the file and has no terminating
character(s)).

This is why text files must be properly *imported* on the system that
has to process them. Once this is done, the code can safely assume that
each line of text is \n terminated.

Dan
 
R

Richard Bos

Arthur J. O'Dwyer said:
I [meant] the '\n' character. AFAIK Windows for example breaks
lines with a sequence carriage return + line feed, but maybe
this has changed.

It has not. But it's not relevant to Windows programming, as someone
has already explained, because all decent DOS/Windows implementations
translate the two bytes 0D.0A to '\n' (for text streams) long before
the user's program ever sees them.

Not just all decent implementations, _any_ implementation which is a C
implementation at all. The Standard requires it.
There may be problems (and usually are, IME), however, when you
compile pete's code on a Unix or Linux implementation and then try to
feed it a text file generated on a DOS or Windows system.

Possibly, but if this is something you need to do often you probably
have a proper file tranfer program which will do the translation for
you. (And if not, it's reasonably simple to write.)

Richard
 
A

Arthur J. O'Dwyer

Arthur J. O'Dwyer said:
I [meant] the '\n' character. AFAIK Windows for example breaks
lines with a sequence carriage return + line feed, but maybe
this has changed.

It has not. But it's not relevant to Windows programming, as someone
has already explained, because all decent DOS/Windows implementations
translate the two bytes 0D.0A to '\n' (for text streams) long before
the user's program ever sees them.

Not just all decent implementations, _any_ implementation which is a C
implementation at all. The Standard requires it.

Nitpick: No, it doesn't. The Standard only requires that the
implementation translate /newlines/ to '\n' before the user code sees
them. If 0D.0A isn't a "newline" on the DS9000, then it doesn't have
to translate it. Replace "DS9000" by "brain-dead Windows implementation,
perhaps a naive GCC port," and you get exactly what I said.
Possibly, but if this is something you need to do often you probably
have a proper file tranfer program which will do the translation for
you. (And if not, it's reasonably simple to write.)

Certainly. But can you ensure that all your potential users have
such a program, or can write one; and that they all know how and when
to use it; and that they always remember to use it? </rhetorical>

-Arthur
 
A

Arthur J. O'Dwyer

You're invoking undefined behaviour in this case: you're opening in text
mode a file which is not a text file (on the platform opening it).

True. That doesn't mean we should never try to do something reasonable
with it, though. (I'm not saying one should /always/ catch weird
newlines, but for programs that need maximum robustness and
user-friendliness I do think it's one of the first things to do.)

-Arthur
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top