|
| 1 | +/* |
| 2 | +
|
| 3 | + ************************** |
| 4 | + * To intrepid Googlers: * |
| 5 | + ************************** |
| 6 | +
|
| 7 | + This file was written by Erik Swan for the Spring 2015 section of ECE 264. |
| 8 | +
|
| 9 | + Although I have made it available publicly under the MIT license, you should be |
| 10 | + well aware that submitting *any* portion of this code as your own work is |
| 11 | + academically dishonest. |
| 12 | +
|
| 13 | + Considering that this file and the corresponding GitHub project have been |
| 14 | + indexed by Google and are likely to show up among the top results for "ECE 264", |
| 15 | + you should assume that using any of this code will quite easily be flagged by |
| 16 | + the anti-cheating tools the teaching team likely has in place. |
| 17 | +
|
| 18 | + Don't be dumb. Do your work. |
| 19 | +
|
| 20 | +*/ |
| 21 | + |
| 22 | +#include <stdlib.h> |
| 23 | +#include <string.h> |
| 24 | + |
| 25 | +/* SOLVE THE PROBLEMS IN ORDER IF POSSIBLE. We don't guarantee fully |
| 26 | + counting solutions to later problems if earlier problems are unsolved. |
| 27 | +
|
| 28 | + Minimum score guarantees: (actual score may be curved above this minimum) |
| 29 | + Problem One working: 60% |
| 30 | + Problems One and Two working: 70% |
| 31 | + Problems One, Two, Three working: 90% |
| 32 | +
|
| 33 | + Problems four and five exist. |
| 34 | +
|
| 35 | + 5% deduction from this if you do not provide a working Makefile |
| 36 | +
|
| 37 | + working = correct output on any tests we make up, and no valgrind errors. |
| 38 | +
|
| 39 | + For reference: |
| 40 | + > valgrind --tool=memcheck --leak-check=full --log-file=memcheck.log ./main |
| 41 | +
|
| 42 | + Code efficiently but DO NOT RACE. Your efficiency and effectiveness is |
| 43 | + a key outcome of this class. |
| 44 | +
|
| 45 | +*/ |
| 46 | + |
| 47 | +/*======================================================================*/ |
| 48 | +/* Problem Zero */ |
| 49 | + |
| 50 | +/* Write a Makefile for this assignment that compiles exam.c and main.c |
| 51 | + into an executable file called main |
| 52 | +*/ |
| 53 | + |
| 54 | + |
| 55 | + |
| 56 | +/*======================================================================*/ |
| 57 | +/* Problem One */ |
| 58 | +/* |
| 59 | + array_sum_nth is a function that returns the sum of SELECTED elements |
| 60 | + of the array of 'len' elements passed in. |
| 61 | +
|
| 62 | + An array element is included in the sum if the index of that |
| 63 | + element is a multiple of the positive integer n. |
| 64 | +
|
| 65 | + Index 0 is considered a multiple of every n. |
| 66 | +
|
| 67 | + So, if array holds the elements 1,2,3,4,5 in that order, and n is |
| 68 | + 2, the return value will be 1+3+5 = 9. |
| 69 | +
|
| 70 | + Other examples can be found in main.c in the testing code. |
| 71 | +
|
| 72 | + If n=1, this function just returns the sum of all the array elements. |
| 73 | +
|
| 74 | + */ |
| 75 | +int array_sum_nth(int * array, int len, int n) { |
| 76 | + int sum = 0, i; |
| 77 | + for(i = 0; i < len; i++) { |
| 78 | + if(!(i % n)) { |
| 79 | + sum += array[i]; |
| 80 | + } |
| 81 | + } |
| 82 | + return sum; |
| 83 | +} |
| 84 | + |
| 85 | + |
| 86 | +/*======================================================================*/ |
| 87 | +/* Problem Two */ |
| 88 | + |
| 89 | +/* |
| 90 | + interleave1 is a function that stores its result in memory pointed |
| 91 | + to by its third argument, named 'output'. |
| 92 | +
|
| 93 | + You may ASSUME that output is not NULL and points at enough memory |
| 94 | + to store the requested result. |
| 95 | +
|
| 96 | + The result computed is the two strings s1 and s2 interleaved: the |
| 97 | + characters of the output alternate from the two inputs. |
| 98 | +
|
| 99 | +
|
| 100 | + Specifically, the first character of the output is the first |
| 101 | + character of s1, then the second character of the output is the |
| 102 | + first character of s2, and so forth alternating. If an input string |
| 103 | + is used up, the remaining output comes from the other string. |
| 104 | +
|
| 105 | + example: |
| 106 | +
|
| 107 | +
|
| 108 | + interleave1("abc", "12345", output); |
| 109 | +
|
| 110 | + will result in output pointing at the string "a1b2c345". |
| 111 | +
|
| 112 | + */ |
| 113 | +void interleave1 (const char * s1, const char * s2, char * output) { |
| 114 | + int i, selector = 1, len = strlen(s1) + strlen(s2); |
| 115 | + |
| 116 | + for(i = 0; i < len; i++) { |
| 117 | + if(selector) { |
| 118 | + *(output + i) = (*s1 == '\0' ? *s2++ : *s1++); |
| 119 | + if(*s1 != '\0') { |
| 120 | + selector = !selector; |
| 121 | + } |
| 122 | + } else { |
| 123 | + *(output + i) = (*s2 == '\0' ? *s1++ : *s2++); |
| 124 | + if(*s2 != '\0') { |
| 125 | + selector = !selector; |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + // Terminate with a null character |
| 131 | + *(output + i) = '\0'; |
| 132 | +} |
| 133 | + |
| 134 | + |
| 135 | +/*======================================================================*/ |
| 136 | +/* Problem Three */ |
| 137 | +/* |
| 138 | + interleave2 functions the same as interleave1 except that the |
| 139 | + resulting string is returned differently: |
| 140 | +
|
| 141 | + SUMMARY: the output is returned in the space of size 'avail' pointed |
| 142 | + to by the pointer 'output', if 'output' is not NULL and 'avail' is |
| 143 | + big enough. If not, that space is freed, and a large enough space |
| 144 | + is created for the output---then 'output' and 'avail' are set to |
| 145 | + describe that new space, the desired output must then be written it |
| 146 | + before returning. |
| 147 | +
|
| 148 | + interleave2 MAY CALL interleave1 and this is useful. |
| 149 | +
|
| 150 | + HINTS (if you need more; you don't need to read these): |
| 151 | +
|
| 152 | + (1) the result is returned as the value of the 'output' parameter, |
| 153 | + together with a number of bytes that is returned in 'avail'. |
| 154 | +
|
| 155 | + (2) the 'output' parameter is passed as char ** so you can change |
| 156 | + the caller's pointer in order to return a value in new memory |
| 157 | + that you allocate if need be. The 'avail' parameter is passed |
| 158 | + as int * so that you can return the size of the space allocated. |
| 159 | +
|
| 160 | + (3) the 'output' parameter, if not NULL, is promised to point to |
| 161 | + available space that may or may not be sufficient for your |
| 162 | + answer. The size of this space, in bytes, is given by the |
| 163 | + 'avail' parameter. If you don't need more space than this, do |
| 164 | + not change 'output' or 'avail'. |
| 165 | +
|
| 166 | + (4) If 'output' is NULL (in which case 'avail' should not be used |
| 167 | + for anything), or if you need more than 'avail' bytes, including |
| 168 | + the null byte for your answer, you must reclaim the space |
| 169 | + pointed to by 'output' and then allocate the space needed, and |
| 170 | + point 'output' to the newly allocated space. Do not do this if |
| 171 | + there was already sufficient space. |
| 172 | +
|
| 173 | + (5) the interleaved string is returned in the space so provided. |
| 174 | +
|
| 175 | + You may use strlen from <string.h> to help determine how much memory |
| 176 | + is needed, but don't forget the null byte. Use the shell command |
| 177 | + "man strlen" to see a description of how to call strlen. (or in Emacs |
| 178 | + "M-x manual", and then enter "strlen" to the prompt) |
| 179 | + */ |
| 180 | +void interleave2 (const char * s1, const char * s2, char ** output, int * avail) { |
| 181 | + if(!(*output) || (strlen(s1) + strlen(s2) + 1 > *avail)) { |
| 182 | + free(*output); |
| 183 | + *avail = strlen(s1) + strlen(s2) + 1; |
| 184 | + *output = malloc(*avail * sizeof(char)); |
| 185 | + } |
| 186 | + interleave1(s1, s2, *output); |
| 187 | +} |
| 188 | + |
| 189 | + |
| 190 | +/*====================================================================== |
| 191 | + * FUNCTIONS BELOW HERE ARE "GRAVY", you do not need them to get a |
| 192 | + * 90% but they may help your grade anyways if you have time. Solve |
| 193 | + * the above problems first, if at all possible. |
| 194 | + */ |
| 195 | + |
| 196 | + |
| 197 | +/*======================================================================*/ |
| 198 | +/* Problem Four */ |
| 199 | +/* |
| 200 | + hidden_subsequence determines if the string s2 is the same as s1 |
| 201 | + with extra characters added at any point. |
| 202 | +
|
| 203 | + i.e. can string s2 become string s1 by deleting characters? |
| 204 | +
|
| 205 | + return 1 if so, and 0 if not. |
| 206 | +
|
| 207 | + to answer this, you look through s2 for the first character of s1, |
| 208 | + and then after that keep looking from that point for the second |
| 209 | + character of s1, and so forth until all of s1 has been found. |
| 210 | +
|
| 211 | + examples: |
| 212 | +
|
| 213 | + hidden_subsequence ("abc", "125a76a687b9c12") returns 1 |
| 214 | + hidden_subsequence ("abc", "125a76a6879c12") returns 0 |
| 215 | +
|
| 216 | +*/ |
| 217 | +int hidden_subsequence (const char * s1, const char * s2) { |
| 218 | + |
| 219 | + // This function is pretty elegant, I like it. :) |
| 220 | + for(; *s1 != '\0'; s1++) { |
| 221 | + for(; *s2 != *s1; s2++) { |
| 222 | + if(*s2 == '\0') { |
| 223 | + return 0; |
| 224 | + } |
| 225 | + } |
| 226 | + } |
| 227 | + return 1; |
| 228 | +} |
| 229 | + |
| 230 | +/*======================================================================*/ |
| 231 | +/* Problem Five */ |
| 232 | +/* |
| 233 | + merge_strings receives two strings s1 and s2. |
| 234 | +
|
| 235 | + ASSUME that s1 and s2 are made up of strictly increasing characters. |
| 236 | +
|
| 237 | + i.e. s1[i] < s1[i+1] for i small enough to stay within string s1, etc. |
| 238 | +
|
| 239 | + so s1 can point to "abbcd" but not "bdcba" |
| 240 | +
|
| 241 | + ** note that characters in strings can be compared with < and that is |
| 242 | + the ordering among characters we are talking about here |
| 243 | +
|
| 244 | + The output string will be placed in space that must be created by |
| 245 | + merge_strings, pointed to by 'output', and must then contain all the |
| 246 | + characters from s1 and s2, in sorted order. |
| 247 | +
|
| 248 | + example |
| 249 | +
|
| 250 | + char * answer; |
| 251 | + merge_strings("aabcccnnop", "bbdx", &answer); |
| 252 | + printf("The answer is \"%s\"\n", answer); |
| 253 | +
|
| 254 | + will print |
| 255 | +
|
| 256 | + The answer is "aabbbcccdnnopx" |
| 257 | +
|
| 258 | + */ |
| 259 | +void merge_strings (const char * s1, const char * s2, char ** output) { |
| 260 | + // Sorting function definition |
| 261 | + int compare(const void * c1, const void * c2) { |
| 262 | + return (*((char *) c1) > *((char *) c2)) ? 1 : -1; |
| 263 | + } |
| 264 | + |
| 265 | + // Allocate buffer and copy strings |
| 266 | + *output = malloc((strlen(s1) + strlen(s2) + 1) * sizeof(char)); |
| 267 | + strcpy(*output, s1); |
| 268 | + strcpy(*output + strlen(s1), s2); |
| 269 | + |
| 270 | + // Sort in place |
| 271 | + qsort(*output, strlen(s1) + strlen(s2), sizeof(char), compare); |
| 272 | +} |
0 commit comments