Art, Programming, Linux

Andrew's notes

Home Posts Tags

C Programming Language - Chapter 1 Solutions

The solution to each exercise of Chapter 1 of the ‘The C Programming Language’ book.

Published on December 20, 2022 2932 words 14 min read Programming

Image by JR Korpa on Unsplash

Contents

Introduction #

C Programming Language (Second Edition) is a book written by Brian W. Kernighan and Dennis M. Ritchie.

With C being a compiled language we will need to somehow compile our code in order for the computer to be able to create an executable for us. To compile a C program within a UNIX system type into a terminal cc followed by the name of the file.c that contains our source code. In the case of the first exercise we aptly named the file hello.c so the command that we need to use is :

cc hello.c

That command creates a file named a.out in the same folder. By running that file, our program is executed properly and the console prints hello world. If you would like to specify a name for your executable you may use the -o flag.

cc hello.c -o appNameHere

Exercise 1-1 #


Run the ``hello, world’’ program on your system. Experiment with leaving out parts of the program, to see what error messages you get.

Solution

#include <stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
};

Exercise 1-2 #


Experiment to find out what happens when prints’s argument string contains \c, where c is some character not listed above.

Solution

The chapter talks about Escape Sequences that we can use in C such as \n. When trying to compile a program using an incorrect escape sequence we will get the following error:

warning: unknown escape sequence: '\c'

The program still compiles however in spite of the error and can be executed “normally” with the exception that the erroneous part of our code does nothing.

Exercise 1-3 #


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

This chapter contains a program that prints to the console a converstion from fahrenite to celcius.

Solution

#include <stdio.h>

/* print Fahrenheit-Celsius table
for fahr = 0, 20, ..., 300; floating-point version */

int main()
{
    float fahr, celsius;
    float lower, upper, step;
    
    lower = 0;  /* lower limit of temperatuire scale */
    upper = 300;    /* upper limit */
    step = 20;    /* step size */

    fahr = lower;
    
    printf("Fahrenite to Celcius\n");   /*solution*/
    printf("====================\n");
    
    while (fahr <= upper) {
        celsius = (5.0/9.0) * (fahr-32.0);
        printf("%3.0f %6.1f\n", fahr, celsius);
        fahr = fahr + step;
    }
    return 0;
}

Exercise 1-4 #


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

Note : The formula for converting Celcius to Fahrenheit is F = (C * 1.8) + 32

Solution

#include <stdio.h>

int main(){
	float celcius, fahr;
	float lower, upper, step;

	lower = 0;
	upper = 160;
	step = 20;

	celcius = lower;

	printf("Celcius to Fahrenheit\n");
	printf("====================\n");
	while(celcius <= upper)
	{
		fahr = (celcius * 1.8) + 32;
		printf("%3.0f %6.0f\n", celcius, fahr);
		celcius+= step;
	};
	return 0;
};

Exercise 1-5 #


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

Solution

#include <stdio.h>

int main(){
	float celcius, fahr;
	float lower, upper, step;

	lower = 0;
	upper = 160;
	step = 20;

	celcius = upper;

	printf("Celcius to Fahrenheit\n");
	printf("====================\n");
	while(celcius >= lower)
	{
		fahr = (celcius * 1.8) + 32;
		printf("%3.0f %6.0f\n", celcius, fahr);
		celcius-= step;
	};
	return 0;
};

Exercise 1-6 #


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

Solution

#include <stdio.h>

int main()
{
    int d,c;
    
    while(d = (c=getchar() != EOF))
        printf("%d\n",d);
    return 0;
};

Every time that the contents of the while loop are evaluated and contents of C are not equal to EOF, the expression is evaluated to equal 1.

Exercise 1-7 #


Write a program to print the value of EOF

Solution

EOF stands for End of File. It is returned to us whenever we use a character reading function such as getchar() to read from a file or from user input and there is no more data to be read e.g it finished returning the contents of the file.

The value of EOF is implementation dependent and is commonly -1.

NOTE: On unix systems the input that causes an end of file is CTRL+D.

#include <stdio.h>

int main(){
    printf ("End of File Value : %d\n", EOF);
    return 0;
};

Exercise 1-8 #


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

#include <stdio.h>

int main()
{
        int c, nl, tabs, spaces;
        c = nl = tabs = spaces = 0;

        while ((c = getchar()) != EOF){
                if (c == '\n')
                        nl++;
                if (c == '\t')
                        tabs++;
                if (c == ' ')
                        spaces++;
        };
        
        printf("new lines: %d\n",nl);
        printf("tabs: %d\n", tabs);
        printf("spaces: %d\n", spaces);
        
        return 0;
};

Exercise 1-9 #


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

Solution

#include <stdio.h>

/* we will use IN and OUT to determine whether we are in a series of blanks or not */

#define IN 1 
#define OUT 0

int main(){
    int c, state;
    
    state = OUT;
    while ((c = getchar()) != EOF){
        if (c == ' ' || c== '\t')
            state = IN;
            
        if (state == OUT)
            putchar(c);
            
        if (state == IN && c != ' ' && c != '\t'){
            state = OUT;
            putchar(' ');
            putchar(c);
        };

    };
    return 0;
};

Exercise 1-10 #


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.

Solution

#include <stdio.h>

int main()
{
    int c;
    
    while ((c = getchar()) != EOF){
        if (c == '\t'){
            putchar('\\');
            putchar('t');
        };
        
        else if (c == '\b'){
            putchar('\\');
            putchar('b');
        };
        
        else if (c == '\\'){
            putchar('\\');
            putchar('\\');
        };
        else
            putchar(c);
    };
    
    return 0;
};

Exercise 1-11 #


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

Solution

Essentially in the word counting program as written in the book there is intentionally an issue where any type of input is counted as a char. It doesn’t matter if its a space, or a tab, or a new line, it still gets evaluated as a character which could be improved upon for human interpretation of the program’s output. A way that the program could be improved is by making sure that only non-blank non-space characters are counted as such.

#include <stdio.h>

#define IN 1
#define OUT 0

/* count lines, words and characters in input */

int main()
{
        int c,nl,wc, nc, state;
        nc = nl = wc = 0;

        state = OUT;

        while((c = getchar()) != EOF){
                if(c == '\n')
                        nl++;

                if(c != ' ' && c != '\t' && c != '\n'){
                        ++nc;
                        state = IN;
                };
                if (state == IN){
                        if( c == ' ' || c == '\t' || c == '\n'){
                                state = OUT;
                                ++wc;
                        };
                };

        };
        printf("words: %d\n",wc);
        printf("chars: %d\n",nc);
        printf("lines: %d\n",nl);
        return 0;
};

Exercise 1-12 #


Write a program that prints its input one word per line.

Solution

#include <stdio.h>

int main()
{
        int c;

        /* write a program that prints its input one word per line */
        
        while ((c = getchar()) != EOF){
                if(c == ' ' || c == '\n' || c == '\t')
                        putchar('\n');
                else
                        putchar(c);
        };

        return 0;
};

Exercise 1-13 #


Write a program to print a histogram of the lengths of the words in its input. It is easy to draw the histogram with the bars horizontal; a vertical orientation is more challenging

Solution

#include <stdio.h>

#define BUFFER 15

int main(){
    // define variables

    int letterCount = 0;
    int letterMax = 0;
    int wordarr[BUFFER];
    int arrlength = 0;

    // initialize array

    int c ;
    for(int i = 0; i < BUFFER; i++)
        wordarr[i] = 0;
    
    // check longest word
    printf("CTRL+D to stop.\n");
    while((c=getchar())!=EOF)
    {
        if(c == ' ' || c == '\n' || c == '\t' || c=='.'){
            if(letterCount>0){
                if(letterCount>letterMax)
                    letterMax=letterCount;
                    arrlength=letterMax;
                ++wordarr[letterCount-1];
            }
            
            letterCount = 0;
        }else{
            letterCount++;
        };
    }
    
    // construct horizontal histogram
    int linecount = 0;
    printf("\n");
    printf("===============\n");
    printf("HISTOGRAM\n");
    printf("===============\n");
    while(linecount < arrlength){
        printf("%2d letter(s):\t",linecount+1);
        for(int i = 0; i<wordarr[linecount]; i++){
            printf("*");
        }
        printf("\n");
        linecount++;
    }
    printf("===============\n");
    return 0;

Exercise 1-14 #


Write a program to print a histogram of the frequencies of different characters in its input

Solution

For the sake of simplicity we will only account characters of the alphanumeric spectrum and only lowercase characters.

#include <stdio.h>

#define NDIGITS 10
#define NCHARS 26

int main()
{
        /* write a program to print a histogram of the frequencies of different characters in its input */

        int chars[NDIGITS + NCHARS];

        for(int i = 0; i< (NDIGITS+NCHARS); i++) 
                chars[i] = 0;

        char c;

        while ((c = getchar()) != EOF){
                if(c >= 'a' && c <='z')
                        chars[c - 'a']++;
                if(c>='0' && c<='9')
                        chars[c-'0'+ NCHARS]++;
        };

        printf("HISTOGRAM================\n");
        for(int i = 0; i < (NDIGITS + NCHARS); i++){
                if( i < NCHARS)
                        printf("char : %2d | ", i);
                else
                        printf("numb : %2d | ", i - NCHARS);
                for( int k = 0; k < chars[i]; k++)
                        printf("#");

                printf("\n");
        };

        return 0;
};

This was the most confusing exercise for me and it took a while to make the connection to c - 'a'. The statement of in the book is key :

By definition, chars are just small integers, so char variables and constants are identical to ints in arithmetic expressions. This is natural and convenient; for example c-‘0’ is an integer expression with a value between 0 and 9 corresponding to the character ‘0’ to ‘9’ stored in c.

Exercise 1-15 #


Rewrite the temperature conversion program to use a function for conversion

Solution

#include <stdio.h>

#define LOWER 0
#define UPPER 300
#define STEP 20

void convert()
{
        float fahr, celcius;
        while(fahr <= UPPER){
                celcius = (5.0/9.0) * (fahr-32);
                printf("%3.0f %6.1f\n", fahr, celcius);
                fahr += STEP;
        };
};

int main(){
        printf("Fahrenite to Celcius\n");
        printf("====================\n");

        convert();

        return 0;
};

Exercise 1-16 #


Revise the main routine of the longest-line program so it will correctly print the length of arbitrary long input lines, and as much as possible of the text.

Solution

#include <stdio.h>

#define MAXLINE 1000

int get_line(char s[], int lim);
void copy (char to[], char from[]);

int main()
{
	int len;
	int max;

	char line[MAXLINE];
	char longest[MAXLINE];

	max = 0;
	while((len = get_line(line,MAXLINE))> 0)
		if(len > max){
			max = len;
			copy(longest,line);
		};
	if (max > 0)
		printf("max is : %d\n", max); /* solution */
		printf("%s",longest);
	return 0;
};

int get_line(char s[], int lim)
{
	int c, i;
	for(i = 0; i < lim-1 && (c = getchar()) != EOF && c!='\n';i++)
		s[i] = c;
	if(c == '\n'){
		s[i] = c;
		++i;
	}
	s[i] = '\0';
	return i;
};

void copy (char to[], char from[])
{
	int i = 0;
	while((to[i] = from[i]) != '\0')
		++i;
};

Exercise 1-17 #


Write a program to print all input lines that are longer than 80 characters.

Solution

#include <stdio.h>

#define MAXLINE 1000
#define LIMIT 80

int lineLength(char arr[], int limit);
main()
{
    /* write a program to print all input lines that are longer than 80 */

    int c,len;
    char line[MAXLINE];
    
    while((len = lineLength(line, MAXLINE)) > 0){
        if(len > LIMIT){
            printf("%s\n",line);
        }
    }
    return 0;
}

int lineLength(char arr[], int limit)
{
    int i = 0;
    int c;
    for( i = 0; i < limit -1 && (c = getchar()) != EOF && c != '\n'; i++)
    {
        arr[i] = c;
    }
    return i;
}

Exercise 1-18 #


Write a program to remove trailing blanks and tabs from each line of input, and to delete entirely blank lines.

Solution

#include <stdio.h>

#define MAXLINE 1000

int readLine(char arr[], int limit);
void remove_blanks(char cArr[], int limit);


int main()
{

    char cArr[MAXLINE];
    int len = 0;

    while((len = readLine(cArr, MAXLINE))> 0)
    {
        printf("%s",cArr);
    }

}

int readLine(char arr[], int limit)
{
    int i = 0;
    int c;
    for( i = 0; i < limit -1 && (c = getchar()) != EOF && c != '\n'; i++)
    {
        arr[i] = c;
    }
    printf("length of line = %d\n", i);
    if(c=='\n'){
        while(i > 0 &&(arr[i-1] == ' ' || arr[i-1] == '\t'))
            i--;
        arr[i]=c;
        i++;
    };
    printf("lengh of new line = %d\n",i);
    arr[i] = '\0';
    return i;
}

Exercise 1-19 #


Write a function reverse(s) that reverses the character string s. Use it to write a program that reverses its input a line at a time.

Solution

#include <stdio.h>
#define MAX 1000

void reverse(char arr[], int limit);
int readLine(char arr[], int limit);

int main(void)
{
    char arr[MAX];
    int len;

    while((len = readLine(arr,MAX))>0)
    {
        reverse(arr, len);
        printf("%s",arr);
    }

    return 0;
    
}

void reverse(char line[], int length)
{
    int start = 0;
    int end = length-2;
    char lineReverse[length];

    for(int i = end; i>=0; i--)
    {
        lineReverse[start] = line[i];
        start++;
    }
    
    for(int i = 0; i < length; i++)
        line[i] = lineReverse[i];
    
    
    line[end+1] = '\n';
    
}

int readLine(char arr[], int limit)
{
    int c, i;

    for(i = 0; i < limit - 1 && ((c=getchar())!= EOF && c!='\n'); i++)
        arr[i] = c;

    if(c == '\n'){
        arr[i]='\n';
        i++;
    }

    arr[i] = '\0';

    return i;
}
    

To check that this program works not just with terminal input but with any file, try piping into it the source code of this file and see the result.

cat reverse.c | ./a.out > result.txt

Exercise 1-20 #


Write a program detab that replaces tabs in the input with the proper number of blanks to space to the next tab stop. Assume a fixed set of tab stops, say every n columns. Should n be a variable or a symbolic parameter?

Solution

#include <stdio.h>

#define TAB 4

int main()
{
        int c;
        while((c=getchar())!= EOF){
                if(c == '\t'){
                        for(int i = 0; i < TAB; i++)
                                putchar(' ');
                }else
                        putchar(c);
        };
};

Exercise 1-21 #


Write a program entab that replaces strings of blanks by the minimum number of tabs and blanks to achieve the same spacing. Use the same tab stops as for detab. When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?

Solution

#include <stdio.h>

int main()
{
    int c;
    int spaces = 0;

    while ((c = getchar()) != EOF)
    {

        if (c == ' ' || c == '\t')
        {
            if (c == '\t')
                putchar(c);

            if (c == ' ')
                spaces += 1;

            if (spaces > 0 && (c != ' ' || c != '\t'))
            {
                while (spaces)
                {
                    putchar(' ');
                    spaces--;
                }
            }
        }
        else
        {
            putchar(c);
        }
    }
    return 0;
}

Exercise 1-22 #


Write a program to ``fold’’ long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column.

Solution

#include <stdio.h>

#define MAXLINE 1000
#define MAXCHARS 50

int readLine(char arr[], int limit);
void breakup(char arr[], int lim);

int main()
{
    int len;
    char arr[MAXLINE];
    
    len = 0;
    while((len = readLine(arr,MAXLINE)) > 0)
    {
        if(len > MAXCHARS)
        {
            breakup(arr,len);
            printf("%s",arr);
        }else{
            printf("%s",arr);
        }
    }
    
    return 0;
}

int readLine(char arr[], int limit)
{
    int c,i;
    for(i = 0; i<limit-1 && (c=getchar())!= EOF && c != '\n'; i++)
        arr[i] = c;
    
    if(c == '\n'){
        arr[i] = '\n';
        i++;
    }
    arr[i] = '\0';
    return i;
}

void breakup(char arr[], int lim)
{
    for(int i = 0; i<lim; i++)
    {
        if(i>0 && i%MAXCHARS==0)
        {
            for(int k = i; k>0; k--)
            {
                if (arr[k] == ' '){
                    arr[k] = '\n';
                    break;
                }
            }
        }
    }
}

Exercise 1-23 #


Write a program to remove all comments from a C program. Don’t forget to handle quoted strings and character constants properly. C comments don’t nest.

Solution

#include <stdio.h>

#define MAXLINE 1000

void removeComments(char arr[], int lim);
int readLine(char arr[], int lim);

/* Write a program to remove all comments from a c program */
/*
*   multi line
*   comment that will be
*   removed
*/
int main()
{
    int len; // this needs to be removed as well
    /* this needs to be removed as well */ char arr[MAXLINE];

    // these comments will all be removed when the program is executed with this file as input

    while ((len = readLine(arr, MAXLINE)) > 0)
    {
        removeComments(arr, len);
        printf("%s", arr);
    }

    return 0;
}

void removeComments(char arr[], int lim)
{
    int i,k,count;
    i = k = count = 0;
    char narr[lim];
    int narrCounter = 0;

    if (arr[0] == '/' && arr[1] == '/')
    {
        arr[0] = '\0';
    }

    if (arr[0] == '/' && arr[1] == '*')
    {
        while (i < lim)
        {
            if (arr[i] == '*' && arr[i + 1] == '/')
            {
                arr[0] = '\0';
            }
            ++i;
        }
    }

    for (i = 0; i < lim; i++)
    {
        if (arr[i] == '/' && arr[i + 1] == '/')
        {
            arr[i] = '\n';
            arr[i + 1] = '\0';
        }
    };

    for(k = 0; k < lim; k++)
    {
        if(arr[k] == '/' && arr[k+1] == '*')
        {
            while(arr[k]!='\n'){
                k++;
                if(arr[k]=='*' && arr[k+1]=='/'){
                    count = k+1;
                    while(count<=lim)
                    {
                        narr[narrCounter]=arr[count+1];
                        narrCounter++;
                        count++;
                    }
                    arr[0] = '\0';
                    printf("%s",narr);
                }
            }
        }
    }

    if((arr[0] == '/' && arr[1] == '*') || (arr[0] == '*'))
    {
        arr[0]='\0';
    }   
}

int readLine(char arr[], int lim)
{
    int i, c;

    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++)
        arr[i] = c;

    if (c == '\n')
    {
        arr[i] = '\n';
        i++;
    }

    arr[i] = '\0';
    return i;
}

Note: Don’t forget to run the program’s source through its executable to make sure that all comments have been removed and that the program works as intented.

cat removeComments.c | ./a.out > results.txt

---

If you found this post useful please consider donating a small amount to support my effort in creating more content like this.