COMP1511 17s1 Introduction to Programming

Objectives

In this Lab, you will practise:

Preparation

Before the lab you should re-read the relevant lecture slides and their accompanying examples. You should also have read the lab assessment guidelines.

Getting Started

One member of your programming pair should login and run the following commands inside a Linux terminal

Create a new directory for this lab called lab09 by typing:

mkdir lab09
Change to this directory by typing:
cd lab09

Exercises: Printing Characters One Per Line

Write a C program, one.c, which reads in a string from standard input and writes out the characters one per line. The output from your program should look like this:
./one
Enter a string: Hello
H
e
l
l
o

Hint: don't use scanf, use fgets to read the string.

Note, your program needs to read only one string - it doesn't have to read until the end of input.

You can assume lines contain at most 4096 characters.

As usual autotest is available to test your program.

 ~cs1511/bin/autotest lab09 one.c
Sample solution for one.c
// Read a string and then print the letters one per line
// written by Andrew Taylor andrewt@cse.unsw.edu.au
// April 2017 as a COMP1511 lab exercise
//

#include <stdio.h>

#define MAXLINE 4094

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

    printf("Enter a string: ");
    fgets(line, MAXLINE, stdin);

    i = 0;
    while (line[i] != '\n' && line[i] != '\0') {
        printf("%c\n", line[i]);
        i = i + 1;
    }

    return 0;
}

Exercises: Palindrome

A palindrome is a sequence which is the same forwards as backwards.

Write a program, palindrome.c, which reads a string and tests if it is a palindrome.

For example:

./palindrome
Enter a string: kayak
String is a palindrome
./palindrome
Enter a string: canoe
String is not a palindrome
Hint: don't use scanf, use fgets to read the string.

Note, your program needs to read only one string - it doesn't have to read until the end of input.

You can assume lines contain at most 4096 characters.

As usual autotest is available to test your program.

 ~cs1511/bin/autotest lab09 palindrome.c
Sample solution for palindrome.c
//
// Read a string and then indicate if it is a palindrome
// written by Andrew Taylor andrewt@cse.unsw.edu.au
// April 2017 as a COMP1511 lab exercise
//

#include <stdio.h>

#define MAXLINE 4094


int
main(int argc, char *args[]) {
    char line[MAXLINE];
    int  left, right;

    printf("Enter a string: ");
    fgets(line, MAXLINE, stdin);

    left = 0;

    right = 0;
    while (line[right] != '\0' && line[right] != '\n') {
        right =  right + 1;
    }

    if (right == 0) {
        return 0;
    }

    right = right - 1;

    while (left < right) {
        if (line[left] != line[right]) {
            printf("String is not a palindrome\n");
            return 0;
        }
        left = left + 1;
        right = right - 1;
    }

    printf("String is a palindrome\n");
    return 0;
}

Exercise: Creating A Numbers File

Write a C program, numbers.c which takes 3 arguments which creates a file containing specified integers, one per line. The first & second arguments will specify a range of integers. The third argument will specify the file to be created. For example:
./numbers 40 42 fortytwo.txt
cat fortytwo.txt
40
41
42
./numbers 1 5 a.txt
cat a.txt
1
2
3
4
5
./numbers 1 1000  1000.txt
wc 1000.txt
1000 1000 3893 1000.txt
You should print a suitable error message if given the wrong number of arguments or if the file can not be created. As usual autotest is available to test your program.
 ~cs1511/bin/autotest lab09 numbers.c
Sample solution for numbers.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s: <start> <finish> <file>\n", argv[0]);
        exit(1);
    }

    int start = atoi(argv[1]);
    int finish = atoi(argv[2]);
    FILE *stream = fopen(argv[3], "w");

    if (stream == NULL) {
        perror(argv[3]);
        exit(1);
    }

    for (int i = start; i <= finish; i = i + 1) {
        fprintf(stream, "%d\n", i);
    }

    fclose(stream);
    return 0;
}

Exercise: Head

Write a program, head.c, which given a filename as argument prints the first 10 lines of the file. If the file has less than 10 lines the entire file should be printed.

Note unlike the 2 previous exercises this program should not create any files. Its just prints part of the content of a file to standard output.

For example:

./head 1000.txt
1
2
3
4
5
6
7
8
9
10
./head /usr/include/stdio.h
/* Define ISO C stdio on top of C++ iostreams.
   Copyright (C) 1991-2016 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
It should also be possible to specify that a different number of lines be printed. This will specified by passing the string "-n" as the first argument to the program, the number of lines to be printed as the second argument and the file as the third argument. For example:
./head -n 3 1000.txt
1
2
3
You should print a suitable message if incorrect arguments are supplied or the file can not be read.

You can assume lines have at most 1024 characters, but if possible avoid this assumption.

As usual autotest is available to test your program.

 ~cs1511/bin/autotest lab09 head.c
Sample solution for head.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DEFAULT_NLINES 10

void
head(char *filename, int nLines) {
    FILE *f;
    int  ch, lines;

    f = fopen(filename, "r");
    if (f == NULL) {
        perror(filename);
        exit(1);
    }
    lines = 0;
    while (lines < nLines) {
        ch = fgetc(f);
        if (ch == EOF) {
            fclose(f);
            return;
        }
        putchar(ch);
        if (ch == '\n') {
            lines = lines + 1;
        }
    }
    fclose(f);
}

#define MAX_LINE_LENGTH 1024


// Alternative version using fgets
// - has the disadvantage of a maximum line length.
void
head1(char *filename, int nLines) {
    int  lineNumber;
    char line[MAX_LINE_LENGTH + 2];

    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        perror(filename);
        exit(1);
    }
    lineNumber = 0;

    while (lineNumber < nLines && fgets(line, MAX_LINE_LENGTH, f) != NULL) {
        lineNumber = lineNumber + 1;
        fputs(line, stdout);
    }
    fclose(f);
}

int main(int argc, char *argv[]) {
    int nLines;
    char *filename;

    if (argc == 2) {
        nLines = DEFAULT_NLINES;
        filename = argv[1];
    } else if (argc == 4 && strcmp(argv[1], "-n") == 0) {
        nLines = atoi(argv[2]);
        filename = argv[3];
    } else {
        fprintf(stderr, "Usage: head [-n lines] <file>");
        exit(1);
    }
    head(filename, nLines);
    return 0;
}

Challenge Exercise: Modifying Palindrome

Modify your Palindrome program (call it palindrome1.c) so characters which are not letters are ignored and difference between upper case and lower case are ignored. For example:

./palindrome1
Enter a string: Do geese see God?
String is a palindrome
./palindrome1
Enter a string: Do ducks see God?
String is not a palindrome
./palindrome1
Enter a string: Madam, I'm Adam
String is a palindrome
./palindrome1
Enter a string: Madam, I'm Andrew
String is not a palindrome

Hint: if you #include <ctype.h> you can use a C library function named tolower to convert a character to lower case.

 ~cs1511/bin/autotest lab09 palindrome1.c
Sample solution for palindrome1.c
//
// Read a string and then indicate if it is a palindrome
// only lower case alphabetic letters are considered
// written by Andrew Taylor andrewt@cse.unsw.edu.au
// April 2017 as a COMP1511 lab exercise
//

#include <stdio.h>
#include <ctype.h>


#define MAXLINE 4094

int
main(int argc, char *args[]) {
    char line[MAXLINE];
    int  left, right ;

    printf("Enter a string: ");
    fgets(line, MAXLINE, stdin);

    left = 0;

    right = 0;
    while (line[right] != '\0' && line[right] != '\n') {
        line[right] = tolower(line[right]);
        right =  right + 1;
    }

    if (right == 0) {
        return 0;
    }

    right = right - 1;

    while (left < right) {
        // printf("line[%d]='%c'line[%d]='%c'\n", left, line[left], right, line[right]);
        if (line[left] < 'a' || line[left] > 'z') {
            left = left + 1;
        } else if (line[right] < 'a' || line[right] > 'z') {
            right = right - 1;
        } else if (line[left] != line[right]) {
            printf("String is not a palindrome\n");
            return 0;
        } else {
           left = left + 1;
           right = right - 1;
        }
    }

    printf("String is a palindrome\n");
    return 0;
}

Challenge Exercise: Tail

Write a program, tail.c, which given a filename as argument prints the last 10 lines of the file. If the file has less than 10 lines the entire file should be printed.

You can assume lines have at most 1024 characters, but you can not make any assumption about how many lines are in the file.

You can not read the entire file into an array.

For example:

./tail 1000.txt
991
992
993
994
995
996
997
998
999
1000
./numbers 1 100000 100000.txt
wc  100000.txt
100000 100000 588895 100000.txt
./tail 100000.txt
99991
99992
99993
99994
99995
99996
99997
99998
99999
100000

You should print a suitable message if incorrect arguments are supplied or the file can not be read.

Unlike the previous exercise it does not have to be possible to specify a different number of lines to be printed.

As usual autotest is available to test your program.

 ~cs1511/bin/autotest lab09 tail.c
Sample solution for tail.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define NLINES 10
#define MAX_LINE_LENGTH 1024

// https://en.wikipedia.org/wiki/Circular_buffer  explains
// how the array line is used here

int main(int argc, char *argv[]) {
    char line[NLINES][MAX_LINE_LENGTH];   // line buffer
    int lineNumber, i;
    FILE *stream;

    if (argc != 2) {
        fprintf(stderr, "Usage: tail [-n lines] <file>");
        exit(1);
    }
    stream = fopen(argv[1], "r");
    if (stream == NULL) {
        fprintf(stderr, "%s: %s: ", argv[0], argv[1]);
        perror("");
        exit(1);
    }

    lineNumber = 0;
    while (fgets(line[lineNumber % NLINES], MAX_LINE_LENGTH, stream) != NULL) {
        lineNumber = lineNumber + 1;
    }
    fclose(stream);

    i = lineNumber - NLINES;
    if (i < 0) {
        i = 0;
    }
    while (i < lineNumber) {
        printf("%s", line[i % NLINES]);
        i = i + 1;
    }

    return 0;
}

Submission/Assessment

When you are satisfied with your work, ask your tutor to assess it. You also need to submit your work electronically by typing (run this command in the lab09 directory):
give cs1511 lab09 one.c palindrome.c numbers.c head.c palindrome1.c tail.c
Submit the challenge exercises only if you attempt them.

If you are working at home, you may find it more convenient to upload your work via give's web interface.

Remember the lab assessment guidelines - if you don't finish the exercises you can finish them in your own time, submit them by Monday 11:00am using give and ask your tutor to assess them at the start of the following lab.

Either or both members of a programming pair can submit the work (make sure each program lists both of you as authors in the header comment).