Introductory C Programming

UW Experimental College

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()) != EOF
```
to 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

```	i = i++
```
do?

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?

An array of characters, terminated with the null character \0.

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.

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.

Tutorial 2. Improve the myatoi function so that it can handle negative numbers.

```#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;
}
```

Tutorial 3. Modify the ``word zipping'' program to move the word from right to left instead of left to right.

```#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;
}```

Exercise 4. Write a program which computes the average (and standard deviation) of a series of numbers.

```#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;
}

```

Exercise 5. Write a rudimentary checkbook balancing program.

```#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;
}```

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.

```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);
```

Exercise 7. Write a program to read its input, one character at a time, and print each character and its decimal value.

```#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.

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:

```#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;
}
```