I. Constructing loops A. Background: Arrays in C ------------------------------------------ ARRAYS IN C - declaration (creation): - constant time element access: trajectory[0], ..., trajectory[19] trajectory[0] = 7; - minimal space overhead: arrays do not store ------------------------------------------ ------------------------------------------ STRINGS ARE CHAR ARRAYS IN C In C a string is an array of chars that char greeting[] = "hello!"; greeting[0] == 'h' greeting[1] == 'e' greeting[2] == 'l' greeting[3] == 'l' greeting[4] == 'o' greeting[5] == '!' greeting[6] == ------------------------------------------ B. tabular method for constructing loops 1. accumulators ------------------------------------------ ACCUMULATORS What is an accumulator? Uses: ------------------------------------------ 2. questions to ask ------------------------------------------ TABULAR METHOD FOR CONSTRUCTION OF LOOPS 0. Should we use a loop? 1. What kind of loop? (while or for?) 2. What information is needed for the steps? 3. Up or down? 4. When should the loop stop? 5. What would be the steps for an example? 6. Generalize from those steps ------------------------------------------ 3. examples a. sum elements of an array ------------------------------------------ EXAMPLE: SUMMING AN ARRAY Write a function int sum(int a[], int sz); that returns the sum of the elements in a at indexes a[0], ..., a[sz-1]. 0. Should we use a loop? 1. What kind of loop? (while or for?) 2. What information is needed for the steps? 3. Up or down? 4. When should the loop stop? 5. What would be the steps for an example? 6. Generalize from those steps ------------------------------------------ ------------------------------------------ EXAMPLE: ADDING TO EACH ARRAY ELEMENT Write a function void addToEach(int a[], int sz, int v); that modifies each element a[i] of to be a[i] + v. 0. Should we use a loop? 1. What kind of loop? (while or for?) 2. What information is needed for the steps? 3. Up or down? 4. When should the loop stop? 5. What would be the steps for an example? 6. Generalize from those steps ------------------------------------------ ------------------------------------------ LENGTH OF A STRING Write a function int mystrlen(char s[]); that return the number of chars in s up to the first null char ('\0'). 0. Should we use a loop? 1. What kind of loop? (while or for?) 2. What information is needed for the steps? 3. Up or down? 4. When should the loop stop? 5. What would be the steps for an example? 6. Generalize from those steps ------------------------------------------ II. "Friday" problems on C loops and arrays A. string problems 1. mystrlen() ------------------------------------------ FOR YOU TO DO Without using strlen() (from ), write, in C, a function int mystrlen(char s[]); that return the number of chars in s up to the first null char ('\0'). Assume that there is a null char in s. The following are tests using tap.h: ok(mystrlen("") == 0); ok(mystrlen("c") == 1); ok(mystrlen("fiddle") == 6); ok(mystrlen("Madam I'm Adam!") == 15); ------------------------------------------ 2. is_substring() ------------------------------------------ FOR YOU TO DO Without using strstr(), write, in C, a function _Bool is_substring(char sought[], char str[]) which returns true just when sought is a substring of str. That is, when there is some index i into str such that sought[0] == str[i], sought[1] == str[i+1], ..., and sought[sought_len-1] == str[sought_len-1] and all the indexes involved are legal for both sought and str. Assume that both sought and str are null-terminated strings. The following are tests using tap.h: ok(is_substring("abcd", "xabcd")); ok(is_substring("", "asdlfjlkfa")); ok(is_substring("fjl", "asdlfjlkfa")); ok(!is_substring("abba", "asdlfjlkfa")); ok(is_substring("Miss", "Mississippi")); ok(!is_substring("Fla.", "Mississippi")); ok(is_substring("Miss", "I love Mississippi")); ok(!is_substring("Miss", "I love Florida.")); ok(!is_substring("Miss", "mississippi")); ok(is_substring("Miss", "Thanks, Miss")); ok(is_substring("dog", "x dog")); ok(is_substring("lazy dog", "The quick brown fox jumped over the lazy dog")); ok(is_substring("brown fox", "The quick brown fox jumped over the lazy dog")); ok(!is_substring("Drump", "The quick brown fox jumped over the lazy dog")); ok(!is_substring("Flabergasted", "Flaber")); ------------------------------------------ B. standard array problems ------------------------------------------ FOR YOU TO DO In C, write a function int arr_min(int a[], int sz) that takes an array of ints, a, of size sz, and returns the minimum element in a. The following are tests that use tap.h: int a3223[] = {3, 2, 2, 3}; ok(arr_min(a3223, 4) == 2); int a13223[] = {1, 3, 2, 2, 3}; ok(arr_min(a13223, 5) == 1); int a5041[] = {5, 0, 4, 1}; ok(arr_min(a5041, 4) == 0); int a999[] = {999}; ok(arr_min(a999, 1) == 999); ------------------------------------------ III. Compilation with multiple modules in C A. typical homework problem example ------------------------------------------ TYPICAL HOMEWORK PROBLEM MODULES Suppose you are to write function f. We provide all files except f.c (where you put the code for f) Modules: tap.c with header tap.h f.c with header f.h test_f.c Compilation command: gcc -Wall -pedantic tap.c f.c test_f.c -o test_f Compilation works in stages: 1. compiling each module (gcc -c *.c) tap.c -> tap.o f.c -> f.o test_f.c -> test_f.o 2. loading/linking (gcc *.o -o test_f) tap.o f.o test_f.o -> test_f.exe During step 1 the compiler During step 2 the loader/linker Running the program: > ./test_f runs test_f.exe on Windows test_f on Unix/MacOS ------------------------------------------ B. declarations and scope issues ------------------------------------------ DECLARATIONS AND SCOPE FOR FUNCTIONS in C A function declaration extern double f(int x); A function declaration and definition double f(int x) { return x*2.0; } Scope of a declaration extends ------------------------------------------ IV. "Friday" problems on C loops and arrays A. string problems 1. downcase ------------------------------------------ FOR YOU TO DO In C, write a function void downcase(char str[]); that takes a string (which is assumed to be allocated and null-terminated), str, and modifies str so that every uppercase char in str (up to the null character) is changed to its corresponding lowercase equivalent, and all other characters are left alone. You may use the following library functions from : // checks if c is an uppercase char int isupper(int c); // return the lowercase equeivalent of c int tolower(int c); ------------------------------------------ ------------------------------------------ TESTING FOR DOWNCASE() // Gary Leavens, file test_downcase.c // Compile with: // gcc tap.c quantifiers.c downcase.c test_downcase.c -o test_downcase #include #include #include #include #include #include "tap.h" #include "quantifiers.h" extern void downcase(char str[]); // static pointer used for checking results char *gstr; // Ensures: result is true when gstr[i] is lower case if it's alphabetic static bool checkLower(int i) { return !isalpha(gstr[i]) || islower(gstr[i]); } // Ensures result is true if downcase worked correctly bool check_downcase(const char *str) { // add 1 to the length below to make sure the null char is copied size_t len = strlen(str) + 1; // To allow modification, need a local copy of str char temp[len]; strncpy(temp, str, len); // The char at index len is a null char: // ok(str[len] == '\0'); gstr = temp; printf("downcasing \"%s\"\n", temp); downcase(temp); printf(" ... result is \"%s\"\n", temp); ok(allIntsIn(checkLower, 0, len-1)); } int main() { plan(4); check_downcase("HI"); check_downcase("ABBA"); check_downcase("Madam, I'm Adam!"); check_downcase("The Rain in Spain Falls Mainly on the Plain!"); return exit_status(); } ------------------------------------------ B. array problems ------------------------------------------ FOR YOU TO DO In C, write a function: void print_histogram(const int freqs[], int sz); that takes an array of non-negative ints, freqs, and a non-negative int, sz, such that freqs has sz elements, and prints a row for each i < sz that has i (in 2 spaces) followed by a colon (:) and a space and freqs[i] asterisks. For example if freqs[i] == i, for 0<= i && i < 5, then the output would be: 0: 1: * 2: ** 3: *** 4: **** If freqs[0] == 3, freqs[1] == 2, freqs[2] == 2, freqs[3] == 3, freqs[4] == 4, freqs[5] == 0, freqs[6] == 2, freqs[7] == 10 then the output would be: 0: *** 1: ** 2: ** 3: *** 4: **** 5: 6: ** 7: ********** ------------------------------------------ How would you change the program to read in the freqs array? How would you change the program to read in the labels? C. an I/O problem ------------------------------------------ FOR YOU TO DO In C, write a program void print_triplets(); that reads from stdin an int, n, such that n >= 6, and prints on stdout triplets of ints of the form (a, b, c), such that a+b+c == n and 0 < a and a < b and b < c. One triplet should be printed per line. For example, print_triplets(6) prints: (1, 2, 3) and print_triplets(10) prints: (1, 2, 7) (1, 3, 6) (1, 4, 5) (2, 3, 5) ------------------------------------------