summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-02-07 22:20:47 +0000
committerMartin Ashby <martin@ashbysoft.com>2023-02-07 22:20:47 +0000
commitcabe1a14b31edce1a247c367f8e1d7265abec34e (patch)
treee66fd91f6682d084ea8484b1be43bd5631dc7610
parent7fa502ba4e60ce762ab529996c66a1a831cb789f (diff)
downloadlearn-c-cabe1a14b31edce1a247c367f8e1d7265abec34e.tar.gz
learn-c-cabe1a14b31edce1a247c367f8e1d7265abec34e.tar.bz2
learn-c-cabe1a14b31edce1a247c367f8e1d7265abec34e.tar.xz
learn-c-cabe1a14b31edce1a247c367f8e1d7265abec34e.zip
Chapter 5
-rw-r--r--ex1-8.c2
-rw-r--r--ex5-1.c97
-rw-r--r--ex5-3.c20
-rw-r--r--ex5-4.c23
-rw-r--r--ex5-5.c20
-rw-r--r--ex5-7.c111
-rwxr-xr-xrun3
7 files changed, 274 insertions, 2 deletions
diff --git a/ex1-8.c b/ex1-8.c
index 7e8c3bd..3ba90d0 100644
--- a/ex1-8.c
+++ b/ex1-8.c
@@ -32,7 +32,7 @@ static struct res _loop(struct res res) {
} else if (c == '\t') {
res.tb++;
}
- __attribute__((musttail))
+ //__attribute__((musttail))
return _loop(res);
}
diff --git a/ex5-1.c b/ex5-1.c
new file mode 100644
index 0000000..9a43c00
--- /dev/null
+++ b/ex5-1.c
@@ -0,0 +1,97 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define PUSHBACK_MAX 10
+typedef struct {
+ FILE* stream;
+ int pushback[PUSHBACK_MAX];
+ int pushback_ix;
+} StreamWithPushback;
+
+StreamWithPushback swpb_new(FILE* f) {
+ StreamWithPushback ret;
+ ret.stream = f;
+ ret.pushback_ix = 0;
+ for (int i=0; i<PUSHBACK_MAX; i++) {
+ ret.pushback[i] = -1;
+ }
+ return ret;
+}
+
+int getch(StreamWithPushback* swpb) {
+ if (swpb->pushback_ix > 0) {
+ int ch = swpb->pushback[swpb->pushback_ix];
+ swpb->pushback_ix--;
+ return ch;
+ }
+ return getc(swpb->stream);
+}
+
+void ungetch(StreamWithPushback* swpb, int ch) {
+ if (swpb->pushback_ix >= PUSHBACK_MAX) {
+ fprintf(stderr, "pushback buffer was full!\n");
+ exit(1);
+ }
+ swpb->pushback[swpb->pushback_ix] = ch;
+ swpb->pushback_ix++;
+}
+
+/* getint: get next integer from input into *pn */
+int getint(StreamWithPushback* swpb, int *pn) {
+ int c, sign;
+
+ while (isspace(c = getch(swpb))) {}
+
+ if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
+ ungetch(swpb, c);
+ return 0;
+ }
+
+ sign = (c == '-') ? -1 : 1;
+ if (c == '+' || c == '-') {
+ c = getch(swpb);
+ // If c isn't then a digit, then we don't have a number.
+ if (!isdigit(c)) {
+ ungetch(swpb, c);
+ // Push the sign character back as well, don't consume it
+ ungetch(swpb, sign == -1 ? '-' : '+');
+ return 0;
+ }
+ }
+
+ for (*pn = 0; isdigit(c); c = getch(swpb)) {
+ *pn = 10 * *pn + (c - '0');
+ }
+ *pn *= sign;
+
+ if (c != EOF) {
+ ungetch(swpb, c);
+ }
+ return c;
+}
+
+#ifndef test
+
+int main(void) {
+ int p, x;
+ StreamWithPushback swpb = swpb_new(stdin);
+ while ((x = getint(&swpb, &p)) != EOF) {
+ if (x > 0) {
+ printf("%d\n", p);
+ } else {
+ printf("not a number!\n");
+ }
+ }
+}
+
+#else
+
+#include "CuTest.h"
+
+// I could write unit tests here, using fmemopen
+// instead of reading something off the filesystem.
+
+// But I can't be bothered.
+
+#endif \ No newline at end of file
diff --git a/ex5-3.c b/ex5-3.c
new file mode 100644
index 0000000..826a581
--- /dev/null
+++ b/ex5-3.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+void z_strcat(char* s, char* t) {
+ // Skip to the end of s
+ for (; *s != '\0'; s++) {}
+ // Copy over t
+ for (; *t != '\0'; t++, s++) {
+ *s = *t;
+ }
+ // Ensure null terminator
+ *s = '\0';
+}
+
+int main(void) {
+ char buf[100] = "";
+ z_strcat(buf, "foo");
+ printf("%s\n", buf);
+ z_strcat(buf, "bar");
+ printf("%s\n", buf);
+} \ No newline at end of file
diff --git a/ex5-4.c b/ex5-4.c
new file mode 100644
index 0000000..d32e965
--- /dev/null
+++ b/ex5-4.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+int strend(char* const s, char* const t) {
+ char* s_p = s;
+ char* t_p = t;
+ for (; *s_p != '\0'; s_p++);
+ for (; *t_p != '\0'; t_p++);
+ for (; !(s_p == s || t_p == t); s_p--, t_p--) {
+ if (*s_p != *t_p) {
+ return 0;
+ }
+ }
+ return t_p == t;
+}
+
+int main(void) {
+ printf("0==%d\n", strend("foo", "bar"));
+ printf("1==%d\n", strend("foo", "foo"));
+ printf("1==%d\n", strend("xyzfoo", "foo"));
+ printf("0==%d\n", strend("foo", "xyzfoo"));
+ printf("1==%d\n", strend("foo", ""));
+ printf("1==%d\n", strend("", ""));
+} \ No newline at end of file
diff --git a/ex5-5.c b/ex5-5.c
new file mode 100644
index 0000000..a6af275
--- /dev/null
+++ b/ex5-5.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+char* z_strncpy(char *dest, char *src, size_t n) {
+ char* max = dest + n;
+ for (; *src != '\0' && dest < max; dest++, src++) {
+ *dest = *src;
+ }
+ for (; dest < max; dest++) {
+ *dest = '\0';
+ }
+ return dest;
+}
+
+int main(void) {
+ char buf[100] = "";
+ z_strncpy(buf, "Hello, World", 5);
+ printf("Hello = %s\n", buf);
+ z_strncpy(buf, "Hello, World", 20);
+ printf("Hello, World = [%s]\n", buf);
+} \ No newline at end of file
diff --git a/ex5-7.c b/ex5-7.c
new file mode 100644
index 0000000..2d277ad
--- /dev/null
+++ b/ex5-7.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <string.h>
+
+// An extremely simple allocation system.
+// Memory must be freed in the reverse order it was allocated.
+#define ALLOCSIZE 10000
+
+static char allocbuf[ALLOCSIZE];
+static char *allocp = allocbuf;
+
+char *alloc(int n) {
+ if (allocbuf + ALLOCSIZE - allocp >= n) {
+ allocp += n;
+ return allocp - n;
+ } else {
+ return NULL;
+ }
+}
+
+void afree(char *p) {
+ if (p >= allocbuf && p < allocbuf + ALLOCSIZE) {
+ allocp = p;
+ }
+}
+
+#define MAXLINES 5000
+
+int readlines(char* lineptr[], int nlines);
+
+void writelines(char* lineptr[], int nlines);
+
+void qsort(char* lineptr[], int left, int right);
+
+int main() {
+ int nlines;
+ char* lineptr[MAXLINES];
+ if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
+ qsort(lineptr, 0, nlines-1);
+ writelines(lineptr, nlines);
+ return 0;
+ } else {
+ fprintf(stderr, "error: input too big to sort\n");
+ return 1;
+ }
+}
+
+#define MAXLEN 1000
+
+int z_getline(char*, int);
+char* alloc(int);
+
+int readlines(char* lineptr[], int maxlines) {
+ int len;
+ int nlines = 0;
+ char* p;
+ char line[MAXLEN];
+ while ((len = z_getline(line, MAXLEN)) > 0) {
+ if (nlines >= maxlines || (p = alloc(len)) == NULL) {
+ return -1;
+ } else {
+ line[len-1] = '\0'; // delete newline
+ strcpy(p, line);
+ lineptr[nlines++] = p;
+ }
+ }
+ return nlines;
+}
+
+void writelines(char* lineptr[], int nlines) {
+ for (int i=0; i<nlines; i++)
+ printf("%s\n", lineptr[i]);
+}
+
+void qsort(char* v[], int left, int right) {
+ int i, last;
+ void swap(char* v[], int i, int j);
+ if (left >= right) {
+ return;
+ }
+ swap(v, left, (left+right)/2);
+ last = left;
+ for (i=left+1; i<=right; i++) {
+ if (strcmp(v[i], v[left]) < 0) {
+ swap(v, ++last, i);
+ }
+ }
+ swap(v, left, last);
+ qsort(v, left, last-1);
+ qsort(v, last+1, right);
+}
+
+void swap(char* v[], int i, int j) {
+ char* temp = v[i];
+ v[i] = v[j];
+ v[j] = temp;
+}
+
+
+/* getline: read a line into s, return length */
+int z_getline(char s[], int lim) {
+ int c, i;
+ for (i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i) {
+ s[i] = c;
+ }
+ if (c == '\n') {
+ s[i] = c;
+ ++i;
+ }
+ s[i] = '\0';
+ return i;
+} \ No newline at end of file
diff --git a/run b/run
index 96e9fac..2efa8b5 100755
--- a/run
+++ b/run
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
-clang -Wall -Werror -o exe $@
+CC=gcc
+${CC} -Wall -Werror -o exe $@
./exe
result=$?
rm exe