Week 08 Tutorial Sample Answers

1. How are you going with assignment 1?

Please remind students that the assignment is due at the end of this week.

2. Consider the program below:

#include <stdio.h>

int main(void) {
    char str[10];
    str[0] = 'H';
    str[1] = 'i';
    printf("%s", str);
    return 0;
}
  1. What will happen when the above program is compiled and executed?
    The above program will compile without errors. printf, like many C library functions, expects strings to be null-terminated.

    In other words, printf expects the array str to contain an element with value '\0' which marks the end of the sequence of characters to be printed.

    printf will print str[0] ('H'), str[1] then examine str[2].

    Code produced by dcc --valgrind will then stop with an error because str[2] is uninitialized.

    The code with gcc will keep executing and printing elements from str until it encounters one containing '\0'. Often str[2] will by chance contain '\0' and the program will work correctly.

    Another common behavior will be that the program prints some extra "random" characters.

    It is also possible the program will index outside the array, which would result in it stopping with an error if it was compiled with dcc.

    If the program was compiled with gcc and uses indices well outside the array, it may be terminated by the operating system because of an illegal memory access.

  2. How do you correct the program?
    #include <stdio.h>
    
    int main(void) {
        char str[10];
        str[0] = 'H';
        str[1] = 'i';
        str[2] = '\0';
        printf("%s", str);
        return 0;
    }
    

3. Name 3 errors in this program:
#include <stdio.h>

#define MAX_LINE 4096

int main(void) {
    char line[MAX_LINE];
    int  i;

    while (fgets(line, MAX_LINE, stdin) != NULL) {
        i = MAX_LINE;
        while (line[i] != '\n') {
            i = i - 1;
        }
        printf("the line is %d characters long\n", i);
    }
    return 0;
}
  1. On the first execution of the inner while loop, it accesses line[MAX_LINE], which is an illegal array index.
  2. It accesses uninitialized array elements - fgets only assigns to the array elements necessary to hold the characters of a line plus a '\0'.
  3. There may not be a '\n' in the array. fgets won't put a '\n' in the array if the line is too long to fit in the array. If there is no '\n' in the array, the code will access a non-existent array element (line[-1]).

4. Write a program line_length.c which reads lines from its input and prints how many characters each line contains.

The only functions you can use are fgets and printf.

You can assume lines contain at most 4096 characters.

For example:

./line_length
Andrew Rocks
line 12 characters long
A very long line.
line 17 characters long
short
line 5 characters long

line 0 characters long
Sample solution for line_length.c
#include <stdio.h>

#define MAX_LINE 4096

int main(void) {
    char line[MAX_LINE];

    while (fgets(line, MAX_LINE, stdin) != NULL) {
        int i = 0;
        while (line[i] != '\n' && line[i] != '\0') {
            i = i + 1;
        }
        printf("line %d characters long\n", i);
    }
    return 0;
}
Alternative solution for line_length.c
// COMP1511 W9 tutorial question 5
#include <stdio.h>
#include <stdlib.h>

#define MAX 4096

// prototype, returns an integers and takes in a string called line
int count(char *line);

int main(void) {

    char line[MAX]; // holder for each line

    while (fgets(line, MAX, stdin) != NULL) {
        // so read in successfully
        printf("line %d characters long\n", count(line));
    }

    return 0;
}

int count(char *line) {
    int i = 0;
    while (line[i] != '\n' && line[i] != '\0') {
        i = i + 1;
    }
    return i;
}

5. Write a program strip_comments.c which reads lines from its input and prints them after removing any C // style comments.

In other words, if the line contains //, it does not print the // or anything after it.

The only functions you can use are fgets and printf.

You can assume lines contain at most 4096 characters.

For example:

./strip_comments
     x = x + 1;  // This means add one to the variable x
     x = x + 1;
Also - is that a good comment to add to a C program?
Sample solution for strip_comments.c
#include <stdio.h>

#define MAX_LINE 4096

int main(void) {
    char line[MAX_LINE];
    int  i;

    // reads lines and print them after
    // removing // style comments

    while (fgets(line, MAX_LINE, stdin) != NULL) {


        // iterate through line and see if we encounter a '/' then '/'
        // everything after is a comment, so stop the string there

        i = 0;
        while (line[i] != '\n' && line[i] != '\0') {

            // safe to look at line[i+1] because
            // we know here line[i] != '\0'

            if (line[i] == '/' && line[i + 1] == '/') {

                // replace // with a newline and null-terminator
                line[i] = '\n';
                line[i + 1] = '\0';

                // could break here but loop will stop anyway
                // because after i = i + 1, line[i] == '\0'
            }

            i = i + 1;
        }

        // write possibly-modified line

        printf("%s", line);
    }
    return 0;
}

6. Write a program filter_empty_lines.c which reads lines from its input and prints them only if they contain a non-white-space character.

In other words, remove lines that are empty or contain only white-space.

The only functions you can use are fgets and printf.

You can assume lines contain at most 4096 characters.

You can assume there are only 3 white space characters: space, tab, and newline.

For example:

./filter_empty_lines
full line
full line
         
another non-empty line
another non-empty line
Sample solution for filter_empty_lines.c
#include <stdio.h>
#include <stdlib.h>

#define MAX 4096

int main(void) {

    char line[MAX];

    while (fgets(line, MAX, stdin) != NULL) {

        // count non-whitespace characaters on this line
        int non_whitespace_count = 0;
        int i = 0;
        while (line[i] != '\n' && line[i] != '\0') {

            // test for non white space
            // !isspace(line[i]) would be better (from ctype.h)

            if ((line[i] != ' ') && (line[i] != '\t') && (line[i] != '\n')) {
                // this is a non-whitespace character
                non_whitespace_count = non_whitespace_count + 1;
                // could break here
            }

            i = i + 1;
        }

        // print the line if it has non-whitespace character
        if (non_whitespace_count > 0) {
            printf("%s", line);
        }

    }

    return 0;
}

7. Write a C program reverse.c which reads lines and writes them out with the characters of each line in reverse order.

It should stop when it reaches the end of the input.

For example:

./reverse
The quick brown fox jumped over the lazy dog.
.god yzal eht revo depmuj xof nworb kciuq ehT
It was the best of times. It was the worst of times.
.semit fo tsrow eht saw tI .semit fo tseb eht saw tI
This is the last line.
.enil tsal eht si sihT

Sample solution for reverse.c
#include <stdio.h>

#define MAX_LINE 4096

int main(void) {
    char line[MAX_LINE];

    while (fgets(line, MAX_LINE, stdin) != NULL) {

        // find the length of this line
        int i = 0;
        while (line[i] != '\n' && line[i] != '\0') {
            i = i + 1;
        }

        // when we exit, i is the index of either
        // newline character or null terminator
        // so go back one position

        i = i - 1;

        // now print line in reverse

        while (i >= 0) {
            printf("%c", line[i]);
            i = i - 1;
        }
        printf("\n");

    }
    return 0;
}

8. Strlen is a function that returns the length of a string. Write your own C function to do the same.
int myStrlen(char *string);
The key part to the question is knowing that a string has a null terminator character "\0" to note the end of the string. You simply loop until you come across that character.

int myStrlen(char *string) {

    int i = 0;
    while (string[i] != '\n' && string[i] != '\0') {
        i = i + 1;
    }
    
    return i;
}