Programming Fundamentals

Information

  • This page contains additional revision exercises for week 01.
  • These exercises are not compulsory, nor do they provide any marks in the course.
  • You cannot submit any of these exercises, however autotests may be available for some them (Command included at bottom of each exercise if applicable).

Exercise — individual:
Temperature

Write a program temperature.c that scans in the temperature of each day for a week, then prints out the temperature.

Your program should scan in seven integers, storing them in an array. The program should then print out the temperatures for the week using the message Day <num>: <temperature> degrees., where <num> is the day of the week from 1-7, and <temperature> is the temperature that was scanned in for that particular day.

Examples

dcc temperature.c -o temperature
./temperature
Enter the temperatures for the week: 30 29 28 30 30 27 24
Day 1: 30 degrees.
Day 2: 29 degrees.
Day 3: 28 degrees.
Day 4: 30 degrees.
Day 5: 30 degrees.
Day 6: 27 degrees.
Day 7: 24 degrees.
./temperature
Enter the temperatures for the week: 0 -4 120 42 3 -250 12
Day 1: 0 degrees.
Day 2: -4 degrees.
Day 3: 120 degrees.
Day 4: 42 degrees.
Day 5: 3 degrees.
Day 6: -250 degrees.
Day 7: 12 degrees.

Assumptions/Restrictions/Clarifications

  • You may assume that the correct number of inputs will be entered.
  • You may assume that the input will always be an integer.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest temperature
Sample solution for temperature.c
// Temperature
// temperature.c
//
// This program scans temperatures for a week into an array, then
// prints out the temperatures for the week

#include <stdio.h>

#define NUM_DAYS 7

int main(void) {
    int temperature[NUM_DAYS];
    printf("Enter the temperatures for the week: ");

    // Scan temperature into array
    for (int i = 0; i < NUM_DAYS; i++) {
        scanf("%d", &temperature[i]);
    }

    // Print out temperatures for the week
    for (int i = 0; i < NUM_DAYS; i++) {
        printf("Day %d: %d degrees.\n", i + 1, temperature[i]);
    }
    return 0;
}

Exercise — individual:
Calculate the average of columns in a 2D array

Download array_col_average.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity array_col_average

Your task is to add code to this function in array_col_average.c:

// Calculates the sum of each col of the array and prints it out
void array_col_average(int array[MAX_SIZE][MAX_SIZE], int num_rows, int num_cols) {
    
    // TODO: Complete this function

}

Write a function array_col_average that calculates the average for each column of the array and prints out the result.

Your function should print out the message Average of col <num> is <average>. for each column, where <num> is the current column, and <average> is the average of that column to two decimal places.

Examples

If the 2D array contains these elements:

{0, 1, 9, 2}, 
{5, 4, 6, 7}, 
{7, 6, 3, 9},
{3, 8, 1, 8}

Your function should print the following:
Average of col 0 is 3.75.
Average of col 1 is 4.75.
Average of col 2 is 4.75.
Average of col 3 is 6.50.

Alternatively, if the 2D array contains these elements:

{0, 1, 2}, 
{3, 4, 5}, 
{6, 7, 8},
{9, 8, 7}

Your function should print the following:
Average of col 0 is 3.00.
Average of col 1 is 3.75.
Average of col 2 is 4.00.
Average of col 3 is 4.25.

Assumptions/Restrictions/Clarifications

  • You may assume that the number of rows and cols will always be greater than 0.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest array_col_average
Sample solution for array_col_average.c
// Array Col Average
// array_col_average.c
//
// This program calculates the average of each column in a 2D array

#include <stdio.h>

#define MAX_SIZE 100

void array_col_average(int array[MAX_SIZE][MAX_SIZE], int num_rows, int num_cols);

int main(void) {
    int array[MAX_SIZE][MAX_SIZE] = {
        {0, 1, 9, 2}, 
        {5, 4, 6, 7}, 
        {7, 6, 3, 9},
        {3, 8, 1, 8}
    };

    printf("First array: \n");
    array_col_average(array, 4, 4);
   
    int array2[MAX_SIZE][MAX_SIZE] = {
        {0, 1, 2}, 
        {3, 4, 5}, 
        {6, 7, 8},
        {9, 8, 7}
    };

    printf("\nSecond array: \n");
    array_col_average(array2, 4, 3);
   
    return 0;
}


// Calculates the sum of each row of the array and prints it out
void array_col_average(int array[MAX_SIZE][MAX_SIZE], int num_rows, int num_cols) {
    int col = 0;
    while (col < num_cols) {
        int sum = 0;
        int row = 0;
        while (row < num_rows) {
            sum += array[row][col];
            row++;
        }
        double average = (double) sum / num_cols;
        printf("Average of col %d is %.2lf.\n", col, average);
        col++;
    }
    return;
}

Exercise — individual:
Calculate Weekly Earnings

Gary keeps track of the amount of money he earns per day, per week and stores this information in a 1D array. Your program should calculate the total amount of money Gray has made in a week.

Write a program calculate_weekly_earnings.c that:

  1. Prompts the user with the message Enter the amount of money earned in the week: .
  2. Scans in seven integers, storing them in an array.
  3. Calculates the sum of an array of size 7.
  4. Print the message The total money earned this week was <sum>. , where <sum> is the total sum of the array.

Examples

dcc calculate_weekly_earnings.c -o calculate_weekly_earnings
./calculate_weekly_earnings
Enter the amount of money earned in the week: 3 9 6 5 1 2 4
The total money earned this week was $30.
./calculate_weekly_earnings
Enter the amount of money earned in the week: 0 63 0 90 34 0 0
The total money earned this week was $187.

Assumptions/Restrictions/Clarifications

  • You may assume that all inputs are integers.
  • You may assume that there will be the correct number of inputs.
  • You may assume that all inputs will be non-negative.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest calculate_weekly_earnings
Sample solution for calculate_weekly_earnings.c
// Calculate Weekly Earnings
// calculate_weekly_earnings.c
//
// This program calculates weekly earnings from a 2D array

#include <stdio.h>

#define NUM_DAYS 7

int main(void) {

    int array[NUM_DAYS];

    printf("Enter the amount of money earned in the week: ");

    // Scans weekly earnings into the array
    for (int i = 0; i < NUM_DAYS; i++) {
        scanf("%d", &array[i]);
    }

    // Loops through the array to calculate total weekly earnings
    int sum = 0;
    for (int i = 0; i < NUM_DAYS; i++) {
        sum += array[i];
    }

    // Prints the total weekly earnings
    printf("The total money earned this week was $%d.\n", sum);
   
    return 0;
}

Exercise — individual:
Find the fastest and slowest runners

Download races.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity races

Your task is to add code to this function in races.c:

    return;
}

Write a program races that determines the fastest and slowest racers in a running race based on their average time.

The racers are numbered from 1 to n , which correspond to the rows 0 to n - 1 in a 2D array. Each column is a lap in the race. In order to find the fastest and slowest runners, each runners time should be averaged for their laps.

Examples

If the 2D array contains these elements:

{11.12, 12.30, 11.54}, 
{15.43, 15.67, 15.14}, 
{12.95, 12.43, 13.02},
{10.04, 10.56, 10.59},
{13.89, 14.05, 13.73}

Your function should print: Runner 4 was the fastest with an average time of 10.40. and Runner 2 was the slowest with an average time of 15.41.

Breaking this down, the following runners and times are displayed below

			Lap 1     Lap 2     Lap 3
Runner 1:   11.12     12.30     11.54
Runner 2:   15.43     15.67     15.14
Runner 3:   12.95     12.43     13.02
Runner 4:   10.04     10.56     10.59
Runner 5:   13.89     14.05     13.73

Your function should average these times to two decimal places, which produces:

           Average time
Runner 1:     11.65
Runner 2:     15.41
Runner 3:     12.80
Runner 4:     10.40
Runner 5:     13.89

Based on these values, it can be determined that Runner 4 is the fastest runner and Runner 2 is the slowest runner, and your function should print the following lines: Runner 4 was the fastest with an average time of 10.40.

Runner 2 was the slowest with an average time of 15.41.

Assumptions/Restrictions/Clarifications

  • You can assume that the averages of all rows will never be equal.
  • You can assume that rows and cols of arrays will always be greater than 0.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest races
Sample solution for races.c
// Races
// races.c
//
// This program calculates the fastest and slowest runners based
// on their average lap time.

#include <stdio.h>

#define MAX_SIZE 100

void find_fastest_and_slowest(double array[MAX_SIZE][MAX_SIZE], int num_rows, int num_cols);

int main(void) {
    double array[MAX_SIZE][MAX_SIZE] = {
        {11.12, 12.30, 11.54}, 
        {15.43, 15.67, 15.14}, 
        {12.95, 12.43, 13.02},
        {10.04, 10.56, 10.59},
        {13.89, 14.05, 13.73}
    };

    printf("First array: \n");
    find_fastest_and_slowest(array, 5, 3);
   
    double array2[MAX_SIZE][MAX_SIZE] = {
        {0, 1, 2}, 
        {3, 4, 5}, 
        {6, 7, 8},
        {9, 8, 7}
    };

    printf("\nSecond array: \n");
    find_fastest_and_slowest(array2, 4, 3);
   
    return 0;
}

// Finds the fastest and slowest racers based on their average lap time
void find_fastest_and_slowest(double array[MAX_SIZE][MAX_SIZE], int num_rows, int num_cols) {
    double min = 0;
    double max = 0;
    int slowest = 0;
    int fastest = 0;

    int row = 0;
    while (row < num_rows) {
        double sum = 0;
        int col = 0;
        while (col < num_cols) {
            sum += array[row][col];
            col++;
        }
        double average = sum / num_cols;
        if (row == 0) {
            min = average;
            max = average;
            slowest = 0;
            fastest = 0;
        } else {
            if (average > max) {
                max = average;
                fastest = col;
            } else if (average < min) {
                min = average;
                slowest = col;
            }
        }
        row++;
    }
    printf("Runner %d was the fastest with an average time of %.2lf.\n", fastest, min);
    printf("Runner %d was the slowest with an average time of %.2lf.\n", slowest, max);
    return;
}

Exercise — individual:
Strings Equal

Download strings_equal.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity strings_equal

You've probably noticed that you can't use the comparison operator, ==, to compare strings. So, how do we compare two strings? For this activity, you'll be writing a function to do exactly that:

You may not use string.h in this exercise.

It takes two strings, string1 and string2, and, if they are element-for-element the same, it returns 1, and 0 otherwise. You shouldn't ever read beyond the null-terminator of either string.

Download strings_equal.c here, or copy it to your CSE account using the following command:

cp -n /import/adams/A/cs1511/public_html/26T2/activities/strings_equal/strings_equal.c .

Your task is to add code to this function in strings_equal.c:

// Takes two strings, and if they are the same,
// returns 1, or 0 otherwise.
int strings_equal(char *string1, char *string2) {
    // Your code goes here!
    // Don't forget to return your result.
    return 0;
}

strings_equal.c also contains a simple main function with some simple assert-based tests to help you build your solution:

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

    // Some simple assert-based tests.
    // You probably want to write some more.

    // Assert will terminate program if evaluated as false
    assert(strings_equal("", "") == 1);
    assert(strings_equal(" ", "") == 0);
    assert(strings_equal("", " ") == 0);
    assert(strings_equal(" ", " ") == 1);
    assert(strings_equal("\n", "\n") == 1);
    assert(strings_equal("This is 17 bytes.", "") == 0);
    assert(strings_equal("", "This is 17 bytes.") == 0);
    assert(strings_equal("This is 17 bytes.", "This is 17 bytes.") == 1);
    assert(strings_equal("Here are 18 bytes!", "This is 17 bytes.") == 0);

    printf("All tests passed.  You are awesome!\n");

    return 0;
}

Your strings_equal function will be called directly in marking. The main function is only to let you test your strings_equal function

You can add more assert tests to main to test your strings_equal function.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest strings_equal
Sample solution for strings_equal.c
// String Equality
// A sample solution.

#include <stdio.h>
#include <assert.h>

int strings_equal(char *string1, char *string2);

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

    // Some simple assert-based tests.
    // You probably want to write some more.
    assert(strings_equal("", "") == 1);
    assert(strings_equal(" ", "") == 0);
    assert(strings_equal("", " ") == 0);
    assert(strings_equal(" ", " ") == 1);
    assert(strings_equal("\n", "\n") == 1);
    assert(strings_equal("This is 17 bytes.", "") == 0);
    assert(strings_equal("", "This is 17 bytes.") == 0);
    assert(strings_equal("This is 17 bytes.", "This is 17 bytes.") == 1);
    assert(strings_equal("Here are 18 bytes!", "This is 17 bytes.") == 0);

    printf("All tests passed.  You are awesome!\n");

    return 0;
}


// Takes two strings, and if they are the same,
// returns 1, or 0 otherwise.
int strings_equal(char *string1, char *string2) {
    int i = 0;

    // note if string2[i] == '\0', loops terminates too
    while (string1[i] == string2[i] && string1[i] != '\0') {
        i = i + 1;
    }

    // could be just return string1[i] == string2[i];

    if (string1[i] == string2[i]) {
        return 1;
    } else {
        return 0;
    }
}

Exercise — individual:
String to Upper

Download string_to_upper.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_to_upper

For this activity, you'll be writing the function string_to_upper. It takes a string and converts it to upper case

string_to_upper.c also contains a simple main function to help you test your solution.

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

    char str[] = "Seventeen...  SEVENTEEN, I SAY!";
    string_to_upper(str);
    printf("%s\n", str);
    return 0;
}

Your string_to_upper function will be called directly in marking. The main function is only to let you test your string_to_upper function

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

    char str[] = "Seventeen...  SEVENTEEN, I SAY!";
    string_to_upper(str);
    printf("%s\n", str);
    return 0;
}

Your string_to_upper function will be called directly in marking. The main function is only to let you test your string_to_upper function

Here is how string_to_upper.c should behave after you add the correct code to the function string_to_upper:

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_to_upper
Sample solution for string_to_upper.c
// Convert a string to uppercase
// string_to_upper.c
//
// This program was written by YOUR-NAME-HERE (zXXXXXXX)
// on INSERT-DATE-HERE

#include <stdio.h>

void string_to_upper(char *buffer);
int uppercase(int c);

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

    // NOTE: THIS WON'T WORK:
    // char *str = "Hello!"
    // string_to_upper(str)
    //
    // str only points to a string literal, which it is not legal to change.
    // If you attempt to modify it on Linux you will get a runtime error.
    // Instead, you need to create an array to store the string in, e.g.:
    //
    // char str[] = "Hello!"
    // string_to_upper(str)

    char str[] = "Seventeen...  SEVENTEEN, I SAY!";
    string_to_upper(str);
    printf("%s\n", str);

    return 0;
}

// Convert the characters in `buffer` to upper case
void string_to_upper(char *buffer) {
    int i = 0;
    while (buffer[i] != '\0') {
        buffer[i] = uppercase(buffer[i]);
        i = i + 1;
    }
}

int uppercase(int c) {
    if (c >= 'a' && c <= 'z') {
        return c - 'a' + 'A';
    } else {
        return c;
    }
}

Exercise — individual:
String to Lower

Download string_to_lower.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_to_lower

For this activity, you'll be writing the function string_to_lower. It takes a string and converts it to lower case.

string_to_lower.c also contains a simple main function to help you test your solution.

int main(void) {

    char str[MAX_LEN] = "Hi, mY nAmE iS sPonGEbOb sQuArePanTS.";
    string_to_lower(str);
    printf("%s\n", str);

    return 0;
}

Your string_to_lower function will be called directly in marking. The main function is only to let you test your string_to_lower function.

Here is how string_to_lower.c should behave after you add the correct code to the function string_to_lower:

dcc string_to_lower.c -o string_to_lower
./string_to_lower
hi, my name is spongebob squarepants.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_to_lower
Sample solution for string_to_lower.c
// convert a string to lowercase
// a sample solution.

#include <stdio.h>

#define MAX_LEN 1024

void string_to_lower(char *buffer);
int lowercase(int c);

int main(void) {

    // NOTE: THIS WON'T WORK:
    // char *str = "Hello!"
    // string_to_lower(str)
    //
    // str only points to a string literal, which it is not legal to change.
    // If you attempt to modify it on Linux you will get a runtime error.
    // Instead, you need to create an array to store the string in, e.g.:
    //
    // char str[] = "Hello!"
    // string_to_lower(str)

    char str[MAX_LEN] = "Seventeen...  SEVENTEEN, I SAY!";
    string_to_lower(str);
    printf("%s\n", str);

    return 0;
}

// Convert the characters in `buffer` to lower case
void string_to_lower(char *buffer) {
    int i = 0;
    while (buffer[i] != '\0') {
        buffer[i] = lowercase(buffer[i]);
        i = i + 1;
    }
}

int lowercase(int c) {
    if (c >= 'A' && c <= 'Z') {
        return c - 'A' + 'a';
    } else {
        return c;
    }
}

Exercise — individual:
String Manipulation

Download string_manipulation.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_manipulation

Your task is to add code to this function in string_manipulation.c:

    // TODO: move code sections into functions
}

Implement the different functions listed in the string_manipulation.c file.

No autotests are provided for this question.

Examples

dcc struct_tutorial.c -o struct_tutorial
./struct_tutorial
Hello, World!
Goodbye
Goodbye is before World.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_manipulation
Sample solution for string_manipulation.c
// Strings
// Some string practice:
//      - declaring & initialising
//      - printing
//      - scanning a string
//      - count vowels and consonants
//      - check string equality (check if 2 strings are the same)
//      - reverse a string
//      - string concatenation (adding a string to the end of another)
//      - title case conversion (every first letter in a word becomes a capital)
//      - count words (words are a series of characters surrounded by spaces)

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

#define MAX_STR_LEN 1024

void count_vowels_consonants(char *string);
int is_vowel(char letter);
void reverse_string(char *string);
void string_concatenation(char *string1, char *string2);
void title_case_conversion(char *string);
void count_words(char *string);

int main(void) {
    // MOST IMPORTANT/USEFUL:

    // Declare & Initialise a String
    char str1[MAX_STR_LEN] = "Hello, World!\n";

    // Print a string
    printf("%s", str1);

    // Scan a string from stdin
    fgets(str1, MAX_STR_LEN, stdin);
    str1[strcspn(str1, "\n")] = '\0';

    // Check if a string is the same as another
    char str2[] = "World";
    if (strcmp(str1, str2) == 0) {
        printf("%s and %s are the same.\n", str1, str2);
    } else if (strcmp(str1, str2) < 0) {
        printf("%s is before %s.\n", str1, str2);
    } else {
        printf("%s is before %s.\n", str2, str1);
    }

    // Copy a string into another
    strcpy(str2, str1);
    printf("str2 is now %s.\n", str2);

    // LESS IMPORTANT/EXTRA PROBLEM SOLVING

    // Count Vowels and Consonants
    count_vowels_consonants(str1);

    // Reverse a String
    reverse_string(str1);

    // String Concatenation
    string_concatenation(str1, "END");
    // Can just use the function strcat
    // strncat(str1, "END");
    printf("%s\n", str1);

    // Title Case Conversion
    title_case_conversion(str1);
    printf("%s\n", str1);

    // Count Words
    count_words(str1);
}

void count_vowels_consonants(char *string) {
    int vowel_count = 0;
    int consonant_count = 0;
    for (int i = 0; string[i] != '\0'; i++) {
        if (is_vowel(string[i])) {
            vowel_count++;
        } else if (isalpha(string[i])) {
            consonant_count++;
        }
    }
    printf("There are %d vowels and %d consonants.\n", vowel_count, consonant_count);
}

int is_vowel(char letter) {
    letter = tolower(letter);
    if (letter == 'a') {
        return 1;
    } else if (letter == 'e') {
        return 1;
    } else if (letter == 'i') {
        return 1;
    } else if (letter == 'o') {
        return 1;
    } else if (letter == 'u') {
        return 1;
    }
    return 0;
}

void reverse_string(char *string) {
    char reversed[MAX_STR_LEN];
    for (int i = 0, j = strlen(string) - 1; j >= 0; i++, j--) {
        reversed[i] = string[j];
    }
    reversed[strlen(string)] = '\0';
    printf("%s\n", reversed);
}

void string_concatenation(char *string1, char *string2) {
    int i = 0;
    while (string1[i] != '\0') {
        i++;
    }
    int j = 0;
    while (j < strlen(string2)) {
        string1[i] = string2[j];
        i++;
        j++;
    }
    string1[i] = '\0';
}

void title_case_conversion(char *string) {
    int prev = 1;
    for (int i = 0; string[i] != '\0'; i++) {
        if (prev) {
            string[i] = toupper(string[i]);
        }
        if (string[i] == ' ') {
            prev = 1;
        } else {
            prev = 0;
        }
    }
}

void count_words(char *string) {
    int prev = 1;
    int word_count = 0;
    for (int i = 0; string[i] != '\0'; i++) {
        if (prev && isalpha(string[i])) {
            word_count++;
        }
        if (string[i] == ' ') {
            prev = 1;
        } else {
            prev = 0;
        }
    }
    printf("There are %d words in this sentence.\n", word_count);
}

Exercise — individual:
String Length

Download string_length.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_length

For this activity, you'll be writing the function string_length. It takes a string, and finds its length, excluding the null-terminator.

string_length.c also contains a simple main function with some simple assert-based tests to help you build your solution:

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

    // Some simple assert-based tests.
    // You probably want to write some more.

    // Assert will terminate program if evaluated as false
    assert(string_length("") == 0);
    assert(string_length("!") == 1);
    assert(string_length("Hello, world!") == 13);
    assert(string_length("17... seventeen.\n") == 17);

    printf("All tests passed.  You are awesome!\n");

    return 0;
}

Your string_length function will be called directly in marking. The main function is only to let you test your string_length function

You can add more assert tests to main to test your string_length function.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_length
Sample solution for string_length.c
// How long is a (piece of) string?
// A sample solution.

#include <assert.h>
#include <stdio.h>

int string_length(char *string);

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

    // Some simple assert-based tests.
    // You probably want to write some more.
    assert(string_length("") == 0);
    assert(string_length("!") == 1);
    assert(string_length("Hello, world!") == 13);
    assert(string_length("17... seventeen.\n") == 17);

    printf("All tests passed.  You are awesome!\n");

    return 0;
}

// Takes a string and finds its length, excluding the null-terminator.
int string_length(char *string) {
    int i = 0;
    while (string[i] != '\0') {
        i = i + 1;
    }
    return i;
}

Exercise — individual:
String Copy

Download string_copy.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_copy

For this activity, you'll be writing the function string_copy

It takes a string in the source buffer, and copies it to the destination buffer, which is dest_size elements in size. If there are more characters in source than there is array space in destination, you should stop after you have filled the array. You should always make sure that your function null-terminates the destination array.

string_copy.c also contains a simple main function with to help you test your string_copy function

int main(int argc, char *argv[]) {
    // Declare a buffer.  In this case, we're declaring and using a
    // 64-byte buffer, but this could be any length you like, and in
    // our tests you will be required to handle arrays of any length.
    char buffer[BUFFER_LENGTH] = {0};

    // Copy a string into the buffer ...
    string_copy(buffer, "Seventeen bytes.\n", BUFFER_LENGTH);

    // ... and print it out.  The `%s` format code prints a string.
    printf("<%s>\n", buffer);

    return 0;
}

Your string_copy function will be called directly in marking. The main function is only to let you test your string_copy function

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_copy
Sample solution for string_copy.c
// Copy a String
// A sample solution.

#include <stdio.h>

#define BUFFER_LENGTH 64

void string_copy(char *destination, char *source, int destination_size);

int main(int argc, char *argv[]) {
    // Declare a buffer.  In this case, we're declaring and using a
    // 64-byte buffer, but this could be any length you like, and in
    // our tests you will be required to handle arrays of any length.
    char buffer[BUFFER_LENGTH] = {0};

    // Copy a string into the buffer ...
    string_copy(buffer, "Seventeen bytes.\n", BUFFER_LENGTH);

    // ... and print it out.  The `%s` format code prints a string.
    printf("<%s>\n", buffer);

    return 0;
}

// Takes a string in `source`, and copies it to `destination`, which
// is `destSize` elements in size; only copies up to `destSize` bytes.
// Ensures the `destination` array is null-terminated.
void string_copy(char *destination, char *source, int destination_size) {
    int i = 0;

    // stop before last array element so we can add '\0'
    while (i < destination_size - 1 && source[i] != '\0') {
        destination[i] = source[i];
        i = i + 1;
    }
    destination[i] = '\0';
}

Exercise — individual:
String Reverse

Download string_reverse.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity string_reverse

For this activity, you'll be writing the function string_reverse. It takes a string and reverses it in place.

string_reverse.c also contains a simple main function to help you test your function string_reverse

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

    char str[] = ".'neetneves' :egassem terces A";
    string_reverse(str);
    printf("%s\n", str);
    return 0;
}

Your string_reverse function will be called directly in marking. The main function is only to let you test your string_reverse function

Here is how string_reverse.c should behave after you add the correct code to the function string_reverse:

dcc string_reverse.c -o string_reverse
./string_reverse
A secret message: 'seventeen'.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_reverse
Sample solution for string_reverse.c
// gnirts a esreveR (Reverse a string)
// A sample solution.

#include <stdio.h>

void string_reverse(char *buffer);
int string_length(char *string);

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

    // NOTE: THIS WON'T WORK:
    // char *str = "Hello!"
    // string_reverse(str)
    //
    // str only points to a string literal, which it is not legal to change.
    // If you attempt to modify it on Linux you will get a runtime error.
    // Instead, you need to create an array to store the string in, e.g.:
    //
    // char str[] = "Hello!"
    // string_reverse(str)

    char str[] = ".'neetneves' :egassem terces A";
    string_reverse(str);
    printf("%s\n", str);
    return 0;
}

// Takes a string in `buffer`, and reverses it in-place.
void string_reverse(char *buffer) {
    int length = string_length(buffer);
    int i = 0;
    while (i < length/2) {

        // swap array elements
        char tmp = buffer[i];
        buffer[i] = buffer[length - i - 1];
        buffer[length - i - 1] = tmp;

        i = i + 1;
    }
}

// Takes a string and finds its length, excluding the null-terminator.
int string_length(char *string) {
    int i = 0;
    while (string[i] != '\0') {
        i = i + 1;
    }
    return i;
}

Exercise — individual:
String Search

Your job is to write a program called string_search.c which lets us count the number of times we see any our of "search terms" in a list of words.

The search terms will be provided to our program via command line arguments. For example:

./string_search hello there

would run the program with 2 search terms - hello and there.

TASK 1: Edit the arguments to your main function so that it can take in command line arguments (aka, the search terms). Try printing out the values of argc and argv and changing the values you type after ./string_search to see what they contain!

TASK 2: Scan in words from standard input until Ctrl-D is pressed.

TASK 3: Count the number of times the search terms appear in the input.

Examples

dcc string_search.c -o string_search
./string_search same
Enter list of words:
same
sand
same
send
shade
same
shadow

There were 3 occurrence(s) in the input.
./string_search many search terms
Enter list of words:
terms
many
same
many
shade
search
research

There were 4 occurrence(s) in the input.

Assumptions/Restrictions/Clarifications

  • You can assume that each word will be no longer than 128 characters long
  • You can assume that there will only be 1 word per line
  • You can assume that the search terms will never have repeats in them

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest string_search
Sample solution for string_search.c
// Simple Regex
// Searches for words in a file that match any of the given substrings.
// Activity written by Paula
// Finished by [Student]

#include <stdio.h>
#include <string.h>

#define MAX_WORD_LEN 128
#define MAX_WORDS 10000


int read_words(char words[MAX_WORDS][MAX_WORD_LEN]);
int word_matches(char *word, char *argv[], int n_match);


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

    int n_match = argc - 1;

    printf("Enter list of words:\n");
    char words[MAX_WORDS][MAX_WORD_LEN];
    int n_words = read_words(words);


    int count = 0;
    for (int i = 0; i < n_words; i++) {
        if (word_matches(words[i], &argv[1], n_match)) {
            count++;
        }
    }
    printf("There were %d occurances in the input.\n", count);

    return 0;
}

int word_matches(char *word, char *argv[], int n_match) {
    for (int i = 0; i < n_match; i++) {
        if (strcmp(word, argv[i]) == 0) {
            return 1;
        }
    }
    return 0;
}


////////////////////////////////////////////
// DO NOT CHANGE THE FUNCTIONS BELOW HERE //
////////////////////////////////////////////

// removes a trailing newline from a string if it exists.
void remove_newline(char *str) {
    int len = strlen(str);
    if (str[len - 1] == '\n') {
        str[len - 1] = '\0';
    }
}

// reads words from stdin until ctrl-d (assuming 1 word per line)
// stores the words in words[][] without trailing newlines
// returns the number of words found.
int read_words(char words[MAX_WORDS][MAX_WORD_LEN]) {
    int i = 0;
    while (fgets(words[i], MAX_WORD_LEN, stdin) != NULL) {
        remove_newline(words[i]);
        i++;
    }
    return i;
}
Alternative solution for string_search.c
// Simple Regex
// Searches for words in standard input that match any of the given search
// strings. Written by [Student]

#include <stdio.h>
#include <string.h>

#define MAX_WORD_LEN 128

void remove_newline(char *str);

int main(int argc, char *argv[]) {
    printf("Enter list of words:\n");

    int total = 0;

    char buf[MAX_WORD_LEN];
    while (fgets(buf, MAX_WORD_LEN, stdin) != NULL) {
        remove_newline(buf);
        for (int i = 1; i < argc; i++) {
            if (strcmp(buf, argv[i]) == 0) {
                total += 1;
            }
        }
    }
    printf("There were %d occurrence(s) in the input.\n", total);

    return 0;
}

void remove_newline(char *str) {
    int len = strlen(str) - 1;
    if (str[len] == '\n') {
        str[len] = '\0';
    }
}

Exercise — individual:
List count even

Download list_count_even.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_count_even

Your task is to add code to this function in list_count_even.c:

// return the number of even values in a linked list
int count_even(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_count_even.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

count_even is given one argument, head, which is the pointer to the first node in a linked list.

Add code to count_even so that its returns the number of even values in the linked list.

For example if the linked list contains these 8 elements:

16, 7, 8, 12, 13, 19, 21, 12

count_even should return 4, because these 4 elements are even:

16, 8, 12, 12

Testing

list_count_even.c also contains a main function which allows you to test your count_even function.

This main function:

  • converts the command-line arguments to a linked list.
  • assigns a pointer to the first node in the linked list to head.
  • calls count_even(head).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your count_even function will be called directly in marking. The main function is only to let you test your count_even function

Examples

Here is how you use main function to test count_even:

dcc list_count_even.c -o list_count_even
./list_count_even 16 7 8 12 13 19 21 12
4
./list_count_even 2 4 6 2 4 6
6
./list_count_even 3 5 7 11 13 15 17 19 23 29
0
./list_count_even 2 4 8 16 32 64 128 256
8
./list_count_even
0

Assumptions/Restrictions/Clarifications

  • An even number is divisible by 2.

  • count_even should return a single integer.

  • count_even should not change the linked list it is given.

  • Your function should not change the next or data fields of list nodes.

  • count_even should not use arrays.

  • count_even should not call malloc.

  • count_even should not call scanf (or getchar or fgets).

  • You can assume the linked list only contains positive integers.

  • count_even should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_count_even
Sample solution for list_count_even.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int count_even(struct node *head);
struct node *strings_to_list(int len, char *strings[]);

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = count_even(head);
    printf("%d\n", result);

    return 0;
}

// return the number of even values in a linked list
int count_even(struct node *head) {
    int num_even = 0;
    struct node *p = head;
    while (p != NULL) {
        if (p->data % 2 == 0) {
            num_even = num_even + 1;
        }
        p = p->next;
    }
    return num_even;
}

// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}
Alternative solution for list_count_even.c
#include <stdio.h>

struct node {
    struct node *next;
    int          data;
};

// return the number of even values in a linked list
// cute, recursive solution
int count_even(struct node *head) {
    if (head == NULL) {
        return 0;
    } else {
        return (head->data % 2) + count_even(head->next);
    }
}

Exercise — individual:
List count favourite

Download list_count_favourite.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_count_favourite

Your task is to add code to this function in list_count_favourite.c:

// Return the number of elements divisible by 17 in the linked list
int count_favourite(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

count_favourite is given one argument, head, which is the pointer to the first node in a linked list.

Add code to count_favourite so that its returns the number of elements divisible by 17 in the list.

For example if the linked list contains these 8 elements:

51, 7, 8, 9, 34, 19, 34, 42

count_favourite should return 3 because 51, 34 and 34 are divisible by 17.

Testing

list_count_favourite.c also contains a main function which allows you to test your count_favourite function.

This main function:

  • converts the command-line arguments to a linked list
  • assigns a pointer to the first node in the linked list to head
  • calls list_count_favourite(head)
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your list_count_favourite function will be called directly in marking. The main function is only to let you test your list_count_favourite function

Examples

Here is how you use main function allows you to test list_count_favourite:

dcc list_count_favourite.c -o list_count_favourite
./list_count_favourite 51 7 8 9 34 19 34 42
3
./list_count_favourite 2 4 6 5 8 9
0
./list_count_favourite 17 34 51 68 85 102 119 136 153
9
./list_clist_count_favouriteount_favourite
0

Assumptions/Restrictions/Clarifications

  • count_favourite should return a single integer.
  • count_favourite should not change the linked list it is given.
  • Your function should not change the next or data fields of list nodes.
  • count_favourite should not use arrays.
  • count_favourite should not call malloc.
  • count_favourite should not call scanf (or getchar or fgets).
  • count_favourite should not print anything. It should not call printf.
  • Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_count_favourite
Sample solution for list_count_favourite.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int count_favourite(struct node *head);
struct node *strings_to_list(int len, char *strings[]);

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = count_favourite(head);
    printf("%d\n", result);

    return 0;
}

// Return the number of elements divisible by 17 in the linked list
int count_favourite(struct node *head) {
    int count = 0;
    struct node *n = head;
    while (n != NULL) {
        if (n->data % 17 == 0) {
            count = count + 1;
        }
        n = n->next;
    }
    return count;
}


// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}
Alternative solution for list_count_favourite.c
#include <stdio.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

// Return the number of elements divisible by 17 in the linked list
int count_favourite(struct node *head) {
    if (head == NULL) {
        return 0;
    }
    return (head->data % 17 == 0) + count_favourite(head->next);
}

Exercise — individual:
List count matches

Download list_count_matches.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_count_matches

Your task is to add code to this function in list_count_matches.c:

// Return the number of matches in the two lists, i.e. the number of
// values which occur at the same position in both linked lists.
int count_matches(struct node *head1, struct node *head2) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_count_matches.c uses the following familiar data type:

struct node {
    int          data;
    struct node *next;
};

Your task is to add code to this function count_matches.

count_matches is given two arguments, head1 and head2, which are pointers to the first node of linked lists.

Add code to count_matches so that returns a count of how many places the two lists have the same value in the same position.

For example, if the two lists contain these values:

1, 4, 1, 5, 9, 2, 1, 8
1, 1, 8, 2, 9, 5

count_matches should return 2 because both lists have the same value (1) at position 0 and the same value (9) at position 4.

Note: the lists may be any length and the two lengths may be unequal.

Testing

list_count_matches.c also contains a main function which allows you to test your count_matches function.

This main function:

  • uses a command line argument of "-" to separate the values for two linked lists.
  • converts the command-line arguments before the "-" to a linked list.
  • assigns a pointer to the first node in the linked list to head1.
  • converts the command-line arguments after the "-" to a linked list.
  • assigns a pointer to the first node in the linked list tohead2.
  • calls count_matches(head1, head2).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your count_matches function will be called directly in marking. The main function is only to let you test your count_matches function

Examples

Here is how the main function allows you to test count_matches:

dcc -o list_count_matches list_count_matches.c
./list_count_matches 3 1 4 - 2 7 1 8 3
0
./list_count_matches 1 2 3 4 - 2 1 3 8
1
./list_count_matches 5 5 6 5 - 6 5 5 5
2
./list_count_matches 3 5 7 - 3 5 19 7 23 29
2
./list_count_matches 1 2 3 4 5 6 - 3 2 1
1
./list_count_matches - 1 2 3 4
0
./list_count_matches 4 3 2 1 -
0
./list_count_matches -
0

Assumptions/Restrictions/Clarifications

  • count_matches should return a single integer.

  • The linked lists may be of unequal lengths.

  • The linked lists may be any length.

  • Either or both linked lists may be empty (contain no elements).

  • count_matches should not change the linked lists it is given.

  • Your function should not change the next or data fields of list nodes.

  • count_matches should not use arrays.

  • count_matches should not call malloc.

  • count_matches should not call scanf (or getchar or fgets).

  • count_matches should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_count_matches
Sample solution for list_count_matches.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};


// Return the number of matches in the two lists, i.e. the number of
// values which occur at the same position in both linked lists.
int count_matches(struct node *head1, struct node *head2) {

    int count = 0;
    while (head1 != NULL&& head2 != NULL) {
        if (head1->data == head2->data) {
            count++;
        }

        head1 = head1->next;
        head2 = head2->next;

    }

    // PUT YOUR CODE HERE (change the next line!)
    return count;

}

// You should not change any of the code below.

int count_matches(struct node *head1, struct node *head2);
struct node *strings_to_list(int len, char *strings[]);

// DO NOT CHANGE THIS MAIN FUNCTION
int main(int argc, char *argv[]) {
    // create two linked lists from command line arguments
    int dash_arg = argc - 1;
    while (dash_arg > 0 && strcmp(argv[dash_arg], "-") != 0) {
        dash_arg = dash_arg - 1;
    }
    struct node *head1 = strings_to_list(dash_arg - 1, &argv[1]);
    struct node *head2 = strings_to_list(argc - dash_arg - 1, &argv[dash_arg + 1]);

    int result = count_matches(head1, head2);
    printf("%d\n", result);

    return 0;
}

// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}

Exercise — individual:
List sum

Download list_sum.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_sum

Your task is to add code to this function in list_sum.c:

// Return the sum of the elements in the linked list pointed by head
int sum(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

sum is given one argument, head, which is the pointer to the first node in a linked list.

Add code to sum so that its returns the sum of the list.

For example if the linked list contains these 8 elements:

1, 7, 8, 9, 13, 19, 21, 42

sum should return 120 because 1 + 7 + 8 + 9 + 13 + 19 + 21 + 42 = 120

Testing

list_sum.c also contains a main function which allows you to test your sum function.

This main function:

  • converts the command-line arguments to a linked list
  • assigns a pointer to the first node in the linked list to head
  • calls list_sum(head)
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your list_sum function will be called directly in marking. The main function is only to let you test your list_sum function

Here is how you use main function allows you to test list_sum:

dcc list_sum.c -o list_sum
./list_sum 1 2 4 8 16 32 64 128 256
511
./list_sum 2 4 6 5 8 9
34
./list_sum 13 15 17 17 18
80
./list_sum 42 4
46
./list_sum
0

Assumptions/Restrictions/Clarifications

  • sum should return a single integer.
  • sum should not change the linked list it is given. Your function should not change the next or data fields of list nodes.
  • sum should not use arrays.
  • sum should not call malloc.
  • sum should not call scanf (or getchar or fgets).
  • sum should not print anything. It should not call printf. Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_sum
Sample solution for list_sum.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int sum(struct node *head);
struct node *strings_to_list(int len, char *strings[]);

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = sum(head);
    printf("%d\n", result);

    return 0;
}

// Return sum of a linked list.
int sum(struct node *head) {
    int total = 0;
    struct node *n = head;
    while (n != NULL) {
        total = total + n->data;
        n = n->next;
    }
    return total;
}


// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}
Alternative solution for list_sum.c
#include <stdio.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

// Return sum of a linked list.
int sum(struct node *head) {
    if (head == NULL) {
        return 0;
    }
    return head->data + sum(head->next);
}

Exercise — individual:
List Count Consecutive

Download list_count_consecutive.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_count_consecutive

Your task is to add code to this function in list_count_consecutive.c:

// TODO: FIX THIS FUNCTION
// Counts the number of consecutive items in a list
// e.g. [2, 3, 2, 5, 4] has 3 consecutive occurances
int count_consecutive(struct node *head) {

    int n_consec = 0;

    struct node *curr = head;
    struct node *prev = NULL;
    while (curr != NULL) {
        // checking to see if previous and current and consecutive.
        if (prev - curr == 1 || prev - curr == -1) {
            n_consec++;
        }

        curr = curr->next;
        prev = prev->next;
    }
    return n_consec;
}

Your job is to fix the function count_consecutive(). Currenty it nearly works, but has some bugs in it

The function should take in a head of a list, and count the number of time two adjacent values in the list are consecutive. In other words, it counts the number of times that a pair of values that are next to each other are 1 value apart

It should return the number of consecutive occurances in the list

When doing this exercise, try to identify what bugs the program had (and how to fix it) instead of just rewriting the program

dcc list_consecutive.c -o list_consecutive
./list_consecutive
How many numbers in initial list?: 
3
1 2 3
There is/are 2 consecutive occurances.
./list_consecutive
How many numbers in initial list?: 
5
1 2 4 5 4
There is/are 3 consecutive occurances.
./list_consecutive
How many numbers in initial list?: 
1
6
There is/are 0 consecutive occurances.
./list_consecutive
How many numbers in initial list?: 
0
There is/are 0 consecutive occurances.

Assumptions/Restrictions/Clarifications

  • print_consecutive should not use arrays.
  • print_consecutive should not call scanf (or getchar or fgets).
  • print_consecutive should not print anything. It should not call printf.
  • Do not change the supplied main function or any other provided functions. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_count_consecutive
Sample solution for list_count_consecutive.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int count_consecutive(struct node *head);
struct node *array_to_list(int len, int array[]);
void print_list(struct node *head);

// DO NOT CHANGE THIS MAIN FUNCTION
#define MAX_INIT_LIST_LEN 100
int main() {
    // Need to read in a number of ints into an array
    printf("How many numbers in initial list?: ");
    int list_size = 0;
    scanf("%d", &list_size);
    int initial_elems[MAX_INIT_LIST_LEN] = {0};
    int n_read = 0;
    while (n_read < list_size && scanf("%d", &initial_elems[n_read])) {
        n_read++;
    }

    // create linked list from first set of inputs
    struct node *head = NULL;
    if (n_read > 0) {
        // list has elements
        head = array_to_list(n_read, initial_elems);
    }

    int n_consec = count_consecutive(head);
    printf("There is/are %d consecutive occurances.\n", n_consec);

    return 0;
}

// TODO: FIX THIS FUNCTION
// Counts the number of consecutive items in a list
// e.g. [2, 3, 2, 5, 4] has 3 consecutive occurances
int count_consecutive(struct node *head) {

    int n_consec = 0;

    if (head == NULL || head->next == NULL) {
        return 0;
    }

    struct node *curr = head->next;
    struct node *prev = head;
    while (curr != NULL) {
        if (prev->data - curr->data == 1 ||
            prev->data - curr->data == -1) {

            n_consec++;
        }

        prev = curr;
        curr = curr->next;
    }
    return n_consec;
}

// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *array_to_list(int len, int array[]) {
    struct node *head = NULL;
    int i = len - 1;
    while (i >= 0) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = array[i];
        head = n;
        i -= 1;
    }
    return head;
}

// DO NOT CHANGE THIS FUNCTION
// print linked list
void print_list(struct node *head) {
    printf("[");
    struct node *n = head;
    while (n != NULL) {
        // If you're getting an error here,
        // you have returned an invalid list
        printf("%d", n->data);
        if (n->next != NULL) {
            printf(", ");
        }
        n = n->next;
    }
    printf("]\n");
}

Exercise — individual:
List count last

Download list_count_last.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_count_last

Your task is to add code to this function in list_count_last.c:

// return the number of values in a linked list equal to the
// last value in that linked list.
int count_last(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_count_last.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

count_last is given one argument, head, which is the pointer to the first node in a linked list. You are guaranteed the list will not be empty.

Add code to count_last so that its returns the number of values which are the same as the last value in the list.

For example if the linked list contains these 8 values:

16, 12, 8, 12, 13, 19, 21, 12

count_last should return 3, because 12 is the last value, and 12 occurs 3 times in the list (including the last number).

Testing

list_count_last.c also contains a main function which allows you to test your count_last function.

This main function:

  • converts the command-line arguments to a linked list.
  • assigns a pointer to the first node in the linked list to head.
  • calls count_last(head).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your count_last function will be called directly in marking. The main function is only to let you test your count_last function

Examples

Here is how you use main function allows you to test count_last:

dcc list_count_last.c -o list_count_last
./list_count_last 16 12 8 12 13 19 21 12
3
./list_count_last 2 4 6 2 4 6
2
./list_count_last 3 5 7 11 13 15 17 19 23 29
1
./list_count_last 2 2 2 3 2
4

Assumptions/Restrictions/Clarifications.

  • count_last will never receive a linked list with no nodes. That is, the head will never be NULL
  • count_last should return a single integer.
  • count_last should not change the linked list it is given.
  • Your function should not change the next or data fields of list nodes.
  • count_last should not use arrays.
  • count_last should not call malloc.
  • count_last should not call scanf (or getchar or fgets).
  • count_last should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_count_last
Sample solution for list_count_last.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int count_last(struct node *head);
struct node *strings_to_list(int len, char *strings[]);

// DO NOT CHANGE THIS MAIN FUNCTION

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = count_last(head);
    printf("%d\n", result);

    return 0;
}


// return the number of values in a linked list equal to the
// last value in that linked list.
int count_last(struct node *head) {
    int last_val;
    struct node *iter = head;
    while (iter) {
        last_val = iter->data;
        iter = iter->next;
    }

    int count = 0;
    iter = head;
    while (iter) {
        if (iter->data == last_val) count++;
        iter = iter->next;
    }

    return count;

}


// DO NOT CHANGE THIS FUNCTION

// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}

Exercise — individual:
List intersection size

Download list_intersection_size.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_intersection_size

Your task is to add code to this function in list_intersection_size.c:

// return the number of values which occur in both linked lists
// no value is repeated in either list
int intersection_size(struct node *head1, struct node *head2) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_intersection_size.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

intersection_size is given two arguments, head1 and head2, which are pointers to the first node of linked lists.

Add code to intersection_size so that its returns the number of values that occur in both linked list.

Assume no value occurs more than once in either linked list.

For example, if the two lists contain these values:

3, 1, 4
2, 7, 1, 8, 3

intersection_size should return 2, because these 2 elements occur in both lists:

1, 3

Testing

list_intersection_size.c also contains a main function which allows you to test your intersection_size function.

This main function:

  • uses a command line argument of "-" to separate the values for two linked lists.
  • converts the command-line arguments before the "-" to a linked list.
  • assigns a pointer to the first node in the linked list to head1.
  • converts the command-line arguments after the "-" to a linked list.
  • assigns a pointer to the first node in the linked list to head2.
  • calls intersection_size(head1, head2).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your intersection_size function will be called directly in marking. The main function is only to let you test your intersection_size function

Here is how the main function allows you to test intersection_size:

dcc list_intersection_size.c -o list_intersection_size
./list_intersection_size 3 1 4 - 2 7 1 8 3
2
./list_intersection_size 16 7 8 12 - 13 19 21 12
1
./list_intersection_size 2 4 6 - 2 4 6
3
./list_intersection_size 3 5 7 11 13 - 15 17 19 23 29
0
./list_intersection_size 1 2 3 4 - 3 2 1
3
./list_intersection_size - 1 2 3 4
0
./list_intersection_size 4 3 2 1 -
0
./list_intersection_size -
0

Assumptions/Restrictions/Clarifications.

  • intersection_size should return a single integer.
  • No value will occur more than once in either linked list.
  • intersection_size should not change the linked lists it is given.
  • Your function should not change the next or data fields of list nodes.
  • intersection_size should not use arrays.
  • intersection_size should not call malloc.
  • intersection_size should not call scanf (or getchar or fgets).
  • intersection_size should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_intersection_size
Sample solution for list_intersection_size.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int intersection_size(struct node *head1, struct node *head2);
int member(int i, struct node *head);
struct node *strings_to_list(int len, char *strings[]);

int main(int argc, char *argv[]) {
    // create two linked lists from command line arguments
    int dash_arg = argc - 1;
    while (dash_arg > 0 && strcmp(argv[dash_arg], "-") != 0) {
        dash_arg = dash_arg - 1;
    }
    struct node *head1 = strings_to_list(dash_arg - 1, &argv[1]);
    struct node *head2 = strings_to_list(argc - dash_arg - 1, &argv[dash_arg + 1]);

    int result = intersection_size(head1, head2);
    printf("%d\n", result);

    return 0;
}

// return the number of values which occur in both linked lists
// no value is repeated in either list
int intersection_size(struct node *head1, struct node *head2) {
    int num_both = 0;
    struct node *p = head1;
    while (p != NULL) {
        if (member(p->data, head2)) {
            num_both = num_both + 1;
        }
        p = p->next;
    }
    return num_both;
}

// return 1 if i occurs in list, 0 otherwise
int member(int i, struct node *head) {
    struct node *p = head;
    while (p != NULL) {
        if (p->data == i) {
            return 1;
        }
        p = p->next;
    }
    return 0;
}


// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}
Alternative solution for list_intersection_size.c
#include <stdio.h>

struct node {
    struct node *next;
    int          data;
};

// return 1 if i  occurs in list, 0 otherwise
int member(int i, struct node *head) {
    if (head == NULL) {
        return 0;
    } if (head->data == i) {
        return 1;
    } else {
        return member(i, head->next);
    }
}

// return the number of values which occur in both linked lists
// no value is repeated in either list
// cute, recursive solution
int intersection_size(struct node *head1, struct node *head2) {
    if (head1 == NULL) {
        return 0;
    } else {
        return member(head1->data, head2) + intersection_size(head1->next, head2);
    }
}

Exercise — individual:
List is set

Download list_is_set.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_is_set

Your task is to add code to this function in list_is_set.c:

// return 1 if the list is a set
int is_set(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_is_set.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

is_set is given one argument, head, which is the pointer to the first node in a linked list.

Add code to is_set so that its returns 1 if the list is a set, and 0 otherwise.

A 'set' is defined as a list that does not repeat an element.

For example if the linked list contains these 8 elements:

16, 7, 8, 12, 13, 19, 21, 12

is_set should return 0, because the element 12 occurs twice.

For example if the linked list contains these 4 elements:

16, 8, 12, 13

is_set should return 1, because none of the elements occur more than once.

Testing

list_is_set.c also contains a main function which allows you to test your is_set function.

This main function:

  • converts the command-line arguments to a linked list.
  • assigns a pointer to the first node in the linked list to head.
  • calls is_set(head).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your is_set function will be called directly in marking. The main function is only to let you test your is_set function

Examples

Here is how you use main function allows you to test is_set:

dcc list_is_set.c -o list_is_set
./list_is_set 16 7 8 12 13 19 21 12
4
./list_is_set 2 4 6 2 4 6
6
./list_is_set 3 5 7 11 13 15 17 19 23 29
0
./list_is_set 2 4 8 16 32 64 128 256
8
./list_is_set
0

Assumptions/Restrictions/Clarifications.

  • An even number is divisible by 2.
  • is_set should return a single integer.
  • is_set should not change the linked list it is given.
  • Your function should not change the next or data fields of list nodes.
  • is_set should not use arrays.
  • is_set should not call malloc.
  • is_set should not call scanf (or getchar or fgets).
  • You can assume the linked list only contains positive integers.
  • is_set should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_is_set
Sample solution for list_is_set.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int is_set(struct node *head);
struct node *strings_to_list(int len, char *strings[]);

// DO NOT CHANGE THIS MAIN FUNCTION

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = is_set(head);
    printf("%d\n", result);

    return 0;
}


int count(struct node *head, int n) {

    int count = 0;
    
    while (head != NULL) {

        if (head->data == n) {
            count++;
        }

        head = head->next;
    }

    return count;
}

// return 1 if the list is a set
int is_set(struct node *head) {

    struct node * current = head;
    while (current != NULL) {
        if (count(head, current->data) != 1) {
            return 0;
        }

        current = current->next;
    }

    return 1;

}


// DO NOT CHANGE THIS FUNCTION

// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}

Exercise — individual:
List product

Download list_product.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_product

Your task is to add code to this function in list_product.c:

// product should return the sum of the elements in list1 multiplied by 
// the corresponding element in list2
// if one list is longer than the other, the extra list elements are ignored 
int product(struct node *head1, struct node *head2) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note list_product.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

product is given two arguments, head1 and head2, which are pointers to the first node of linked lists.

product should return the sum of the elements in the first list multiplied by the corresponding element in the second list.

If one list is longer than the other, the extra elements should be ignored.

For example, if the two lists contain these values:

list1: 3, 1, 4, 1, 5, 9

list2: 2, 7, 9

product should return 49, because 3 * 2 + 1 * 7 + 4 * 9 = 49 .

For example, if the two lists contain these values:

list1: 2, 7

list2: 4, 42, 4242, 4242, 4242424242

product should return 302, because 2 * 4 + 7 * 42 = 302.

Testing

list_product.c also contains a main function which allows you to test your product function.

This main function:

  • uses a command line argument of "-" to separate the values for two linked lists.
  • converts the command-line arguments before the "-" to a linked list
  • assigns a pointer to the first node in the linked list to head1
  • converts the command-line arguments after the "-" to a linked list
  • assigns a pointer to the first node in the linked list to head2
  • calls product(head1, head2)
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your product function will be called directly in marking. The main function is only to let you test your product function

Examples

Here is how the main function allows you to test product:

dcc list_product.c -o list_product
./list_product 3 1 4 1 5 9 - 2 7 9 8
57
./list_product 16 7 8 12 - 13 19 21 12
653
./list_product 2 4 6 - 42
84
./list_product - 1 2 3 4
0
./list_product 4 3 2 1 -
0
./list_product -
0

Assumptions/Restrictions/Clarifications.

  • The lists may be different lengths.
  • The data fields of the lists may contain any integer.
  • product should return only a single integer.
  • product should not change the linked lists it is given.
  • product should not change the next or data fields of list nodes.
  • product should not use arrays.
  • product should not call malloc.
  • product should not call scanf (or getchar or fgets).
  • product should not print anything. It should not call printf.

Do not change the definition of struct node.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_product
Sample solution for list_product.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

int product(struct node *head1, struct node *head2);
int member(int i, struct node *head);
struct node *strings_to_list(int len, char *strings[]);

int main(int argc, char *argv[]) {
    // create two linked lists from command line arguments
    int dash_arg = argc - 1;
    while (dash_arg > 0 && strcmp(argv[dash_arg], "-") != 0) {
        dash_arg = dash_arg - 1;
    }
    struct node *head1 = strings_to_list(dash_arg - 1, &argv[1]);
    struct node *head2 = strings_to_list(argc - dash_arg - 1, &argv[dash_arg + 1]);

    int result = product(head1, head2);
    printf("%d\n", result);

    return 0;
}


// product should the sum of the elements in list1 multiplied by 
// the corresponding element in list2
// if one list is longer than the other, the extra list elements are ignored 
int product(struct node *head1, struct node *head2) {
	if (!head1 || !head2) {
		return 0;
	} else {
		return (head1->data * head2->data) + product(head1->next, head2->next);
	}
}



// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}

Exercise — individual:
List split

Download list_split.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_split

Your task is to add code to this function in list_split.c:

// Given a list with at least one node, and exactly one 0,
// split the list into a list with everything before the 0,
// and a list with the 0 and everything after.
// Return a malloced split_list struct with each of these lists.
struct split_list *split(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return NULL;

}

Note list_split.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

As well as this new datatype:

struct split_list {
    struct node *before;
    struct node *after;
};

split is given one argument, head. head is the pointer to the first node in a linked list. That linked list will contain at least one node, and exactly one of those nodes will have data 0.

Add code to split so that it splits the given list into two smaller lists, one linked list that contains all the nodes before the 0; and one linked list that contains the 0, and any following nodes.

split should return a malloced split_list struct.

If the zero is the first node, it should return a split_list struct with before = NULL.

If the zero is the last node, it should return a split_list struct with after being a pointer to that zero.

For example if the linked list contains these 8 elements:

16, 7, 8, 19, 0, 19, 2, 12

split should return a pointer to a split_list struct with before pointing to:

16, 7, 8, 19

And after pointing to:

0, 19, 2, 12

Testing

list_split.c also contains a main function which allows you to test your split function.

This main function:

  • converts the command-line arguments to a linked list
  • assigns a pointer to the first node in the linked list to head
  • calls split(head)
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your split function will be called directly in marking. The main function is only to let you test your split function

dcc list_split.c -o list_split
./list_split 0 1 2 3
split([0, 1, 2, 3])
before = []
after = [0, 1, 2, 3]
./list_split 5 3 -1 1 0
split([5, 3, -1, 1, 0])
before = [5, 3, -1, 1]
after = [0]
./list_split 1 2 -3 -4 0 -4 3 -2 1
split([1, 2, -3, -4, 0, -4, 3, -2, 1])
before = [1, 2, -3, -4]
after = [0, -4, 3, -2, 1]

Assumptions/Restrictions/Clarifications

  • split should not free any memory.
  • split should not change the data fields of list nodes.
  • split should not use arrays.
  • split will need to call malloc exactly once.
  • split should not call scanf (or getchar or fgets).
  • split should not print anything. It should not call printf.
  • You do not need to change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_split
Sample solution for list_split.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

struct split_list {
    struct node *before;
    struct node *after;
};

struct split_list *split(struct node *head);
struct node *strings_to_list(int len, char *strings[]);
void print_list(struct node *head);

// DO NOT CHANGE THIS MAIN FUNCTION

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    struct split_list *list_split = split(head);
    printf("before = ");
    print_list(list_split->before);
    printf("after = ");
    print_list(list_split->after);

    return 0;
}


// Given a list with exactly one 0 in it, split
// the list into a list with everything before the 0,
// and a list with the 0 and everything after.
// Return a malloced split_list struct with each of these lists.
struct split_list *split(struct node *head) {
    struct split_list *list_split = malloc(sizeof(struct split_list));
    list_split->before = NULL;
    list_split->after = NULL;
    if (head->data == 0) {
        list_split->after = head;
        return list_split;
    } else {
        list_split->before = head;
        struct node *curr = head;

        while (curr->next != NULL) {
            if (curr->next->data == 0) {
                list_split->after = curr->next;
                curr->next = NULL;
                return list_split;
            }
            curr = curr->next;
        }
    }

    return NULL;

}


// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    int i = len - 1;
    while (i >= 0) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
        i -= 1;
    }   
    return head;
}

// DO NOT CHANGE THIS FUNCTION
// print linked list
void print_list(struct node *head) {
    printf("[");    
    struct node *n = head;
    while (n != NULL) {
        // If you're getting an error here,
        // you have returned an invalid list
        printf("%d", n->data);
        if (n->next != NULL) {
            printf(", ");
        }
        n = n->next;
    }
    printf("]\n");
}

Exercise — individual:
List diagonal

Download lists_diagonal.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity lists_diagonal

Your task is to add code to this function in lists_diagonal.c:

// Treat the linked lists like they're a 2D array
// and return 1 if the first element is repeated
// diagonally through the lists
int has_diagonal(struct list_node *head) {
    return 0;
}

lists_diagonal.c is written using struct node and struct list_node that cannot be changed.

struct node is a normal linked list node while struct list_node is used to make a linked list where each element contains a list of struct nodes.

For this exercise, you will implement the function has_diagonal It should take a pointer to the head of a struct list_node linked list, and check the values of the inner struct node linked list.

Imagine each struct node list as extending out from each struct list_node list (i.e. a 2D linked list). has_diagonal will return 1 if there is a diagonal pattern, and 0 if there isn't.

A diagonal in this exercise means that the first number in the first list is the same as the second number in the second list and the third number in the third list and so on.

For example if the list of lists looks like this:

list_node 0 contains the list {5, 0, 0}
list_node 1 contains the list {0, 5, 0}
list_node 2 contains the list {0, 0, 5}

has_diagonal should return 1 as the number 5 is repeated diagonally down the list of lists:

list_node 0 contains the list {5, 0, 0}
list_node 1 contains the list {0, 5, 0}
list_node 2 contains the list {0, 0, 5}

However, if the list of lists looks like this:

list_node 0 contains the list {5, 0, 0, 0}
list_node 1 contains the list {0, 4, 0, 0}
list_node 2 contains the list {0, 0, 5, 0}
list_node 3 contains the list {0, 0, 0, 5}

has_diagonal should return 0, because the 2nd element of the second list does not equal the value of the first element of the first list:

list_node 0 contains the list {5, 0, 0, 0}
list_node 1 contains the list {0, 4, 0, 0}
list_node 2 contains the list {0, 0, 5, 0}
list_node 3 contains the list {0, 0, 0, 5}

Assumptions/Restrictions/Clarifications

  • struct node and struct list_node cannot be edited. They must be used as they are
  • You may not use arrays in this solution. Arrays are not necessary to complete this task
  • You can assume that you'll never receive an empty list of struct list_nodes
  • You can assume that all lists of struct nodes are also not empty
  • You can assume that there will always be the same number of struct nodes in each list and that will be the same number of struct list_nodes. That is to say, the 2D grid formed by the lists will always be square
  • Your submitted file may contain a main function. It will not be tested or marked

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest lists_diagonal
Sample solution for lists_diagonal.c
#include <stdio.h>
#include <stdlib.h>

// Do not edit these structs. You may use them exactly as
// they are but you cannot make changes to them

// A node in a linked list
struct node {
    int data;
    struct node *next;
};

// a list_node in a linked list. Each list_node
// contains a list of nodes.
struct list_node {
    struct node *my_list;
    struct list_node *next;
};

// Treat the linked lists like they're a 2D array
// and return 1 if the first element is repeated
// diagonally through the lists
int has_diagonal(struct list_node *head) {
    int has = 1;
    int i = 0;
    // assuming that we're never getting an empty first list
    int number = head->my_list->data;
    while (head != NULL) {
        int j = 0;
        struct node *n = head->my_list;
        while (n != NULL) {
            if (j == i && n->data != number) {
                // we're at the diagonal and they're not equal
                has = 0;
            }
            n = n->next;
            j++;            
        }
        i++;
        head = head->next;
    }
    return has;
}

// This helper function is for the main below and will
// have no effect on your has_diagonal. It does not
// need to be modified.
struct node *make_list(int a, int b, int c);

// This is a main function which could be used
// to test your has_diagonal function.
// It will not be marked.
// Only your has_diagonal function will be marked.
//
// It's recommended to change the int values in this
// main to test whether your has_diagonal is working.
int main(void) {
    struct list_node *head = malloc(sizeof(struct list_node));
    struct list_node *l = head;
    
    // create the first list
    l->my_list = make_list(5, 0, 0);
    
    // create the second list
    l->next = malloc(sizeof(struct list_node));
    l = l->next;
    l->my_list = make_list(0, 5, 0);
    
    // create the third list
    l->next = malloc(sizeof(struct list_node));
    l = l->next;
    l->my_list = make_list(0, 0, 5);
    l->next = NULL;
    
    printf("The result of has_diagonal is: %d\n", has_diagonal(head));
    
    return 0;
}

struct node *make_list(int a, int b, int c) {
    struct node *head = malloc(sizeof(struct node));
    struct node *n = head;
    n->data = a;
    n->next = malloc(sizeof(struct node));
    n = n->next;
    n->data = b;
    n->next = malloc(sizeof(struct node));
    n = n->next;
    n->data = c;
    n->next = NULL;
    
    return head;
}

Exercise — individual:
Most frequent list

Download most_frequent_list.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity most_frequent_list

Your task is to add code to this function in most_frequent_list.c:

// return the value which occurs most frequently in a linked list
// if several values are equally most frequent
// the value that occurs earliest in the list is returned
int most_frequent(struct node *head) {

    // PUT YOUR CODE HERE (change the next line!)
    return 42;

}

Note most_frequent_list.c uses the following familiar data type:

struct node {
    struct node *next;
    int          data;
};

most_frequent is given one argument, head, which is the pointer to the first node in a linked list.

Add code to most_frequent so that its returns the most frequently occurring value in the linked list.

For example if the linked list contains these 8 elements:

655 10 204 8192 76 38 204 43912 204

most_frequent should return 204, because it is the most frequently occurring integer -- it appears 3 times.

For example if the linked list contains these 8 elements:

7 8 12 3 12 3 8

most_frequent should return 8.

There is a tie for most frequently occurring integer - 3, 8 and 12 all occur twice.

8 occurred first in the list so it should be returned.

You are not permitted to use arrays or malloc in your function.

Testing

most_frequent_list.c also contains a main function which allows you to test your most_frequent function.

This main function:

  • converts the command-line arguments to a linked list.
  • assigns a pointer to the first node in the linked list to head.
  • calls most_frequent(head).
  • prints the result.

Do not change this main function. If you want to change it, you have misread the question.

Your most_frequent function will be called directly in marking. The main function is only to let you test your most_frequent function

Here is how you the main function allows you to test most_frequent:

dcc most_frequent_list.c -o most_frequent_list
./most_frequent_list 655 10 204 8192 76 38 204 43912 204
204
./most_frequent_list 5 4 6 5 4 6
5
./most_frequent_list 3 5 7 11 13 15 3 17 19 23 29 13 3
3

Assumptions/Restrictions/Clarifications.

  • most_frequent should return a single integer.
  • most_frequent should not change the linked list it is given.
  • Your function should not change the next or data fields of list nodes.
  • most_frequent should not use arrays.
  • most_frequent should not call malloc.
  • most_frequent should not call scanf (or getchar or fgets).
  • You can assume the linked list contains at least one integer.
  • most_frequent should not print anything. It should not call printf.

Do not change the supplied main function. It will not be tested or marked.

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest most_frequent_list
Sample solution for most_frequent_list.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node {
    struct node *next;
    int          data;
};

struct node *strings_to_list(int len, char *strings[]);
int most_frequent(struct node *head);
int count_occurrances(int i, struct node *head);

int main(int argc, char *argv[]) {
    // create linked list from command line arguments
    struct node *head = strings_to_list(argc - 1, &argv[1]);

    int result = most_frequent(head);
    printf("%d\n", result);

    return 0;
}

// return the value which occurs most frequently in a linked list
// if several values are equally most frequent
// the value that occurs earliest in the list is returned
int most_frequent(struct node *head) {
    int most_frequent_num = 0;
    int most_frequent_count = 0;
    struct node *p = head;
    while (p != NULL) {
        int count = count_occurrances(p->data, head);
        if (count > most_frequent_count) {
            most_frequent_num = p->data;
            most_frequent_count = count;
        }
        p = p->next;
    }
    return most_frequent_num;
}

// return the number of times i, occurs in a linked list
int count_occurrances(int i, struct node *head) {
    int num = 0;
    struct node *p = head;
    while (p != NULL) {
        if (p->data == i) {
            num = num + 1;
        }
        p = p->next;
    }
    return num;
}


// DO NOT CHANGE THIS FUNCTION

// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
    struct node *head = NULL;
    for (int i = len - 1; i >= 0; i = i - 1) {
        struct node *n = malloc(sizeof(struct node));
        assert(n != NULL);
        n->next = head;
        n->data = atoi(strings[i]);
        head = n;
    }
    return head;
}