K&R Solutions - 1.11

Q: How would you test the word count program? What kinds of input are most likely to uncover bugs if there are any?


A: There is no perfect answer to this kind of question. Writing good test is really a matter of experience. Part of the reason all programs have bugs is that even the best test writers can't anticipate all the wild ways a program will be used by other people. Nevertheless, writing good tests is a good skill to develop, as you can filter out about 99% of potential bugs that way, and prevent unexpected behaviour when you make small changes to large programs.


The first thing I would do is test it with no characters at all, hoping for '0 0 0'. Next, test it with one word, then with one tab, then with one newline. Then a tab and a newline, then a newline and a tab... you probably don't need the full 16, but instinct tells me that starting input with white space might cause problems. After that, a few short strings like 'two words' will cover the basics. Of course, in real life, I hope I can write such thorough tests.


That might seem like a lot but if you write a test once, you get the peace of mind forever.



K&R Solutions - 1.10

Q: Write a program to copy its input to its output, replacing each tab by \t , each backspace by \b , and each backslash by \\ . This makes tabs and backspaces visible in an unambiguous way.

A:

#include <stdio.h>

int main(void)
{
  char c;

  while ((c = getchar()) != EOF) {
    if (c == '\t') {
      printf("\\t");
    } else if (c == '\b') {
      printf("\\b");
    } else if (c == '\\') {
      printf("\\\\");
    } else {
      putchar(c);
    }
  }

  return 0;
}
tab	example
tab\texample
\ example
\\ example
Backspace example doesn't work!
Backspace example doesn't work!

Denis Richie standing by the computer where he invented C

Notes:

Your terminal emulator takes care of automatically backspacing for you, so the final part of this exercise is long-obsolete.


Explicit backspaces were a problem Richie dealt with when they were developing C and Unix in the 70s. Their office computer didn't have a monitor, only a printer (teletype) which didn't show the characters you had already backspaced (in fact, it added the whitespace \b which was applied as a character deletion only after you saved the line); you just had to try to keep track of your corrections in your head.


According to people around back then, the reason C tends to be so terse, and keywords/variable names tended to be so short, is that backspacing was so frustratingly difficult to keep track of that they wanted to keep the lines as short as possible. This is contrary to the modern style, where clear names are considered extremely important.


It's pretty easy (and fun) to run Unix 6 on an emulator, to get a bit of a taste of what these people were dealing with back then. After trying to write a few small programs, you'll get a pretty good feeling for why old Unix culture discouraged long names.



K&R Solutions - 1.9

Q: Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank.

A:

#include <stdio.h>

int main(void)
{
  int c, blanks;
  blanks = 0;

  while ((c = getchar()) != EOF) {
    if (c == ' ')
      blanks++;
    else
      blanks = 0;

    if (blanks < 2)
      putchar(c);
  }

  return 0;
}
> ./1.9
here   is  a whitespace   test
here is a whitespace test


K&R Solutions - 1.8

Q: Write a program to count blanks, tabs, and newlines.

A:

#include <stdio.h>

int main(void)
{
        int c, blanks, tabs, newlines;

        blanks = tabs = newlines = 0;
        while ((c = getchar()) != EOF)
                if (c == ' ')
                        ++blanks;
                else if (c == '\t')
                        ++tabs;
                else if (c == '\n')
                        ++newlines;

        printf("\nBlanks: %d\n", blanks);
        printf("Tabs: %d\n", tabs);
        printf("Newlines: %d\n", newlines);

        return 0;
}
sldfsk fldskj
skdfjl	fdslkjlewk	eflwkjlewkr	fdk
Blanks: 1
Tabs: 3
Newlines: 1


K&R Solutions - 1.7

Q: Write a program to print the value of EOF .

A:

#include <stdio.h>

int main(void)
{
  printf("%d\n", EOF);

  return 0;
}
> ./1.7
-1


K&R Solutions - 1.6

Q: 1.6: Verify that the expression getchar() != EOF is 0 or 1.

A:

#include <stdio.h>

int main(void)
{
  printf("Type and press enter OR ctrl+d: \n");
  printf("getchar() != EOF -> %d\n", getchar() != EOF);

  return 0;
}
> ./1.6
Type and press enter OR ctrl+d: 
> (ctrl-d)
getchar() != EOF -> 0
> ./1.6
Type and press enter OR ctrl+d: 
> foo
getchar() != EOF -> 1


K&R Solutions - 1.5

Q: Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0.


A:

#include <stdio.h>

int main(void)
{
  int fahr;

  for (fahr = 300; fahr >= 0; fahr -= 20)
    printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));

  return 0;
}
300  148.9
280  137.8
260  126.7
240  115.6
220  104.4
200   93.3
180   82.2
160   71.1
140   60.0
120   48.9
100   37.8
 80   26.7
 60   15.6
 40    4.4
 20   -6.7
  0  -17.8


K&R Solutions - 1.4

Q: Write a program to print the corresponding Celsius to Fahrenheit table.

A:

#include <stdio.h>
int main(void)
{
  double fahr, celsius;
  double lower, upper, step;

  lower = 0;
  upper = 300;
  step = 20;

  fahr = lower;

  printf("Celsius    Fahrenheit\n");
  printf("---------------------\n");

  while (celsius <= upper) {
    fahr = (9.0/5.0) * celsius + 32;
    printf("%7.0f    %9.1f\n", celsius, fahr);
    celsius += step;
  }

  return 0;
}
Celsius    Fahrenheit
---------------------
      0         32.0
     20         68.0
     40        104.0
     60        140.0
     80        176.0
    100        212.0
    120        248.0
    140        284.0
    160        320.0
    180        356.0
    200        392.0
    220        428.0
    240        464.0
    260        500.0
    280        536.0
    300        572.0


K&R Solutions - 1.3

Q: Modify the temperature conversion program to print a heading above the table.

A:

#include <stdio.h>

int main(void)
{
  double fahr, celsius;
  double lower, upper, step;

  lower = 0;
  upper = 300;
  step = 20;

  fahr = lower;

  printf("Fahrenheit    Celsius\n");
  printf("---------------------\n");

  while (fahr <= upper) {
    celsius = (5.0/9.0) * (fahr-32.0);
    printf("%10.0f    %6.1f\n", fahr, celsius);
    fahr += step;
  }

  return 0;
}
> make 1.3
> ./1.3
Fahrenheit    Celsius
---------------------
         0     -17.8
        20      -6.7
        40       4.4
        60      15.6
        80      26.7
       100      37.8
       120      48.9
       140      60.0
       160      71.1
       180      82.2
       200      93.3
       220     104.4
       240     115.6
       260     126.7
       280     137.8
       300     148.9