Question 1.
What would the expression
c = getchar() != EOF
do?
It would read one character and compare it to the constant EOF. If the character read was equal to EOF, it would set c to 0, otherwise (i.e. for any other character) it would set c to 1. What it would not do is read a character, assign it to c, and then test it against EOF, which is what you usually want to do, and which you need to write
(c = getchar()) != EOFto do.
Question 2. Why must the variable used to hold getchar's return value be type int?
So that it can reliably store the value EOF.
Variables of type char are typically 8 bits large,
which means that they can hold 28,
or 256 different character values.
Furthermore, on an 8-bit system,
getchar can theoretically return
characters having any of these 256 character values.
However, getchar can also return a 257th value, EOF,
which is not a character value but rather an indication that there are no
more characters to get.
You can no more reliably store
getchar's 257 return values in a
variable of type char than you can store 13 eggs in a
carton that holds a dozen.
If you tried to assign getchar's return value
to a char,
you could either mistake a real character value for EOF
or EOF for a real character value,
resulting either in premature termination of input or an infinite loop.
An int, on the other hand, is on the vast majority of
machines larger than a char, so it can comfortably hold
all 256 character values, plus EOF.
Question 3.
What is the difference
between the prefix and postfix forms of the ++ operator?
The prefix form increments first,
and the incremented value goes on to participate in the
surrounding expression (if any).
The postfix form increments later;
the previous value
goes on to participate in the surrounding expression.
Question 4.
What would the expression
Nothing, or at least, nothing useful.
Since it tries to modify i twice,
it's undefined.
Question 5.
What is the definition of a string in C?
Question 6.
What will the getline function
do
if successive calls to getchar return the four values
'a', 'b', 'c', and EOF?
The first three characters are placed in the line array,
as usual,
and when the EOF indicator is read,
getline breaks out of its loop,
also as usual.
Although c is now EOF,
nch is 3,
so the condition c == EOF && nch == 0
is false.
getline therefore does not return EOF,
but rather terminates the line with \0
and returns its length,
just as it does with a normal line
which it finds \n at the end of.
Tutorial 2.
Improve the myatoi function so that it can handle negative numbers.
Tutorial 3.
Modify the ``word zipping'' program
to move the word from right to left instead of left to right.
Exercise 4.
Write a program
which computes the average
(and standard deviation)
of a series of numbers.
Exercise 5.
Write a rudimentary checkbook balancing program.
Reading the key word and the amount from the same line
would be surprisingly difficult,
using only the tools we have in hand so far.
We'll see a clean way of doing it in a week or two.
Exercise 6.
Rewrite the ``compass'' code
to use strcpy and strcat.
Exercise 7.
Write a program to read its input,
one character at a time,
and print each character and its decimal value.
Exercise 8.
Write a program to read its input,
one line at a time,
and print each line backwards.
Here is one way of doing it,
using only what we've seen so far:
This page by Steve Summit
// Copyright 1995-9
// mail feedback
i = i++
do?
An array of characters,
terminated with the null character \0.
Can this situation ever occur?
One way to answer a question like this is not to try too hard to answer it,
to err on the side of conservatism,
to assume that if we can't prove that the unusual situation won't arise,
we might as well be safe and arrange that our code can handle it
if it somehow comes up.
(There's obviously little or no harm in writing code
to handle a situation that never comes up,
while the reverse--neglecting
to write code to handle a situation that does come up--can
of course be very harmful.)
In any case,
under Unix at least,
this situation can in fact come up.
Unix does not enforce any notion of a ``text file'';
the sequence a, b, c, EOF
at the end of a file
is no more or less favored
(by the operating system, that is)
than the sequence a, b, c, \n, EOF.
Furthermore, there are some programs
(e.g. full-screen text editors such as EMACS)
which make it easy to create a text file without a final newline
(if only by accident).
(But there are also examples of programs
which inadvertently ignore the last line of a file
whose last line does not end in \n,
and this is a bug which can cause data loss.)
So writing getline to treat a ``line'' ending in EOF
(but no \n)
is not only reasonable, but useful.
#include <ctype.h>
int myatoi(char str[])
{
int i;
int retval = 0;
int negflag = 0;
for(i = 0; str[i] != '\0'; i = i + 1)
{
if(!isspace(str[i]))
break;
}
if(str[i] == '-')
{
negflag = 1;
i = i + 1;
}
for(; str[i] != '\0'; i = i + 1)
{
if(!isdigit(str[i]))
break;
retval = 10 * retval + (str[i] - '0');
}
if(negflag)
retval = -retval;
return retval;
}
#include <stdio.h>
extern int getline(char [], int);
int main()
{
char word[20];
int len;
int i, j;
printf("type something: ");
len = getline(word, 20);
for(i = 80 - len - 1; i >= 0; i--)
{
for(j = 0; j < i; j++)
printf(" ");
printf("%s \r", word);
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
extern int getline(char [], int);
int main()
{
char line[100];
int x;
double sum, sumsq;
int n;
double mean, stdev;
sum = sumsq = 0.0;
n = 0;
while(getline(line, 100) != EOF)
{
x = atoi(line);
sum = sum + x;
sumsq = sumsq + x * x;
n = n + 1;
}
mean = sum / n;
stdev = sqrt((sumsq - sum * sum / n) / (n - 1));
printf("mean: %f\n", mean);
printf("std. dev.: %f\n", stdev);
return 0;
}
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#define MAXLINE 100
extern int getline(char [], int);
int main()
{
double balance = 0.0;
char line1[MAXLINE], line2[MAXLINE];
while(getline(line1, MAXLINE) > 0)
{
getline(line2, MAXLINE);
if(strcmp(line1, "deposit") == 0)
balance += atof(line2);
else if(strcmp(line1, "check") == 0)
balance -= atof(line2);
else {
printf("bad data line: not \"check\" or \"deposit\"\n");
continue;
}
printf("balance: %.2f\n", balance);
}
return 0;
}
char word[20];
if(y > 0)
strcpy(word, "north");
else if(y < 0)
strcpy(word, "south");
else strcpy(word, ""); /* empty string */
if(x > 0)
strcat(word, "east");
else if(x < 0)
strcat(word, "west");
else strcat(word, ""); /* empty string */
printf("%s\n", word);
#include <stdio.h>
int main()
{
int c;
while((c = getchar()) != EOF)
printf("character %c has value %d\n", c, c);
return 0;
}
You will notice that this program prints a funny line or two
for each new line ('\n') in the input,
because when the %c in the printf call
finds itself printing a \n character that we've just read,
it naturally prints a newline at that point.
#include <stdio.h>
extern int getline(char [], int);
extern int reverse(char [], int);
int main()
{
char line[100];
int len;
while((len = getline(line, 100)) != EOF)
{
reverse(line, len);
printf("%s\n", line);
}
return 0;
}
int reverse(char string[], int len)
{
int i;
char tmp;
for(i = 0; i < len / 2; i = i + 1)
{
tmp = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = tmp;
}
return 0;
}
In practice, it would be a nuisance to have to pass the length
of the string to the reverse function.
Strings in C are always terminated by the ``zero'' or
``nul'' character, represented by \0.
Therefore, reverse (or any piece of code)
can always compute the length of a string, either by searching
for the \0,
or by calling the library function strlen,
which computes the length of a string by searching for the
\0.
Here is how the program might look if the reverse
function did not require that the length of the string be
passed in:
#include <stdio.h>
#include <string.h>
extern int getline(char [], int);
extern int reverse(char []);
int main()
{
char line[100];
while(getline(line, 100) != EOF)
{
reverse(line);
printf("%s\n", line);
}
return 0;
}
int reverse(char string[])
{
int len = strlen(string);
int i;
char tmp;
for(i = 0; i < len / 2; i = i + 1)
{
tmp = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = tmp;
}
return 0;
}