From 442a49ad5a48d417345959b903ae6a6d32d55759 Mon Sep 17 00:00:00 2001 From: Haidong Ji Date: Fri, 15 Apr 2022 15:51:30 -0500 Subject: Great C programming fun Excellent fundamentals and displine training, many tools and techniques exercises: gdb, emacs, valgrind, git --- 32_kvs/Makefile | 12 ++++++ 32_kvs/README | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 32_kvs/README~ | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 32_kvs/grade.txt | 19 +++++++++ 32_kvs/kv.c | 87 ++++++++++++++++++++++++++++++++++++++++ 32_kvs/kv.c~ | 81 ++++++++++++++++++++++++++++++++++++++ 32_kvs/kv.h | 26 ++++++++++++ 32_kvs/kv.o | Bin 0 -> 58936 bytes 32_kvs/kv_test | Bin 0 -> 54408 bytes 32_kvs/kv_test.c | 17 ++++++++ 32_kvs/kv_test.o | Bin 0 -> 54280 bytes 32_kvs/test.old | 6 +++ 32_kvs/test.txt | 3 ++ 13 files changed, 487 insertions(+) create mode 100644 32_kvs/Makefile create mode 100644 32_kvs/README create mode 100644 32_kvs/README~ create mode 100644 32_kvs/grade.txt create mode 100644 32_kvs/kv.c create mode 100644 32_kvs/kv.c~ create mode 100644 32_kvs/kv.h create mode 100644 32_kvs/kv.o create mode 100755 32_kvs/kv_test create mode 100644 32_kvs/kv_test.c create mode 100644 32_kvs/kv_test.o create mode 100644 32_kvs/test.old create mode 100644 32_kvs/test.txt (limited to '32_kvs') diff --git a/32_kvs/Makefile b/32_kvs/Makefile new file mode 100644 index 0000000..38f5d54 --- /dev/null +++ b/32_kvs/Makefile @@ -0,0 +1,12 @@ +CFLAGS=-Wall -Werror -std=gnu99 -pedantic -ggdb3 +OBJS=kv_test.o kv.o +PROGRAM=kv_test + +$(PROGRAM): $(OBJS) + gcc $(CFLAGS) -o $@ $(OBJS) + +%.o: %.c kv.h + gcc -c $(CFLAGS) $< + +clean: + rm -f $(OBJS) $(PROGRAM) *~ diff --git a/32_kvs/README b/32_kvs/README new file mode 100644 index 0000000..35b0a18 --- /dev/null +++ b/32_kvs/README @@ -0,0 +1,118 @@ +For the next 4 problems, you will be doing one slightly larger program, which +we will cut up into 4 discretely testable pieces. + +The big picture is that your program will read two types of input files. +The first type of input file (which your program will read one of) will have the format: + +key1=value1 +key2=value2 +.... +keyN=valueN + +That is, it might say + +Jean Luc Picard=Captain +Will Riker=Commander +Beverly Crusher=Commander +Data=Lt. Commander +Geordi LaForge=Lt. Commander +Worf=Lt. Commander +Deanna Troi=Commander + +Note that the division between the key and the value is the first equals sign (the +values could have = in them, but the keys cannot. So a=b=c, would have a key of a, and +a value of b=c). + +The second type of input file will contain a list of lines (which will typically match +the keys from the first input file). Your program will read one or more of this +type of file. For example, it might contain: + +Jean Luc Picard +Will Riker +Worf +Deanna Troi +Q + +For each such input file that your program reads, it will print out the counts +of the values for the corresponding keys (or for anything that did not +match any known key from the first input file). E.g. given the above to input files, +it would print to the corresponding output file (which will be named the same +as the input file, but with ".count" appended to the name). + +Captain: 1 +Commander: 2 +Lt. Commander: 1 + : 1 + + + + +In thinking about our program, we might come up with the following +generalized high-level algorithm: + + //read the key/value pairs from the file named by argv[1] (call the result kv) + //count from 2 to argc (call the number you count i) + //count the values that appear in the file named by argv[i], using kv as the key/value pair + // (call this result c) + //compute the output file name from argv[i] (call this outName) + //open the file named by outName (call that f) + //print the counts from c into the FILE f + //close f + //free the memory for outName and c + //free the memory for kv + +This high-level algorithm suggests many functions which we can split our task into. +We will cut them up into 4 groups to make the 4 problems of this assignment: + +The first step (this problem): + - read the key/value pairs from a file + - free the memory for the key/value pairs + +The second step (next problem): + - compute the output file name + +The third step (problem after that): + - print the counts to a file + - free the memory for the counts + +The fourth step (the problem after that): + - compute the counts of values that appear in a particular input file + +Each subsequent problem will have more details about it. + +For this particular problem, you will need to: + + - read the key/value pairs from a file + - free the memory for the key/value pairs + +To start with this problem, you are going to want to define two structs, in the +file kv.h. The first one (struct _kvpair_t) should define the structure for +one key/value pair. The second should define the structure for an +array of key/value pairs (hint: you will want to include the length of the +array in this structure). + +Now you will want to write the four functions in kv.c. + +In readKVs, you will want to open the file, read the lines of text, split them into +key/value pairs, add the resulting pairs to an array (hint: realloc it to make it larger +each time), close the file, and return the kvarray_t * that has your array. + +Remember that you will want to abstract out complex steps into functions (you should +see at least 2 pieces to naturally pull out into their own functions). + +Next, you will write freeKVs, which should free all the memory allocated by readKVs. +That is, freeKVs(readKVs(filename)) should not leak any memory. + +Third, write printKVs which should take a kvarray_t *, and print out + + "key = '%s' value = '%s'\n" +for each key/value pair in the array, with the first %s being whatever the key is, +and the second being whatever value (e.g., key = 'Jean Luc Picard' value = 'Captain'). + +Finally, write the lookupValue function, which takes a kvarray_t * and a char * (string). +The char * that is passed in represents a key. This function searches the kvarray_t +for a matching key, and if found, returns the corresponding value. If no match is found, +this function returns NULL. + +Once you complete these functions, test them using the main in kv_test.c before +proceeding to the next problem. diff --git a/32_kvs/README~ b/32_kvs/README~ new file mode 100644 index 0000000..b4ee3c6 --- /dev/null +++ b/32_kvs/README~ @@ -0,0 +1,118 @@ +For the next 4 problems, you will be doing one slightly larger program, which +we will cut up into 4 discretely testable pieces. + +The big picture it that your program will read two types of input files. +The first type of input file (which your program will read one of) will have the format: + +key1=value1 +key2=value2 +.... +keyN=valueN + +That is, it might say + +Jean Luc Picard=Captain +Will Riker=Commander +Beverly Crusher=Commander +Data=Lt. Commander +Geordi LaForge=Lt. Commander +Worf=Lt. Commander +Deanna Troi=Commander + +Not that the division between the key and the value is the first equals sign (the +values could have = in them, but the keys cannot. So a=b=c, would have a key of a, and +a value of b=c). + +The second type of input file will contain a list of lines (which will typically match +the keys from the first input file). Your program will read one or more of this +type of file. For example, it might contain: + +Jean Luc Picard +Will Riker +Worf +Deanna Troi +Q + +For each such input file that your program reads, it will print out the counts +of the values for the corresponding keys (or for anything that did not +match any known key from the first input file). E.g. given the above to input files, +it would print to the corresponding output file (which will be named the same +as the input file, but with ".count" appended to the name). + +Captain: 1 +Commander: 2 +Lt. Commander: 1 + : 1 + + + + +In thinking about our program, we might come up with the following +generalized high-level algorithm: + + //read the key/value pairs from the file named by argv[1] (call the result kv) + //count from 2 to argc (call the number you count i) + //count the values that appear in the file named by argv[i], using kv as the key/value pair + // (call this result c) + //compute the output file name from argv[i] (call this outName) + //open the file named by outName (call that f) + //print the counts from c into the FILE f + //close f + //free the memory for outName and c + //free the memory for kv + +This high-level algorithm suggests many functions which we can split our task into. +We will cut them up into 4 groups to make the 4 problems of this assignment: + +The first step (this problem): + - read the key/value pairs from a file + - free the memory for the key/value pairs + +The second step (next problem): + - compute the output file name + +The third step (problem after that): + - print the counts to a file + - free the memory for the counts + +The fourth step (the problem after that): + - compute the counts of values that appear in a particular input file + +Each subsequent problem will have more details about it. + +For this particular problem, you will need to: + + - read the key/value pairs from a file + - free the memory for the key/value pairs + +To start with this problem, you are going to want to define two structs, in the +file kv.h. The first one (struct _kvpair_t) should define the structure for +one key/value pair. The second should define the structure for an +array of key/value pairs (hint: you will want to include the length of the +array in this structure). + +Now you will want to write the four functions in kv.c. + +In readKVs, you will want to open the file, read the lines of text, split them into +key/value pairs, add the resulting pairs to an array (hint: realloc it to make it larger +each time), close the file, and return the kvarray_t * that has your array. + +Remember that you will want to abstract out complex steps into functions (you should +see at least 2 pieces to naturally pull out into their own functions). + +Next, you will write freeKVs, which should free all the memory allocated by readKVs. +That is, freeKVs(readKVs(filename)) should not leak any memory. + +Third, write printKVs which should take a kvarray_t *, and print out + + "key = '%s' value = '%s'\n" +for each key/value pair in the array, with the first %s being whatever the key is, +and the second being whatever value (e.g., key = 'Jean Luc Picard' value = 'Captain'). + +Finally, write the lookupValue function, which takes a kvarray_t * and a char * (string). +The char * that is passed in represents a key. This function searches the kvarray_t +for a matching key, and if found, returns the corresponding value. If no match is found, +this function returns NULL. + +Once you complete these functions, test them using the main in kv_test.c before +proceeding to the next problem. diff --git a/32_kvs/grade.txt b/32_kvs/grade.txt new file mode 100644 index 0000000..241c564 --- /dev/null +++ b/32_kvs/grade.txt @@ -0,0 +1,19 @@ +Grading at Fri 24 Dec 2021 08:54:52 PM UTC +Attempting to compile: +################################################# +testcase1: +Your output is correct + - Valgrind was clean (no errors, no memory leaks) +valgrind was clean +################################################# +testcase2: +Your output is correct + - Valgrind was clean (no errors, no memory leaks) +valgrind was clean +################################################# +testcase3: +Your output is correct + - Valgrind was clean (no errors, no memory leaks) +valgrind was clean + +Overall Grade: A diff --git a/32_kvs/kv.c b/32_kvs/kv.c new file mode 100644 index 0000000..00958c5 --- /dev/null +++ b/32_kvs/kv.c @@ -0,0 +1,87 @@ +#include "kv.h" +#include +#include +#include + +char *splitLine2KV(char *line, const char *delim) { + char *v = strstr(line, delim); + + if (v == NULL) + return NULL; + + *v = '\0'; + + v = v + strlen(delim); + strtok(v, "\n"); + + char *ans = malloc((strlen(v) + 1) * sizeof(*ans)); + strcpy(ans, v); + // return v + strlen(delim); + return ans; +} + +kvarray_t *readKVs(const char *fname) { + FILE *f = fopen(fname, "r"); + if (f == NULL) { + fprintf(stderr, "Could not open file\n"); + return NULL; + } + + kvarray_t *kvArray = malloc(sizeof(*kvArray)); + kvArray->kvarray = NULL; + kvArray->kvarrayLength = 0; + char *line = NULL; + size_t sz = 0; + int i = 0; + char *v = NULL; + + while (getline(&line, &sz, f) >= 0) { + v = splitLine2KV(line, "="); + if (v) { + kvpair_t *kvPair = malloc(sizeof(*kvPair)); + kvPair->key = malloc((strlen(line) + 1) * sizeof(kvPair->key)); + kvPair->value = malloc((strlen(v) + 1) * sizeof(kvPair->value)); + strcpy(kvPair->key, line); + strcpy(kvPair->value, v); + kvArray->kvarray = realloc(kvArray->kvarray, (i + 1) * sizeof(kvpair_t)); + kvArray->kvarray[i] = *kvPair; + i++; + kvArray->kvarrayLength = i; + free(kvPair); + } + free(v); + } + free(line); + + if (fclose(f) != 0) { + fprintf(stderr, "Could not close file\n"); + return NULL; + } + + return kvArray; +} + +void freeKVs(kvarray_t *pairs) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + free(pairs->kvarray[i].key); + free(pairs->kvarray[i].value); + } + free(pairs->kvarray); + free(pairs); +} + +void printKVs(kvarray_t *pairs) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + printf("key = '%s' value = '%s'\n", pairs->kvarray[i].key, + pairs->kvarray[i].value); + } +} + +char *lookupValue(kvarray_t *pairs, const char *key) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + if (strcmp(pairs->kvarray[i].key, key) == 0) { + return pairs->kvarray[i].value; + } + } + return NULL; +} diff --git a/32_kvs/kv.c~ b/32_kvs/kv.c~ new file mode 100644 index 0000000..d215207 --- /dev/null +++ b/32_kvs/kv.c~ @@ -0,0 +1,81 @@ +#include "kv.h" +#include +#include +#include + +char *splitLine2KV(char *line, const char *delim) { + char *v = strstr(line, delim); + + if (v == NULL) + return NULL; + + *v = '\0'; + return v + strlen(delim); +} + +kvarray_t *readKVs(const char *fname) { + FILE *f = fopen(fname, "r"); + if (f == NULL) { + fprintf(stderr, "Could not open file\n"); + return NULL; + } + + kvarray_t *kvArray = malloc(sizeof(*kvArray)); + kvArray->kvarray = NULL; + char *line = NULL; + size_t sz = 0; + int i = 0; + + while (getline(&line, &sz, f) >= 0) { + char *v; + v = splitLine2KV(line, "="); + if (v) { + char *value = malloc((strlen(v) + 1) * sizeof(*value)); + strcpy(value, strtok(v, "\n")); + char *key = malloc((strlen(line) + 1) * sizeof(*key)); + strcpy(key, line); + + kvpair_t *kvPair = malloc(sizeof(kvPair)); + kvPair->key = key; + kvPair->value = value; + kvArray->kvarray = realloc(kvArray->kvarray, (i + 1) * sizeof(kvpair_t)); + kvArray->kvarray[i] = *kvPair; + free(kvPair); + i++; + kvArray->kvarrayLength = i; + } + } + free(line); + + if (fclose(f) != 0) { + fprintf(stderr, "Could not close file\n"); + return NULL; + } + + return kvArray; +} + +void freeKVs(kvarray_t *pairs) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + free(pairs->kvarray[i].key); + free(pairs->kvarray[i].value); + } + free(pairs->kvarray); + free(pairs); +} + +void printKVs(kvarray_t *pairs) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + printf("key = '%s' value = '%s'\n", pairs->kvarray[i].key, + pairs->kvarray[i].value); + } +} + +char *lookupValue(kvarray_t *pairs, const char *key) { + for (int i = 0; i < pairs->kvarrayLength; i++) { + if (strcmp(pairs->kvarray[i].key, key) == 0) { + return pairs->kvarray[i].value; + } + } + return NULL; +} diff --git a/32_kvs/kv.h b/32_kvs/kv.h new file mode 100644 index 0000000..51ccbb1 --- /dev/null +++ b/32_kvs/kv.h @@ -0,0 +1,26 @@ +#ifndef __KV_H__ +#define __KV_H__ + + +struct _kvpair_t { + char * key; + char * value; +}; +typedef struct _kvpair_t kvpair_t; + +struct _kvarray_t { + kvpair_t * kvarray; + int kvarrayLength; +}; +typedef struct _kvarray_t kvarray_t; + + +kvarray_t * readKVs(const char * fname); + +void freeKVs(kvarray_t * pairs); + +void printKVs(kvarray_t * pairs); + +char * lookupValue(kvarray_t * pairs, const char * key); + +#endif diff --git a/32_kvs/kv.o b/32_kvs/kv.o new file mode 100644 index 0000000..017f5db Binary files /dev/null and b/32_kvs/kv.o differ diff --git a/32_kvs/kv_test b/32_kvs/kv_test new file mode 100755 index 0000000..3aa5b6e Binary files /dev/null and b/32_kvs/kv_test differ diff --git a/32_kvs/kv_test.c b/32_kvs/kv_test.c new file mode 100644 index 0000000..5532512 --- /dev/null +++ b/32_kvs/kv_test.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include "kv.h" + +#define NUM_LOOKUPS 5 +int main(void) { + kvarray_t * array = readKVs("test.txt"); + printf("Printing all keys\n\n"); + printKVs(array); + char *tests[NUM_LOOKUPS] = {"banana", "grapes", "cantaloupe", "lettuce", "orange"}; + for (int i = 0; i < NUM_LOOKUPS; i++) { + printf("lookupValue('%s')=%s\n", tests[i], lookupValue(array,tests[i])); + } + freeKVs(array); + return EXIT_SUCCESS; +} diff --git a/32_kvs/kv_test.o b/32_kvs/kv_test.o new file mode 100644 index 0000000..458acf1 Binary files /dev/null and b/32_kvs/kv_test.o differ diff --git a/32_kvs/test.old b/32_kvs/test.old new file mode 100644 index 0000000..782743e --- /dev/null +++ b/32_kvs/test.old @@ -0,0 +1,6 @@ +apple=red +banana=yellow +orange=orange +grapes=purple +carrot=orange +eggplant=purple diff --git a/32_kvs/test.txt b/32_kvs/test.txt new file mode 100644 index 0000000..c812bb6 --- /dev/null +++ b/32_kvs/test.txt @@ -0,0 +1,3 @@ +a +bc +df -- cgit v1.2.3