some "newbie" questions

B

Buck Rogers

Hi guys!

I've just bought The C Programming Language, K&R, 2nd Ed.

I am having some trouble with the earlier excercises and some
questions about the related sample programs. I've hunted through
the FAQ, with no luck.

==========================================================
1. I've added int before main(), and return 0 to the below
sample from p.17.

#include <stdio.h>

int main( void )
{
int c;

while ((c = getchar()) != EOF)
putchar(c);

return 0;
}

Why does this program not end when I enter a blank line?
It just keeps running until I press Ctr-C. Doesn't a
blank line signify EOF? Will this program only end if
Ctr-C is inputed by the user?

excercise 1-6: Verify that the expression getchar() != EOF is 0
or 1.

excercise 1-7: Write a program to print the value of EOF.
=============================================================

I've tried c = (getchar() != EOF) and then printing the value
of c, which comes up with rubbish. I've spent a day on this and
cannot answer the two above questions - logic is not my strong
point. Any hints would be appreciated.


========================================================
2. I've added int before main(), and return 0 to the below
sample from p.18.

int main( void )
{
double nc;

for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);

return 0;
}
============================================================

I personally would have used nc++, but the book reckons the
results would be the same. Anyway, why does the above sample
not increment the value of nc in any way? All the program
does is keep on accepting values that I type in ie.

5
6
7
ajalal

The program ends when I press Ctr-C.

I don't know if C has changed so much from when the book was
written that I actually need to radically modify the samples to
achieve what they were meant to achieve.

I am also somewhat an advanced newbie(ie. I've read other C texts cover
to cover), so getting stuck so early in this book really puts me in my
place. However I am determined to do each and every excercise.

Thanks in advance!

Buck
 
L

Les Cargill

Buck said:
Hi guys!

I've just bought The C Programming Language, K&R, 2nd Ed.

I am having some trouble with the earlier excercises and some
questions about the related sample programs. I've hunted through
the FAQ, with no luck.

==========================================================
1. I've added int before main(), and return 0 to the below
sample from p.17.

#include <stdio.h>

int main( void )
{
int c;

while ((c = getchar()) != EOF)
putchar(c);

return 0;
}

Why does this program not end when I enter a blank line?
It just keeps running until I press Ctr-C. Doesn't a
blank line signify EOF? Will this program only end if
Ctr-C is inputed by the user?

A blank line will not signify EOF. Try Ctrl-D or try Ctrl-Z.
excercise 1-6: Verify that the expression getchar() != EOF is 0
or 1.

excercise 1-7: Write a program to print the value of EOF.
=============================================================

I've tried c = (getchar() != EOF) and then printing the value
of c, which comes up with rubbish. I've spent a day on this and
cannot answer the two above questions - logic is not my strong
point. Any hints would be appreciated.

Try "printf("%c\n",EOF);" Other possibilities include
"printf("%d\n",EOF)" or "printf("%x\n",EOF);"
========================================================
2. I've added int before main(), and return 0 to the below
sample from p.18.

int main( void )
{
double nc;

for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);

return 0;
}
============================================================

I personally would have used nc++, but the book reckons the
results would be the same. Anyway, why does the above sample
not increment the value of nc in any way? All the program
does is keep on accepting values that I type in ie.

5
6
7
ajalal

The program ends when I press Ctr-C.

When you press Ctrl-C, this generates an interrupt that causes
the program to abort. It never gets to the line with the printf.

Try Ctrl-D or Ctrl-Z to trigger the EOF condition.
 
M

Mark McIntyre

Hi guys!

I've just bought The C Programming Language, K&R, 2nd Ed.

I am having some trouble with the earlier excercises and some
questions about the related sample programs. I've hunted through
the FAQ, with no luck.

(About the first example. )
Why does this program not end when I enter a blank line?

because a blank line doesn't signal EOF. Its a line with a single
carriage return on it.
It just keeps running until I press Ctr-C. Doesn't a
blank line signify EOF? Will this program only end if
Ctr-C is inputed by the user?

Ctrl-C doesn't signal EOF, It ends your program by terminating it
abruptly. You might find Ctrl-Z better, if you're on DOS.
int main( void )
{
double nc;

for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);

return 0;
}
============================================================

I personally would have used nc++, but the book reckons the
results would be the same. Anyway, why does the above sample
not increment the value of nc in any way?

Think about how a for loop works.

for(statement)
do something.

Since, you have a semicolon on the line below the for() statement, it
executes the ; until you signal EOF.
All the program
does is keep on accepting values that I type in ie.

yup, thats correct. Its supposed to do that - its counting characters
remember? However its ALSO incrementing nc. But you never know, since
your programme is terminated without executing the printf.
The program ends when I press Ctr-C.

Correct. Ctrl-C doesn't signal EOF, it terminates your program.And so
you don't see hte printf.
I don't know if C has changed so much from when the book was
written that I actually need to radically modify the samples to
achieve what they were meant to achieve.

They actually work fine, you're vust signalling EOF wrong.
 
K

Kevin Goodsell

Les said:
Try "printf("%c\n",EOF);" Other possibilities include
"printf("%d\n",EOF)" or "printf("%x\n",EOF);"

The last one invokes undefined behavior. EOF has type (signed) int. %x
is for unsigned int only.

Note that K&R2 mistakenly says (in at least 2 places - pages 244 and
154) that %x, %X, %o, and %u expect type 'int'. This is noted in the
errata list (though I believe it only corrects one of the two instances
of the error).

-Kevin
 
D

donLouis

Hi guys!

I've just bought The C Programming Language, K&R, 2nd Ed.

I am having some trouble with the earlier excercises and some
questions about the related sample programs. I've hunted through
the FAQ, with no luck.

if i may suggest, instead of "typing" in EOF or any other input,
create a text file and put test data in it. then, "feed" the file
to your program. on a win32 platform, type in:

c:\<whatever> type file.txt | program.exe

this will enable you to perform boundary tests on your program,
i.e. "what does my program do if file.txt is empty?", or,
"my program is supposed to replace extra spaces with only one
space. what about a large number of spaces after a single
character?", etc, etc.

it also has the benefit of letting the system take care of EOF
for you.

you may also want a text editor that allows you to put non-printable
ascii in your file, tabs, bells, whatever.
 
L

Les Cargill

Kevin said:
The last one invokes undefined behavior. EOF has type (signed) int. %x
is for unsigned int only.

What it'll do on most 32 bit compilers is treat it as if you typed:

printf("%x\n",(unsigned int)EOF);

You won't even get a warning, either. But I still
should have included the cast. Been using compilers
that don't complain about it for too long.
 
D

darklight

Buck Rogers wrote:>
excercise 1-6: Verify that the expression getchar() != EOF is 0
or 1.
This answer is taken from the C answer book by tondo & gimple
I had the same problem with the above question
K&R is not for the total begginer.
answer below copied from book hope it helps

#include<stdio.h.

main()
{
int c;

while(c = getchar() != EOF)
printf("%d\n",c);
printf("%d - at EOF\n",c);
}

The expression
c = getchar() != EOF
is equivalent to
c = (getchar() != EOF)

page 17 K&R: the program reads characters from the standard input and
uses the expression above. While getchar has a character to read it does not
return the end of file and

getchar() != EOF

is true. So 1 is assigned to c. When the program encounters the end of file,
the expression is false. Then 0 is assigned to c and the loop terminates.
 
S

Sean Kenwrick

Les Cargill said:
What it'll do on most 32 bit compilers is treat it as if you typed:

printf("%x\n",(unsigned int)EOF);

You won't even get a warning, either. But I still
should have included the cast. Been using compilers
that don't complain about it for too long.
You will never find a compiler that will complain about this since the
compiler knows nothing about what the format specifiers mean in the printf()
function. These are all interpreted at run-time and the function will
blindly attempt to cast the passed values to the appropriate type.
Thus there is no difference between:

printf("%x\n",EOF);

and

printf("%x\n",(unsigned int) EOF);

Since a run-time casting will always take place anyway so your compile-time
cast is redundant in this case as far as I can tell...

Sean
 
T

The Real OS/2 Guy

Hi guys!

I've just bought The C Programming Language, K&R, 2nd Ed.

That's fine - when you own already programming experience with one or
more other languages. K&R is THE book to learn C - but it is not
designed to learn programming.
I am having some trouble with the earlier excercises and some
questions about the related sample programs. I've hunted through
the FAQ, with no luck.

==========================================================
1. I've added int before main(), and return 0 to the below
sample from p.17.

#include <stdio.h>

int main( void )
{
Fine!

int c;

Fine. You knows that getchar() returns an int, not a char!

while ((c = getchar()) != EOF)
putchar(c);

return 0;
}

Why does this program not end when I enter a blank line?
It just keeps running until I press Ctr-C. Doesn't a
blank line signify EOF? Will this program only end if
Ctr-C is inputed by the user?

That is because EOF is neither a blank line nor Ctrl+c. EOF is
definened as a flag generated from the stream handler behind eg.
getc() for the event that one tries to read behind the end of a file.
To genererate that event from kkeyboard you has to type a special key
freqence:

on some systems that is Ctrl+d, on others that is Ctrl+z, on others
that is something else.

Ctri+c generates an even known as break. This will break the program
immediately independant what the program does.
excercise 1-6: Verify that the expression getchar() != EOF is 0
or 1.

excercise 1-7: Write a program to print the value of EOF.
=============================================================

I've tried c = (getchar() != EOF) and then printing the value
of c, which comes up with rubbish. I've spent a day on this and
cannot answer the two above questions - logic is not my strong
point. Any hints would be appreciated.

printf("%d\n", c);

and then press Ctrl+d or Ctrl+Z depending on your system.
========================================================
2. I've added int before main(), and return 0 to the below
sample from p.18.

int main( void )
{
double nc;

for (nc = 0; getchar() != EOF; ++nc)
;

That is an endless loop. It eats and throws away anything typed in
until Ctrl+D/Z is typed. The ';' is an empty statement, so as you
doesn't use brackedts to group multiple statements to the for loop the
body of it is empty and the printf gets only reached when getchar()
returns EOF.

As you breaks the program with Ctrl+c the printf gets never reached,
so nothing is printed.
printf("%.0f\n", nc);

return 0;
}
============================================================

I personally would have used nc++, but the book reckons the
results would be the same. Anyway, why does the above sample
not increment the value of nc in any way? All the program
does is keep on accepting values that I type in ie.

That's right. The bug sits in front of your screen.
5
6
7
ajalal

The program ends when I press Ctr-C.

Works as designed.
 
A

Alexander Bartolich

followup to Sean Kenwrick:
You will never find a compiler that will complain about this since
the compiler knows nothing about what the format specifiers mean in
the printf() function.

Both wrong and irrelevant.

A string literal can be fully analyzed at compile time, and there is
one popular compiler (gcc) that issues diagnostics in such case.
[...] the function will blindly attempt to cast the passed values
to the appropriate type.

This is the real issue. An explicit cast overrides whatever
intelligence the compiler may have. And type promotion can make
such casts superfluous.

$ cat printf.c
#include <stdio.h>
int main()
{
unsigned x = -1;
return printf("%x\n", -1L);
}

$ gcc -Wall printf.c
printf.c: In function `main':
printf.c:5: warning: unsigned int format, long int arg (arg 2)
printf.c:4: warning: unused variable `x'

Note that the potentially unsafe conversion of -1 to unsigned
raises no warning.
 
C

CBFalconer

Alexander said:
followup to Sean Kenwrick:
You will never find a compiler that will complain about this
since the compiler knows nothing about what the format
specifiers mean in the printf() function.

Both wrong and irrelevant.

A string literal can be fully analyzed at compile time, and there
is one popular compiler (gcc) that issues diagnostics in such case.
[...] the function will blindly attempt to cast the passed
values to the appropriate type.

This is the real issue. An explicit cast overrides whatever
intelligence the compiler may have. And type promotion can make
such casts superfluous.

$ cat printf.c
#include <stdio.h>
int main()
{
unsigned x = -1;
return printf("%x\n", -1L);
}

$ gcc -Wall printf.c
printf.c: In function `main':
printf.c:5: warning: unsigned int format, long int arg (arg 2)
printf.c:4: warning: unused variable `x'

Note that the potentially unsafe conversion of -1 to unsigned
raises no warning.

It is not unsafe, and is completely defined.

Try your program with the following changes:

#include <stdio.h>
int main(void)
{
unsigned x = -1;
char *fmt = "%x\n";
printf(fmt, -1L);
return 0;
}

(The return change is simply to return a legitimate value).
 
K

Kevin Goodsell

Sean said:
These are all interpreted at run-time and the function will
blindly attempt to cast the passed values to the appropriate type.

There's no basis for this claim, and it's probably wrong on nearly all
implementations. Most implementations probably use the type indicated in
the format string to determine how to interpret raw bytes. No casting of
the object itself is likely to be involved in most cases (though it
could in some cases - for example, %c might interpret the bits as int
then cast that int to char).

The implementation doesn't use the format string to "cast the passed
value to the appropriate type", it uses the format string to determine
what the the passed value is.
Thus there is no difference between:

printf("%x\n",EOF);

and

printf("%x\n",(unsigned int) EOF);

Except that one is correct and one is not.
Since a run-time casting will always take place anyway so your compile-time
cast is redundant in this case as far as I can tell...

The "run-time casting" is a figment of your imagination. No such thing
is required by the standard. It's completely possible for an
implementation to pass signed ints and unsigned ints in different
registers (for example), in which case printf() may see that an unsigned
int is expected, and try to pull that unsigned int from the register it
expects unsigned ints to be in, giving a wrong result, a crash, or any
number of possible results.

-Kevin
 
C

Chris Torek

The "run-time casting" is a figment of your imagination. No such thing
is required by the standard.

Indeed, to be precise, such a thing *cannot* exist, because in C,
the thing called a "cast" is a syntactic construct, in much the
same way as a string literal is a syntactic construct, or the
curly braces used to enclose blocks are "mere" syntax. Syntax
is something the Standard uses in phases 1 through 6 and the
first part of phase 7; "run-time" is exclusively during or after
(usually after) phase 8:

7. White-space characters separating tokens are no longer
significant. Each preprocessing token is converted
into a token. The resulting tokens are syntactically
and semantically analyzed and translated as a
translation unit.

8. All external object and function references are
resolved. Library components are linked to satisfy
external references to functions and objects not
defined in the current translation. All such
translator output is collected into a program image
which contains information needed for execution in its
execution environment.

The cast construct -- a type-name enclosed in parentheses -- acts
as a request for a conversion, often a run-time conversion, but
the cast itself is just a compile-time notion.

The much bigger problem here is that printf() is a variadic function.
As such, the actual arguments that correspond to the ", ..." part
of printf()'s prototype merely undergo the "default promotions".
You may of course use a cast to force a particular conversion,
which will subsequently undergo the default promotion (if any).
The example code fragment (which I deleted) does not use a cast,
and almost certainly has no conversions; most likely it passes
an ordinary "int" value of -1 (EOF is "usually" defined as -1,
although the standard requires only some integer constant whose
type is "int" and value is negative).
It's completely possible for an
implementation to pass signed ints and unsigned ints in different
registers (for example) ...

There is a footnote that suggests otherwise:

[#8] The range of nonnegative values of a signed integer
type is a subrange of the corresponding unsigned integer
type, and the representation of the same value in each type
is the same.27 ...

27. The same representation and alignment requirements are
meant to imply interchangeability as arguments to
functions, return values from functions, and members of
unions.

The number (and perhaps precise text) of the footnote may have
changed between C89 and C99, but the sense has been constant for
more than a decade. Clearly, the C Standards folks *meant* to
say "you can pass an unsigned T where a signed T is expected,
and vice versa, as long as the value you pass fits in either
type". The question is, did they actually say that?

The big problem here is that footnotes are "non-normative", i.e.,
have no effect on the actual Standard. If a footnote says that C
compilers must be purple, you can still sell a green or yellow one
without violating that Standard. This footnote says "interchangeable"
but the rest of the standard (both C89 and C99) appears not to.
... in which case printf() may see that an unsigned
int is expected, and try to pull that unsigned int from the register it
expects unsigned ints to be in, giving a wrong result, a crash, or any
number of possible results.

These do appear to be possible.

(I am not sure why C99 never addressed this. If C89 really *meant*
"interchangeable", why not just come out and *say* "interchangeable"?)
 
L

Les Cargill

Sean said:
You will never find a compiler that will complain about this since the
compiler knows nothing about what the format specifiers mean in the printf()
function.

gcc does, just not in this case. It makes a special exception for
printf, since the standard(s) refer(s) to it.

These are all interpreted at run-time and the function will
blindly attempt to cast the passed values to the appropriate type.
Thus there is no difference between:

printf("%x\n",EOF);

and

printf("%x\n",(unsigned int) EOF);

Since a run-time casting will always take place anyway so your compile-time
cast is redundant in this case as far as I can tell...

Pretty much. :)
 
L

Les Cargill

Kevin said:
There's no basis for this claim, and it's probably wrong on nearly all
implementations. Most implementations probably use the type indicated in
the format string to determine how to interpret raw bytes. No casting of
the object itself is likely to be involved in most cases (though it
could in some cases - for example, %c might interpret the bits as int
then cast that int to char).

The implementation doesn't use the format string to "cast the passed
value to the appropriate type", it uses the format string to determine
what the the passed value is.

Even if it is not necessary ( eg: no warning ), it would be a Good Thing
to cast it, if only to document things. It's just more correct.
Except that one is correct and one is not.


The "run-time casting" is a figment of your imagination. No such thing
is required by the standard. It's completely possible for an
implementation to pass signed ints and unsigned ints in different
registers (for example), in which case printf() may see that an unsigned
int is expected, and try to pull that unsigned int from the register it
expects unsigned ints to be in, giving a wrong result, a crash, or any
number of possible results.

Yup!
 
A

Alexander Bartolich

begin followup to Les Cargill:
gcc does, just not in this case. It makes a special exception for
printf, since the standard(s) refer(s) to it.

Just a minor nitpicking: The function name is not hard-wired into
gcc. The whole thing relies on cooperation by the header file.

# The `format' attribute specifies that a function takes `printf',
# `scanf', `strftime' or `strfmon' style arguments which should be
# type-checked against a format string. For example, the
# declaration:
#
# extern int
# my_printf (void *my_object, const char *my_format, ...)
# __attribute__ ((format (printf, 2, 3)));
#
# causes the compiler to check the arguments in calls to `my_printf'
# for consistency with the `printf' style format string argument
# `my_format'.
 
P

Peter Nilsson

Chris Torek said:
It's completely possible for an
implementation to pass signed ints and unsigned ints in different
registers (for example) ...

There is a footnote that suggests otherwise:

[#8] The range of nonnegative values of a signed integer
type is a subrange of the corresponding unsigned integer
type, and the representation of the same value in each type
is the same.27 ...

27. The same representation and alignment requirements are
meant to imply interchangeability as arguments to
functions, return values from functions, and members of
unions.

It's surprising that this is left as a footnote in that section, yet
it is normative in the va_arg macro specs! [Note the standard doesn't
say that printf et al _use_ va_arg.]
 
D

Dave Thompson

Chris Torek said:
It's completely possible for an
implementation to pass signed ints and unsigned ints in different
registers (for example) ...

There is a footnote that suggests otherwise:

[#8] The range of nonnegative values of a signed integer
type is a subrange of the corresponding unsigned integer
type, and the representation of the same value in each type
is the same.27 ...

27. The same representation and alignment requirements are
meant to imply interchangeability as arguments to
functions, return values from functions, and members of
unions.
(Footnote 31 to 6.2.5p9 in actual C99. At least prior to TC1.)
It's surprising that this is left as a footnote in that section, yet
it is normative in the va_arg macro specs! [Note the standard doesn't
say that printf et al _use_ va_arg.]

Right, or even be written in C, as has been debated here before.

Interchangeability is also normative for oldstyle/K&R1/unprototyped
calls in 6.5.2.2p6. But not for prototyped calls, at least to a
prototyped definition (since that would have incompatible function
type in violation of p9); for an unprototyped definition the type
declared does not include the parameter types, and they are not
explicitly required to be compatible (after promotion) as they are in
p6, but I think that must have been intended because in practice calls
with (truly) mismatching arguments (to an unprototyped definition) are
pretty likely to not work right, since long before 1989.

And the same for void* versus char* (6.2.5p26) in both/all cases.


- David.Thompson1 at worldnet.att.net
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top