CMSI 284
Homework #2
Partial Answers
  1. /*
     * This application writes a table of piano notes and their frequencies
     * to standard output.
     */
    
    #include <stdio.h>
    #include <math.h>
    
    char *names[] = {"A","A#","B","C","C#","D","D#","E","F","F#","G","G#"};
    int STEPS = sizeof names / sizeof (char*);
    int INITIAL_FREQUENCY = 27.5;
    int NUM_KEYS = 88;
    
    int main() {
        int i;
        for (i = 0; i < NUM_KEYS; i++) {
            printf("%s\t%10.4f\n", names[i%STEPS],
                    INITIAL_FREQUENCY * pow(2.0, (double)i / STEPS));
        }
        return 0;
    }
    
  2. /*
     * pianoscales.c
     *
     * Takes a single command line argument which is the name of a note
     * and prints, to standard output, the major (Ionian) and minor (Aeolian)
     * scales starting at that note.  The program is very week; note names
     * are constrained to be in {A, A#, B, C, C#, D, D#, E, F, F#, G, G#}.
     */
    
    #include <stdio.h>
    #include <string.h>
    
    char *keys[] = {"A","A#","B","C","C#","D","D#","E","F","F#","G","G#"};
    int NUMBER_OF_NOTES = sizeof keys / sizeof (char*);
    int majorSteps[] = {2,2,1,2,2,2,1};
    int minorSteps[] = {2,1,2,2,1,2,2};
    
    /*
     * Writes a progression of notes whose step sizes come from the steps array.
     */
    void printScale(int noteIndex, int steps[], int numberOfSteps) {
        int i;
        int j;
        for (i = 0, j = 0; i <= numberOfSteps; j += steps[i++]) {
            printf("%3s", keys[(noteIndex + j) % NUMBER_OF_NOTES]);
        }
    }
    
    /*
     * Display the major and minor scales for a specified piano key input.
     */
    int main(int argc, char** argv) {
        int j;
    
        if (argc != 2) {
            printf("This program requires exactly one command line argument\n");
            return -1;
        }
    
        /* Find the note index for a given note name */
        for (j = 0; j < NUMBER_OF_NOTES && strcmp(argv[1], keys[j]) != 0; j++)
            ;
    
        /* Not found? */
        if (j == NUMBER_OF_NOTES) {
            printf("No such key: %s\n", argv[1]);
            return -2;
        }
    
        /* Write major and minor */
        printf("%s major:", argv[1]);
        printScale(j, majorSteps, 7);
        printf("\n%s minor:", argv[1]);
        printScale(j, minorSteps, 7);
        printf("\n");
    
        return 0;
    }
    
  3. #include <stdlib.h>
    
    #define max(x,y) ((x)<(y)?(y):(x))
    
    /*
     * max_string(s, t) returns the string u with the same length as
     * the longes of s and t, containing, in each position i, the
     * larger of s[i] and t[i].  If a position is part of only one
     * of s or t, then u[i] contains the character in the longer
     * string.
     */
    char* max_string(char* s, char* t) {
        int length_s = strlen(s);
        int length_t = strlen(t);
    
        /* Allocate space for the result */
        int n = max(length_s, length_t);
        char* result = malloc(n * sizeof(char) + 1);
    
        /* Put in the result characters */
        int i;
        for (i = 0; i < n; i++) {
            if (i >= length_s) result[i] = t[i];
            else if (i >= length_t) result[i] = s[i];
            else result[i] = max(s[i], t[i]);
        }
    
        /* Insert the string terminator and return. */
        result[i] = '\0';
        return result;
    }
    
    /*
     * max_string_test_case.c
     *
     * Test case for the funky max_string function.
     */
    
    #include <assert.h>
    #include <string.h>
    #include <stdio.h>
    
    /* Usually it's best to include from .h files, but this is ok for a test */
    #include "max_string.c"
    
    int main() {
    
        assert(strcmp(max_string("doghouse", "rats"), "rotsouse") == 0);
        assert(strcmp(max_string("rats", "doghouse"), "rotsouse") == 0);
        assert(strcmp(max_string("", ""), "") == 0);
        assert(strcmp(max_string("", "Abc"), "Abc") == 0);
        assert(strcmp(max_string("Abc", ""), "Abc") == 0);
        assert(strcmp(max_string("123", "abc"), "abc") == 0);
        assert(strcmp(max_string("abc", "123"), "abc") == 0);
    
        printf("All tests passed\n");
    
        return 0;
    }
    
  4. #include <string.h>
    #include <stdlib.h>
    
    /*
     * Returns the k-fold left-rotation of s, as a newly allocated
     * string. (That means the caller is responsible for the memory.)
     * If k is not in the range 0..strlen(s), returns NULL.
     *
     * Examples:
     *    rotate_left("doghouse", 0)  ===>  "doghouse"
     *    rotate_left("doghouse", 1)  ===>  "oghoused"
     *    rotate_left("doghouse", 2)  ===>  "ghousedo"
     *    rotate_left("doghouse", 3)  ===>  "housedog"
     *    rotate_left("doghouse", 4)  ===>  "ousedogh"
     *    rotate_left("doghouse", 5)  ===>  "usedogho"
     *
     * Rotating a negative number of times returns a copy of the
     * input, as it should, since rotating -4 times is rotating
     * not at all.
     */
    char* rotate_left(char* s, int k) {
        int i = 0;
        int j;
        int n = strlen(s);
    
        /* Handle non-positive k as well as the empty string. */
        if (k <= 0 || n == 0) return strdup(s);
    
        /* Ensure 0 <= k < n.  This is one reason we checked for n==0 above. */
        if (k >= n) k %= n;
    
        /* Allocate space for the result */
        char* result = malloc(n * sizeof(char) + 1);
    
        /* Put in the result characters */
        for (j = k; j < n; j++) result[i++] = s[j];
        for (j = 0; j < k; j++) result[i++] = s[j];
    
        /* Insert the string terminator and return. */
        result[i] = '\0';
        return result;
    }
    
    #include <assert.h>
    #include <string.h>
    #include <stdio.h>
    
    /* Usually it's best to include from .h files, but this is ok for a test */
    #include "rotate.c"
    
    int main() {
    
        assert(strcmp(rotate_left("doghouse", -5), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", -50), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 0), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 8), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 16), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 24), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 32), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 800000), "doghouse") == 0);
        assert(strcmp(rotate_left("doghouse", 1), "oghoused") == 0);
        assert(strcmp(rotate_left("doghouse", 2), "ghousedo") == 0);
        assert(strcmp(rotate_left("doghouse", 3), "housedog") == 0);
        assert(strcmp(rotate_left("doghouse", 4), "ousedogh") == 0);
        assert(strcmp(rotate_left("doghouse", 5), "usedogho") == 0);
        assert(strcmp(rotate_left("doghouse", 6), "sedoghou") == 0);
        assert(strcmp(rotate_left("doghouse", 7), "edoghous") == 0);
        assert(strcmp(rotate_left("doghouse", 11), "housedog") == 0);
        assert(strcmp(rotate_left("doghouse", 19), "housedog") == 0);
        assert(strcmp(rotate_left("", 0), "") == 0);
        assert(strcmp(rotate_left("", 1), "") == 0);
        assert(strcmp(rotate_left("", 60000), "") == 0);
        assert(strcmp(rotate_left("", -20), "") == 0);
        assert(strcmp(rotate_left("x", -20), "x") == 0);
        assert(strcmp(rotate_left("x", 0), "x") == 0);
        assert(strcmp(rotate_left("x", 20), "x") == 0);
        assert(strcmp(rotate_left("x", 5000), "x") == 0);
    
        printf("All tests passed\n");
    
        return 0;
    }
    

  5. Common problems with many of the submissions: