Directions: Answers are in red.
Write a C function to_lower that will take a C string as input parameter, and will return a new malloced string that is a copy of the input parameter except that any uppercase letter has been converted to lowercase. See the function to_lower in the next question.
File: sins.c | Runs of sins |
---|---|
#include <stdio.h> /* prototypes here */ void printitlower(char **p); char *to_lower(char *s); void main(void) { char *sins[] = {"ENVY", "SLOTH", "GLUTTONY", "WRATH", "PRIDE", "LUST", "GREED", NULL}; char *laws[] = {"Trustworthy", "Loyal", "Helpful", "Friendly", "Courteous", "Kind", "Obedient", "Cheerful", "Thrifty", "Brave", "Clean", "Reverent", NULL}; /* 2 calls to the function here */ printit(sins); printf("\n"); printit(laws); printf("\n"); printitlower2(sins); printf("\n"); printitlower(laws); } /* code for the function here */ void printit(char **p) { while (*p != NULL) { printf("%s\n", *(p++)); } } void printit2(char **p) { char *s; while (*p) { s = *p; while (*s) putchar(*s++); putchar('\n'); p++; } } void printitlower(char **p) { while (*p) printf("%s\n", to_lower(*(p++))); } char *to_lower(char *s) { char *t = (char *)malloc(sizeof(char)*(strlen(s) + 1)); char *tsave = t; while (*s != '\0') { *t = tolower(*s); t++; s++; } *t = '\0'; return tsave; } |
% cc -o sins sins.c % sins ENVY SLOTH GLUTTONY WRATH PRIDE LUST GREED Trustworthy Loyal Helpful Friendly Courteous Kind Obedient Cheerful Thrifty Brave Clean Reverent envy sloth gluttony wrath pride lust greed trustworthy loyal helpful friendly courteous kind obedient cheerful thrifty brave clean reverent |
void f(int m, int n) { double r[m][n]; /* other stuff */ } |
For the above reasons, it is not straightforward to write a function in C that will take an arbitrary 2-dimensional array as input parameter. Instead, one must resort to trickery, as in the following examples:
File: arr.c | File: arr2.c |
---|---|
#include <stdio.h> int index(int i, int j, int n); void readarray(double *r, int m, int n); void writearray(double *r, int m, int n); int main() { int m, n; /* m-by-n arrays */ double *r; scanf("%i %i", &m, &n); r = (double *)malloc(sizeof(double)*m*n); readarray(r, m, n); writearray(r, m, n); } void readarray(double *r, int m, int n) { int i, j; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { scanf("%lf", &r[index(i, j, n)]); } } void writearray(double *r, int m, int n) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf("%6.1f", r[index(i, j, n)]); printf("\n"); } } /* DEFINITION FOR FUNCTION "index" HERE */ int index(int i, int j, int n) { return i*n + j; } % cat arr.txt 3 4 1.0 2.0 3.0 4.0 11.0 12.0 13.0 14.0 21.0 22.0 23.0 24.0 31.0 32.0 33.0 34.0 % cc -o arr arr.c % arr < arr.txt 1.0 2.0 3.0 4.0 11.0 12.0 13.0 14.0 21.0 22.0 23.0 24.0 | #include <stdio.h> /* DEFINITION FOR MACRO "R" HERE */ /* #define R(i, j, n) r[(i)*(n) + (j)] */ #define R(i, j, n) *(r + (i)*(n) + (j)) void readarray(double *r, int m, int n); void writearray(double *r, int m, int n); int main() { int m, n; /* m-by-n arrays */ double *r; scanf("%i %i", &m, &n); r = (double *)malloc(sizeof(double)*m*n); readarray(r, m, n); writearray(r, m, n); } void readarray(double *r, int m, int n) { int i, j; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { scanf("%lf", &R(i, j, n)); } } void writearray(double *r, int m, int n) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf("%6.1f", R(i, j, n)); printf("\n"); } } % cat arr.txt 3 4 1.0 2.0 3.0 4.0 11.0 12.0 13.0 14.0 21.0 22.0 23.0 24.0 31.0 32.0 33.0 34.0 % cc -o arr2 arr2.c % arr2 < arr.txt 1.0 2.0 3.0 4.0 11.0 12.0 13.0 14.0 21.0 22.0 23.0 24.0 |
Items to insert | Diagram of array |
---|---|
"rat", with hash("rat") == 8 "cat", with hash("cat") == 10 "dog", with hash("dog") == 8 "pig", with hash("pig") == 9 "cow", with hash("cow") == 0 "bat", with hash("bat") == 0 | h[0] ---> "pig" h[1] ---> "cow" h[2] ---> "bat" h[3] ---> NULL h[4] ---> NULL h[5] ---> NULL h[6] ---> NULL h[7] ---> NULL h[8] ---> "rat" h[9] ---> "dog" h[10]---> "cat" |
Instead one can use a special entry in h[0]. It can be anything at all (such as -1 or a pointer to a string that is never used as a legitimate entry). The software interprets this entry as "deleted", and skips over it in searches. (Actually, a "deleted" entry could be used for insertions.)
One could recreate the hash table to eliminate "deleted" entries. There is a clever algorithm (not presented in the course), that rearranged entries in a minimal way on deletions, so that no "deleted" category is needed.
File: adjlist.c | Run of: adjlist |
---|---|
#include <stdio.h> #include <stdlib.h> #include <stdlib.h> #define N 5 struct gnode { int v; int dist; struct gnode *next; }; void adjlist(struct gnode *g[]); void insert(struct gnode *g[], int v1, int v2, int d); int main(void) { struct gnode *g[N]; int i; for (i = 0; i < N; i++) g[i] = NULL; adjlist(g); } void adjlist(struct gnode *g[]) { /* POSSIBLE ADDITIONAL DECLARATION(S) HERE */ /* because of the separate function, none needed */ FILE *edges; int i; int v1, v2, d; for (i = 0; i < N; i++) g[i] = NULL; if ((edges = fopen("edges.dat", "r")) == NULL) { printf("Can't open file: edges.dat\n"); exit(1); } while (fscanf(edges, "%i %i %i", &v1, &v2, &d) != EOF) { /* PUT PART OF YOUR ANSWER HERE */ insert(g, v1, v2, d); } } /* POSSIBLE ADDITIONAL FUNCTION(S) HERE */ void insert(struct gnode *g[], int v1, int v2, int d) { struct gnode *t = (struct gnode *) malloc(sizeof(struct gnode)); t -> v = v2; t -> dist = d; t -> next = g[v1]; g[v1] = t; } void dumpgraph(struct gnode *g[]) { int i; struct gnode *p; for (i = 0; i < N; i++) { printf("g[%i]:", i); p = g[i]; while (p != NULL) { printf("-->(%i,%i)", p -> v, p -> dist); p = p -> next; } printf("-->NULL\n"); } } |
% cat edges.dat 0 1 10 0 3 5 1 2 1 1 3 2 2 4 4 3 1 3 3 2 9 3 4 2 4 0 7 4 2 6 % cc -o adjlist adjlist.c % adjlist g[0]:-->(3,5)-->(1,10)-->NULL g[1]:-->(3,2)-->(2,1)-->NULL g[2]:-->(4,4)-->NULL g[3]:-->(4,2)-->(2,9)-->(1,3)-->NULL g[4]:-->(2,6)-->(0,7)-->NULL |