COMP1911 23T2 Introduction to Programming
  1. Discuss the weakness of the style in the code below and how it might be improved. Don't spend too long on this. There are so many style issues. Just choose a few to talk about.

    Note:

    x += 1;  //is shorthand for
    x = x + 1;
    
    // Test if a point is inside a triangle.
    // Julian Saknussemm
    //
    // Given Three points of a triangle, and another arbitrary point this program determines if that point lies inside
    // the triangle.
    //
    // This is determined by satisfying the following rule:
    // A point P(x,y) is inside triangle A(x0,y0), B(x1,y1), C(x2,y2)
    // iff
    // P is on the same side of the line AB as C
    // P is on the same side of the line BC as A
    // and
    // P is on the same side of the line AC as B
    //
    // A special case exits for a vertical line (inf gradient) when testing the side of the line
    
    #include <stdio.h>
    
    int test2( double px, double py, double m, double b )
    {   if( py < m * px + b ) {
            return -1; // point is under line
               }else if ( py == m * px + b ){
               return 0;
               } else {
               return 1; // over
            }
    }
    
    int // two points lie on the same side of a line
    test1( double px, double py, double m,double b, double lx,double ly) {
            return (test2( px,py, m,b )==test2(lx,ly,m,b));
    }
    int tritest(double x0,double y0,double x1,double y1,double x2,double y2,double px, double py){
    
            int line1, line2, line3;
    // line eqns
    
    double m01 = (y1-y0)/(x1-x0);
    // b: y - y1 = m( x - x1 ), x = 0
    double b01 = m01 * -x1 + y1;
    double m02, m12, b02, b12;
    m02 = (y2-y0)/(x2-x0);
    m12 = (y2-y1)/(x2-x1);
    b02 = m02 * -x2 + y2;
    b12 = m12 * -x2 + y2;
    
    // vertical line checks
    if( x1 == x0 ) {
       line1 = ( (px <= x0) == (x2 <= x0) );
    } else {
       line1 = test1( px, py, m01, b01,x2,y2);
    }
    
    if( x1 == x2 ) {
            line2 = ( (px <= x2) == (x0 <= x2) );
    } else {
            line2 = test1(px,py, m12, b12,x0,y0);
    }
    
    if( x2 == x0 ) {
    line3 = ( (px <= x0 ) == (x1 <= x0) );} else {
            line3 = test1(px, py, m02,b02,x1,y1);
    }
    
       return line1 && line2 && line3;
    
    }
    int main(void) {
    double x0,y0,x1,y1,x2,y2,px;
    double py;
    
    int scanfsReturnValueAggregatedOverAllScanfs = 0;
    
    // get input
            printf("Triangle Vertex A (x,y): "); scanfsReturnValueAggregatedOverAllScanfs += scanf("%lf,%lf", &x0,&y0);
            printf("Triangle Vertex  B (x,y): "); scanfsReturnValueAggregatedOverAllScanfs += scanf("%lf,%lf", &x1,&y1);
            printf("Triangle Vertex  C (x,y): "); scanfsReturnValueAggregatedOverAllScanfs += scanf("%lf,%lf", &x2,&y2);
       printf("Test Point (x,y): "); scanfsReturnValueAggregatedOverAllScanfs += scanf("%lf,%lf", &px,&py);
    
    // print error
       if( scanfsReturnValueAggregatedOverAllScanfs != 8 ) {
                    printf("You're stupid and didn't put in the right inputs!\n");
                    return 1;
    }
    
    // print answer
       printf("Point (%.2lf,%.2lf) is ", px,py);
       if(tritest(x0,y0,x1,y1,x2,y2,px,py)) printf("inside");
       else printf("outside");
       printf(" the Triangel\n");
    
    // return 0
    return 0;
    }
    
    
    Many style issues, discussed in class.
    • But some very bad indentation.
    • Main function should be at top of file, with function prototypes above it.
    • What does the test2 function do? Needs a better name and a function header comment
    • Insulting error message
    • lines too wide and more than one statement on each line
    • Variable names are not great. scanfsReturnValueAggregatedOverAllScanfs is too long,
    • It is not immediately clear what x0, x1 etc are
    • In the main for some reason, px is declared on the same line as x0 but py isn't.
    • return 0 is not a useful comment etc
  2. This question is revision and also a warm up for one of the lab questions. Write a program which reads integers in the range 1..99 and prints how many time each integer has been read. The program should end when non-numeric input is encountered.

    It should behave in the following way

    ./integerCounter
    Enter a number: 1
    You have entered 1 1 times
    Enter a number: 1
    You have entered 1 2 times
    Enter a number: 99
    You have entered 99 1 times
    Enter a number: 3
    You have entered 3 1 times
    Enter a number: -1
    Try again: number has to be between 0 and 99 inclusive
    Enter a number: 3
    You have entered 3 2 times
    Enter a number: 
    
    Sample solution for integerCounter.c
    // A simple program which reads integers in the range 0..99
    // and prints how many time each integer has been read.
    //
    // Andrew Taylor - andrewt@unsw.edu.au
    // 10/4/18
    
    #include <stdio.h>
    
    #define LARGEST_INTEGER 99
    
    int main(void) {
        // the array element at index i
        // contains a count of how many times integer i has been seen
        int integerCounts[LARGEST_INTEGER + 1] = {0};
        int n;
        
        printf("Enter a number: ");
        while (scanf("%d", &n) == 1) {
           
            if (n < 0 || n > LARGEST_INTEGER) {
                printf("Try again: number has to be between 0 and %d inclusive\n",
                        LARGEST_INTEGER);
            } else {
                integerCounts[n] = integerCounts[n] + 1;
                printf("You have entered %d %d times\n", n, integerCounts[n]);
            }
            printf("Enter a number: ");
        }
        printf("\n");
    }
    
    
  3. What would the following program print?
    #include <stdio.h>
    
    int main(void) {
        int x = 'B';
        printf("%c\n",x+1);
        return 0;
    }
    
    It will print the letter C and a newline.
  4. Write a program upper_case.c which reads characters from its input and convert all lower case letters to upper case.

    The only functions you can use are getchar and putchar.

    For example:

    ./upper_case
    I'm very angry that you ate my chips!!!!!!
    I'M VERY ANGRY THAT YOU ATE MY CHIPS!!!!!!
    
    Sample solution for upper_case.c
    #include <stdio.h>
    
    int main(void) {
        int c;
        int alphabetPosition;
    
        // getchar returns an int which will contain either
        // the ASCII code of the character read or EOF
    
        c = getchar();
        while (c != EOF) {
    
            if (c >= 'a' && c <= 'z') {
                // toupper() would be better
                alphabetPosition = c - 'a';
                c = 'A' + alphabetPosition;
            }
    
            putchar(c);
    
            c = getchar();
        }
        return 0;
    }
    
    
  5. Write a program encrypt.c that encrypts a message by shifting letters one position up in the alphabet: 'a' => 'b', 'b' => 'c' ... 'y' => 'z' and shifts 'z' => 'a'

    It should do the same for upper case leters.

    Other characters should be unchanged.

    The only functions you can use are getchar and putchar.

    For example:

    ./encrypt
    Zulu Kilo Alpha proceed to Foxtrot Juliet at 1900 HOURS.
    Avmv Ljmp Bmqib qspdffe up Gpyuspu Kvmjfu bu 1900 IPVST.
    
    Sample solution for encrypt.c
    #include <stdio.h>
    
    int main(void) {
        int c;
    
        c = getchar();
        while (c != EOF) {
    
            // rotate letters one position higher in alphabet
            // a =>, b => c ... y => z, z => a
    
            if (c >= 'A' && c < 'Z') {
                c = c + 1;
            } else if (c == 'Z') {
                c = 'A';
            } else if (c >= 'a' && c < 'z') {
                c = c + 1;
            } else if (c == 'z') {
                c = 'a';
            }
    
            putchar(c);
            c = getchar();
        }
        return 0;
    }
    
    
  6. Write a program decrypt.c that decrypts (inverts the encryption) a message which has been encrypted by encrypt.c from the previous question.

    Again the only functions you can use are getchar and putchar.

    For example:

    ./decrypt
    Avmv Ljmp Bmqib qspdffe up Gpyuspu Kvmjfu bu 1900 IPVST.
    Zulu Kilo Alpha proceed to Foxtrot Juliet at 1900 HOURS.
    
    Sample solution for decrypt.c
    #include <stdio.h>
    
    int main(void) {
        int c;
    
        c = getchar();
        while (c != EOF) {
    
            // rotate letters one positon lower in alphabet
            // z => y, y => x ... b => a, a => z
    
            if (c > 'A' && c <= 'Z') {
                c = c - 1;
            } else if (c == 'A') {
                c = 'Z';
            } else if (c > 'a' && c <= 'z') {
                c = c - 1;
            } else if (c == 'a') {
                c = 'z';
            }
    
            putchar(c);
            c = getchar();
        }
        return 0;
    }
    
    
  7. Write a program sum_digits.c which reads characters from its input and counts digits.

    When the end of input is reached it should print a count of how many digits occured in its input and their sum.

    The only functions you can use are getchar and printf.

    For example:

    ./sum_digits
    1 2 3 o'clock
    4 o'clock rock
    Input contained 4 digits which summed to 10
    ./sum_digits
    12 twelve 24 twenty four
    thirty six 36
    Input contained 6 digits which summed to 18
    
    Sample solution for sum_digits.c
    #include <stdio.h>
    
    int main(void) {
        int c;
        int digitCount, digitSum, digitValue;
    
        digitCount = 0;
        digitSum = 0;
    
        // getchar returns an int which will contain either
        // the ASCII code of the character read or EOF
    
        c = getchar();
        while (c != EOF) {
    
            // test if ch is digit, isdigit would be better
            if (c >= '0' && c <= '9') {
                digitCount = digitCount + 1;
                digitValue = c - '0';
                digitSum = digitSum + digitValue;
            }
    
            c = getchar();
        }
        printf("Input contained %d digits which summed to %d\n", digitCount, digitSum);
        return 0;
    }
    
    
  8. Consider the following program
    #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/run?
      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 /home/bin/dcc --valgrind will then stop with an error because str[2] is uninitialized.

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

      Another common behaviour 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 indexes well outside the array it may be terminated by the the operating system with a segmentation fault 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;
      }
      
  9. 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
    C Rocks
    line 7 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];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
            i = 0;
            while (line[i] != '\n' && line[i] != '\0') {
                i = i + 1;
            }
            printf("line %d characters long\n", i);
        }
        return 0;
    }
    
    
  10. 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 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
    <control-d>
    
    Sample solution for reverse.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            i = 0;
            while (line[i] != '\n' && line[i] != '\0') {
                i = i + 1;
            }
    
            i = i - 1;
    
            while (i >= 0) {
                printf("%c", line[i]);
                i = i - 1;
            }
            printf("\n");
    
        }
        return 0;
    }
    
    
  11. 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 another words remove lines 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 & new-line.

    For example:

    ./filter_empty_lines
    full line
    full line
             
    another no-empty line
    another no-empty line
    
    Sample solution for filter_empty_lines.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int main(void) {
        char line[MAX_LINE];
        int  i;
        int nonWhiteSpaceCount;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            // print lines iff they contain a non white-space character
    
            i = 0;
            nonWhiteSpaceCount = 0;
            while (line[i] != '\0') {
                // test for white space (isspace function would be better here)
    
                if (line[i] != ' ' && line[i] != '\t' && line[i] != '\n') {
                    nonWhiteSpaceCount = whiteSpaceCount + 1;
                    // could break here
                }
    
                i = i + 1;
            }
    
            if (nonWhiteSpaceCount > 0) {
                printf("%s", line);
            }
        }
        return 0;
    }
    
    
  12. Write a program strip_comments.c which reads lines from its input and prints them after removing any C // style comments. In another 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 and NO! That is NOT a good comment to add to a C program. It adds no meaning to the code and is stating the obvious.
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            // strip // style comments from input
    
            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 end of -line
                    line[i] = '\n';
                    line[i + 1] = '\0';
    
                    // could break here but loop will stop anyway
                }
    
                i = i + 1;
            }
    
            // write possibly-modified line
    
            printf("%s", line);
        }
        return 0;
    }
    
    
  13. Write a program input_statistics.c that for the characters provided on standard input.:
    • outputs the number of white-space characters (spaces, tabs and new lines)
    • outputs the numbers of words word (any contiguous sequence of non-white-space characters), and
    • outputs the length of the shortest word
    • outputs the length of the longest word

    For example:

    ./input_statistics
        "Beauty is truth, truth beauty," ? that is all
        Ye know on earth, and all ye need to know.
    Input contains 27 blanks, tabs and new lines
    Number of words: 19
    Length of shortest word: 2
    Length of longest word: 8
    ./input_statistics
    And here is another example with only one line of input!!!!!!!!!
    Input contains 11 blanks, tabs and new lines
    Number of words: 11
    Length of shortest word: 2
    Length of longest word: 14
    
    Sample solution for input_statistics.c
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * Description: Outputs                                                        *
     *              - the number of blank characters (spaces, tabs and new lines)  *
     *              - the length of the shortest word                              *
     *                (any sequence of nonblank characters), and                   *
     *              - the length of the longest word                               *
     *                (any sequence of nonblank characters)                        *
     *              read from standard input.                                      *
     *                                                                             *
     * Written by Eric Martin for COMP9021                                         *
     * Modified by Andrew Taylor for COMP9021                                         *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    
    #include <stdio.h>
    
    int main(void) {
        int whiteSpaceCount;
        int wordMinLength, wordMaxLength, wordCurrentLength;
        int wordCount;
        int ch;
    
        wordCount = 0;
        whiteSpaceCount = 0;
        wordCurrentLength = 0;
    
        ch = getchar();
        while (ch != EOF) {
    
            // iswhite would be better here
            if (ch == ' ' || ch == '\t' || ch == '\n') {
    
                whiteSpaceCount = whiteSpaceCount + 1;
    
                // A complete word has just been read iff wordCurrentLength > 0,
                // which is then the length of that word.
    
                if (wordCurrentLength > 0) {
                    if (wordCount == 0) {
                        wordMinLength = wordCurrentLength;
                    } else if (wordCurrentLength < wordMinLength) {
                        wordMinLength = wordCurrentLength;
                    } else if (wordCurrentLength > wordMaxLength) {
                        wordMaxLength = wordCurrentLength;
                    }
    
                    wordCurrentLength = 0;
                    wordCount = wordCount + 1;
                }
            } else {
                wordCurrentLength = wordCurrentLength + 1;
            }
            ch = getchar();
        }
    
        printf("Input contains %d blanks, tabs and new lines\n", whiteSpaceCount);
    
        if (wordCount == 0) {
            printf("No word has been input\n");
        } else {
            printf("Number of words: %d\n", wordCount);
            printf("Length of shortest word: %d\n", wordMinLength);
            printf("Length of longest word: %d\n", wordMaxLength);
        }
    
        return 0;
    }
    
    
  14. Write a program letter_triangle.c that read an positive integer n and outputs a triangle of letters of height n as below. For example:
    ./letter_triangle
    Enter height: 3
      A
     BCB
    DEFED
    ./letter_triangle
    Enter height: 7
          A
         BCB
        DEFED
       GHIJIHG
      KLMNONMLK
     PQRSTUTSRQP
    VWXYZABAZYXWV
    ./letter_triangle
    Enter height: 10
             A
            BCB
           DEFED
          GHIJIHG
         KLMNONMLK
        PQRSTUTSRQP
       VWXYZABAZYXWV
      CDEFGHIJIHGFEDC
     KLMNOPQRSRQPONMLK
    TUVWXYZABCBAZYXWVUT
    
    Sample solution for letter_triangle.c
    
    // Description: Prompts the user for a strictly positive number N
    //              and outputs an equilateral triangle of height N.
    //              The top of the triangle (line 1) is labeled with the letter A.
    //              For all nonzero p < N, line p + 1 of the triangle is labeled
    //              with letters that go up in alphabetical order modulo 26
    //              from the beginning of the line to the middle of the line,
    //              starting wth the letter that comes next in alphabetical order
    //              modulo 26 to the letter in the middle of line p,
    //              and then down in alphabetical order modulo 26
    //              from the middle of the line to the end of the line.
    //
    // Written by Eric Martin for COMP9021
    // modified by Andrew Taylor for 1911
    
    #include <stdio.h>
    
    int main(void) {
        int ch, i, j, k;
        int height = 0;
    
    
        printf("Enter height: ");
        scanf("%d", &height);
    
        ch = 'A';
        i = 1;
        while (i <= height) {
    
            /* Displays spaces on the left */
            j = 0;
            while (j < height - i) {
                printf(" ");
                j = j + 1;
            }
    
            /* Displays letters before middle column */
            k = 1;
            while (k < i) {
                putchar(ch);
    
                /* code of next letter */
                ch = (ch - 'A' + 1) % 26 + 'A';
                k = k + 1;
            }
    
            /* Displays middle column */
            putchar(ch);
    
            /* Displays letters after middle column */
            k = 1;
            while (k < i) {
    
                /* Code of previous letter */
                ch = (ch - 'A' + 25) % 26 + 'A';
                putchar(ch);
                k = k + 1;
            }
            printf("\n");
    
            /* Code of first letter to be input on next line */
            ch = ((1 + i) * i / 2) % 26 + 'A';
            i = i + 1;
        }
    
        return 0;
    }