Last active
June 12, 2024 19:10
-
-
Save soyart/f8f4b4b50a71f7d3fa105ae69f9e10f5 to your computer and use it in GitHub Desktop.
K&R C exercises
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| void unescape(void); | |
| int main(void) | |
| { | |
| printf("knr 1-10\n"); | |
| printf("Unescape special characters\n"); | |
| unescape(); | |
| } | |
| void unescape(void) | |
| { | |
| int c; | |
| c = 0; | |
| while ((c = getchar()) != EOF) { | |
| switch (c) { | |
| case '\t': | |
| putchar('\\'); | |
| putchar('t'); | |
| continue; | |
| case '\b': | |
| putchar('\\'); | |
| putchar('b'); | |
| continue; | |
| case '\\': | |
| putchar('\\'); | |
| putchar('\\'); | |
| continue; | |
| } | |
| putchar(c); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define STATE_OUT 0 | |
| #define STATE_IN 1 | |
| void one_word_per_line(void); | |
| int in_or_out(int); | |
| int main(void) | |
| { | |
| printf("knr 1-12\n"); | |
| printf("Print the input, one word per line\n"); | |
| one_word_per_line(); | |
| } | |
| int in_or_out(int c) | |
| { | |
| switch (c) { | |
| case ' ': | |
| case '\t': | |
| case '\n': | |
| return STATE_OUT; | |
| } | |
| return STATE_IN; | |
| } | |
| void one_word_per_line(void) | |
| { | |
| int c, state; | |
| c = 0; | |
| state = STATE_OUT; | |
| while ((c = getchar()) != EOF) { | |
| if (c == ' ' || c == '\t' || c == '\n') { | |
| if (state == STATE_IN) { | |
| state = STATE_OUT; | |
| putchar('\n'); | |
| } | |
| continue; | |
| } else if (state == STATE_OUT) { | |
| state = STATE_IN; | |
| } | |
| if (state == STATE_IN) { | |
| putchar(c); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| int main(void) | |
| { | |
| int i, j, c; | |
| int histo[256]; | |
| printf("k&r 1-14\n"); | |
| printf("Print a histogram representing frequency of character in the input\n"); | |
| c = 0; | |
| for (i = 0; i < 256; i++) { | |
| histo[i] = 0; | |
| } | |
| while ((c = getchar()) != EOF) { | |
| ++histo[c]; | |
| } | |
| for (i = 1; i < 256; i++) { | |
| printf("%d (%c): ", i, i); | |
| for (int j = 0; j < histo[i]; j++) { | |
| printf("*"); | |
| } | |
| printf("\n"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| int main(void) | |
| { | |
| int i, j, c; | |
| int ndigits[10]; | |
| c = 0; | |
| for (i = 0; i < 10; i++) { | |
| ndigits[i] = 0; | |
| } | |
| while ((c = getchar()) != EOF) { | |
| if (c >= '0' && c <= '9') { | |
| ++ndigits[c - '0']; | |
| } | |
| } | |
| for (i = 0; i < 10; i++) { | |
| printf("%d: ", i); | |
| for (int j = 0; j < ndigits[i]; j++) { | |
| printf("*"); | |
| } | |
| printf("\n"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define MAXLEN 1000 | |
| #define EIGHTY 80 | |
| int get_line(char line[], int limit); | |
| int main(void) | |
| { | |
| int len = 0; | |
| char line[MAXLEN]; | |
| printf("k&r 1-17\n"); | |
| printf("Only print input lines that are longer than 80 characters\n"); | |
| while ((len = get_line(line, MAXLEN)) > 0) { | |
| if (len > EIGHTY) { | |
| printf("%s", line); | |
| } | |
| } | |
| } | |
| int get_line(char line[], int limit) | |
| { | |
| int i; | |
| int c; | |
| for (i = 0; i < limit - 1 && (c = getchar()) != EOF && c != '\n'; i++) { | |
| line[i] = c; | |
| } | |
| if (c == '\n') { | |
| line[i] = c; | |
| i++; | |
| } | |
| line[i] = '\0'; | |
| return i; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define MAXLEN 1000 | |
| int get_line(char line[], int limit); | |
| int main(void) | |
| { | |
| int len = 0; | |
| char line[MAXLEN]; | |
| printf("k&r 1-18\n"); | |
| printf("Remove trailing blanks and tabs, and remove blank lines completely\n"); | |
| while ((len = get_line(line, MAXLEN)) > 0) { | |
| int until = 0; | |
| // We loop from len, which line[len] will have \0 stored from get_line | |
| for (int i = len; i >= 0; i--) { | |
| int c = line[i]; | |
| switch (c) { | |
| case '\0': | |
| case '\n': | |
| case ' ': | |
| case '\t': | |
| continue; | |
| } | |
| until = i; | |
| break; | |
| } | |
| if (until == 0) { | |
| continue; | |
| } | |
| for (int i = 0; i <= until; i++) { | |
| putchar(line[i]); | |
| } | |
| putchar('\n'); | |
| putchar('\0'); | |
| } | |
| } | |
| // If input is "foo\n", then line will be "foo\n\0" of length 4 | |
| // This means that input[4] (5th elem) will be \0 and safe to access | |
| int get_line(char line[], int limit) | |
| { | |
| int i; | |
| int c; | |
| for (i = 0; i < limit - 1 && (c = getchar()) != EOF && c != '\n'; i++) { | |
| line[i] = c; | |
| } | |
| if (c == '\n') { | |
| line[i] = c; | |
| i++; | |
| } | |
| line[i] = '\0'; | |
| return i; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define MAXLEN 1000 | |
| int get_line(char line[], int limit); | |
| int main(void) | |
| { | |
| int len = 0; | |
| char line[MAXLEN]; | |
| printf("k&r 1-19\n"); | |
| printf("Reverse line by line\n"); | |
| while ((len = get_line(line, MAXLEN))) { | |
| for (int i = len; i >= 0; i--) { | |
| int c = line[i]; | |
| switch (c) { | |
| case '\0': | |
| case '\n': | |
| continue; | |
| } | |
| putchar(c); | |
| } | |
| putchar('\n'); | |
| putchar('\0'); | |
| } | |
| } | |
| int get_line(char line[], int limit) | |
| { | |
| int i; | |
| int c; | |
| for (i = 0; i < limit - 1 && (c = getchar()) != EOF && c != '\n'; i++) { | |
| line[i] = c; | |
| } | |
| if (c == '\n') { | |
| line[i] = c; | |
| i++; | |
| } | |
| line[i] = '\0'; | |
| return i; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define TABSZ 8 | |
| int pad_blanks(int count, int tabsz); | |
| int main(void) | |
| { | |
| int len = 0; | |
| int count = 0; | |
| int c; | |
| int spaces; | |
| printf("k&r 1-20\n"); | |
| printf("Detab\n"); | |
| while ((c = getchar()) != EOF) { | |
| // Print every char that's not a tab | |
| if (c != '\t') { | |
| putchar(c); | |
| count++; | |
| } | |
| if (c == '\t') { | |
| spaces = pad_blanks(count, TABSZ); | |
| for (int i = 0; i < spaces; i++) { | |
| putchar(' '); | |
| } | |
| count = 0; | |
| continue; | |
| } | |
| if (c == '\n') { | |
| count = 0; | |
| } | |
| } | |
| } | |
| int pad_blanks(int count, int tabsz) | |
| { | |
| return tabsz - (count % tabsz); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define TABSZ 4 | |
| int main(void) | |
| { | |
| int len = 0; | |
| int c = 0; | |
| int spaces = 0; | |
| printf("k&r 1-21\n"); | |
| printf("Entab\n"); | |
| // tabsz = 4 | |
| // | |
| // foo......bar | |
| // foo-..bar | |
| // bar..baz.... | |
| // bar..baz- | |
| // | |
| // Number of tabs needed = tabsz/spaces | |
| // and number of padding space is tabsz - (count % tabz) | |
| while ((c = getchar()) != EOF) { | |
| // Starts counting | |
| if (c == ' ') { | |
| spaces++; | |
| continue; | |
| } | |
| if (spaces != 0) { | |
| int tabs = 0; | |
| int pads = 0; | |
| tabs = spaces / TABSZ; | |
| pads = spaces % (TABSZ * tabs); | |
| for (int j = 0; j < tabs; j++) { | |
| putchar('\t'); | |
| } | |
| for (int k = 0; k < pads; k++) { | |
| putchar(' '); | |
| } | |
| spaces = 0; | |
| } | |
| putchar(c); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| // Normal code | |
| #define STATE_OK 0 | |
| // In quotes | |
| #define STATE_QUOTE 1 | |
| // In double quotes | |
| #define STATE_DOUBLEQUOTE 2 | |
| // The 1st slash is encountered | |
| #define STATE_SLASH_ENTER 3 | |
| // The 2nd star in this /* comment */ | |
| #define STATE_STAR_EXIT 4 | |
| // The 2nd slash in this /* comment */ | |
| #define STATE_SLASH_EXIT 5 | |
| // This style | |
| #define STATE_COMMENT 6 | |
| /* This style */ | |
| #define STATE_COMMENT_STAR 7 | |
| int next_state(int state, int c); | |
| int main(void) | |
| { | |
| int c = 0; | |
| int prev_char = 0; | |
| int state = STATE_OK; | |
| int prev_state = STATE_OK; | |
| while ((c = getchar()) != EOF) { | |
| state = next_state(state, c); | |
| switch (state) { | |
| case STATE_OK: | |
| // Print the slash in C expr like 1.0/2.0 | |
| if (prev_state == STATE_SLASH_ENTER) { | |
| putchar(prev_char); | |
| } | |
| case STATE_QUOTE: | |
| case STATE_DOUBLEQUOTE: | |
| putchar(c); | |
| } | |
| prev_char = c; | |
| prev_state = state; | |
| } | |
| } | |
| int next_state(int state, int c) | |
| { | |
| switch (state) { | |
| case STATE_OK: | |
| switch (c) { | |
| case '"': | |
| return STATE_DOUBLEQUOTE; | |
| case '\'': | |
| return STATE_QUOTE; | |
| case '/': | |
| return STATE_SLASH_ENTER; | |
| } | |
| break; // breaking from the switch will return unchanged state | |
| case STATE_QUOTE: | |
| switch (c) { | |
| case '\n': | |
| printf("error: found multi-line quotes"); | |
| exit(1); | |
| case '\'': | |
| return STATE_OK; | |
| } | |
| break; | |
| case STATE_DOUBLEQUOTE: | |
| switch (c) { | |
| case '\n': | |
| printf("error: found multi-line double quotes"); | |
| exit(1); | |
| case '"': | |
| return STATE_OK; | |
| } | |
| break; | |
| case STATE_SLASH_ENTER: | |
| switch (c) { | |
| case '/': | |
| return STATE_COMMENT; | |
| case '*': | |
| return STATE_COMMENT_STAR; | |
| } | |
| return STATE_OK; | |
| case STATE_COMMENT: | |
| switch (c) { | |
| case '\n': | |
| return STATE_OK; | |
| } | |
| break; | |
| case STATE_COMMENT_STAR: | |
| switch (c) { | |
| case '*': | |
| return STATE_STAR_EXIT; | |
| } | |
| break; | |
| case STATE_STAR_EXIT: | |
| switch (c) { | |
| case '/': | |
| return STATE_SLASH_EXIT; | |
| } | |
| return STATE_COMMENT_STAR; | |
| case STATE_SLASH_EXIT: | |
| switch (c) { | |
| case '/': | |
| return STATE_SLASH_ENTER; | |
| } | |
| return STATE_OK; | |
| default: | |
| // Unknown state | |
| printf("error: unknown state %d", state); | |
| exit(2); | |
| } | |
| return state; // state unchanged (from break inside the switch) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <ctype.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| long power(long base, long pow); | |
| long htoi(char s[]); | |
| long htoi_0x(char s[]); | |
| long htoi_pow(char s[]); | |
| int main(void) | |
| { | |
| int result, result_pow, result_0x; | |
| char hex[] = "10f"; | |
| char hex_0x[] = "0x10f"; | |
| result = htoi(hex); | |
| result_pow = htoi_pow(hex); | |
| result_0x = htoi_0x(hex_0x); | |
| printf("result: %d\n", result); | |
| printf("result_pow: %d\n", result_pow); | |
| printf("result_0x: %d\n", result_0x); | |
| } | |
| long htoi(char s[]) | |
| { | |
| long result = 0; | |
| long len = strlen(s); | |
| for (int i = 0; i < len; i++) { | |
| char c = s[i]; | |
| int h = 0; // hex value at current position | |
| if (c >= '0' && c <= '9') { | |
| h = c - '0'; | |
| } else if (c >= 'a' && c <= 'f') { | |
| h = c - 'a' + 10; | |
| } else if (c >= 'A' && c <= 'F') { | |
| h = c - 'A' + 10; | |
| } else { | |
| return result; | |
| } | |
| // 89f = 2207 | |
| // = (8 << 4*2) + (9 << 4*1) + (15 << 0) | |
| // | |
| // 891 = 2193 | |
| // = (8 << 4*2) + (9 << 4*1) + (1 << 0) | |
| int pow = len - i - 1; | |
| result += h * (1 << (4 * pow)); | |
| printf("htoi: pos %d, pow %d, result %ld\n", i, pow, result); | |
| } | |
| return result; | |
| } | |
| long htoi_0x(char s[]) | |
| { | |
| long result = 0; | |
| int len = strlen(s); | |
| int maybe_0x = 0; | |
| for (int i = 0; i < len; i++) { | |
| char c = s[i]; | |
| int h = 0; // hex value at current position | |
| if (i == 0 && c == '0') { | |
| maybe_0x = 1; | |
| } | |
| if (maybe_0x && i == 1 && c == 'x') { | |
| result = 0; // discard old result | |
| } | |
| if (c >= '0' && c <= '9') { | |
| h = c - '0'; | |
| } else if (c >= 'a' && c <= 'f') { | |
| h = c - 'a' + 10; | |
| } else if (c >= 'A' && c <= 'F') { | |
| h = c - 'A' + 10; | |
| } else { | |
| if (!maybe_0x) { | |
| return result; | |
| } | |
| maybe_0x = 0; | |
| } | |
| int pow = len - i - 1; | |
| result += h * (1 << (4 * pow)); | |
| printf("htoi_0x: pos %d, pow %d, result %ld\n", i, pow, result); | |
| } | |
| return result; | |
| } | |
| long htoi_pow(char s[]) | |
| { | |
| long result = 0; | |
| long len = strlen(s); | |
| for (int i = 0; i < len; i++) { | |
| char c = s[i]; | |
| int h = 0; | |
| if (c >= '0' && c <= '9') { | |
| h = c - '0'; | |
| } else if (c >= 'a' && c <= 'f') { | |
| h = c - 'a' + 10; | |
| } else if (c >= 'A' && c <= 'F') { | |
| h = c - 'A' + 10; | |
| } else { | |
| return result; | |
| } | |
| int pow = len - i - 1; | |
| long p = power(16, pow); | |
| result += p * h; | |
| printf("htoi_pow: pos %d, pow %d, result %ld\n", i, pow, result); | |
| } | |
| return result; | |
| } | |
| long power(long base, long pow) | |
| { | |
| long result = 1; | |
| for (int i = 0; i < pow; i++) { | |
| result *= base; | |
| } | |
| return result; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| long count(void); | |
| int main(void) | |
| { | |
| long c; | |
| c = 0; | |
| printf("knr 1-8\n"); | |
| printf("Count blanks, tabs, and newlines\n"); | |
| c = count(); | |
| printf("result: %ld\n", c); | |
| } | |
| long count() | |
| { | |
| int c; | |
| long result; | |
| c = 0; | |
| result = 0; | |
| while ((c = getchar()) != EOF) { | |
| switch (c) { | |
| case ' ': | |
| case '\t': | |
| case '\n': | |
| ++result; | |
| } | |
| } | |
| return result; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define STATE_OUT 0 | |
| #define STATE_IN 1 | |
| void copy_and_replace(void); | |
| int in_or_out(int); | |
| int main(void) | |
| { | |
| printf("knr 1-9\n"); | |
| printf("Truncate blanks and tabs to just 1 blank\n"); | |
| copy_and_replace(); | |
| } | |
| int in_or_out(int c) | |
| { | |
| switch (c) { | |
| case ' ': | |
| case '\t': | |
| case '\n': | |
| return STATE_OUT; | |
| } | |
| return STATE_IN; | |
| } | |
| void copy_and_replace(void) | |
| { | |
| int c; | |
| int state, prev_state; | |
| c = 0; | |
| prev_state = state = STATE_OUT; | |
| while ((c = getchar()) != EOF) { | |
| state = in_or_out(c); | |
| if (state == STATE_IN) { | |
| putchar(c); | |
| prev_state = state; | |
| continue; | |
| } | |
| if (state != prev_state) { | |
| putchar(' '); | |
| } | |
| prev_state = state; | |
| } | |
| putchar('\n'); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| // Returns x with the n bits that begin at position p (0 is rightmost) | |
| // set to the rightmost n bits of y, leaving the other bits unchanged. | |
| // | |
| // For simplicity, this exercise uses unsigned ints | |
| unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y); | |
| // Use chars because int is too long to debug | |
| unsigned setbits_debug(unsigned char x, unsigned char p, unsigned char n, unsigned char y); | |
| // Prints n in binary format | |
| void printb(int n); | |
| void printbc(unsigned char n); | |
| // Copied from the book. Used for finding changed bits | |
| unsigned getbits_knr(unsigned x, int p, int n); | |
| int main(void) | |
| { | |
| int pos, n; | |
| pos = 7; | |
| n = 4; | |
| unsigned x = 115U; // 0000 0000 0111 0011 | |
| unsigned y = 74U; // 0000 0000 0100 1010 | |
| // Expected result: 0000 0000 1010 0011 // 163U | |
| unsigned e = 163U; | |
| unsigned result = setbits(x, pos, n, y); | |
| printf("result:\t"); | |
| printb(result); | |
| unsigned ok = result == e; | |
| printf("result ok: %s\n", ok ? "true" : "false"); | |
| if (!ok) { | |
| unsigned result_debug = setbits_debug(x, pos, n, y); | |
| printf("result_debug:\t"); | |
| printb(result_debug); | |
| printf("result_debug ok: %s\n", result_debug == e ? "true" : "false"); | |
| } | |
| unsigned changed = getbits_knr(result, pos, n); | |
| printf("changed bits: "); | |
| printbc(changed); | |
| } | |
| // See setbits_debug | |
| unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y) | |
| { | |
| unsigned shift = p + 1 - n; | |
| unsigned mask = ~0u << n; | |
| return (x & ~(~mask << shift)) | ((y & ~mask) << shift); | |
| } | |
| unsigned setbits_debug(unsigned char x, unsigned char p, unsigned char n, unsigned char y) | |
| { | |
| printf("p: %d\n", p); | |
| printf("n: %d\n", n); | |
| int target = p + 1 - n; | |
| printf("target left shifts: %d\n", target); | |
| printf("x:\t"); | |
| printbc(x); | |
| printf("y:\t"); | |
| printbc(y); | |
| unsigned mask1 = ~0u << n; // leading 1s with n bits of 0s to the right | |
| unsigned mask2 = ~(mask1); // leading 0s with n bits of 1s to the right | |
| unsigned mask3 = mask2 << target; // 1s in target range, the rest is 0s | |
| unsigned mask4 = ~mask3; | |
| printf("mask1:\t"); | |
| printbc(mask1); | |
| printf("mask2:\t"); | |
| printbc(mask2); | |
| printf("mask3:\t"); | |
| printbc(mask3); | |
| printf("mask4:\t"); | |
| printbc(mask4); | |
| y &= mask2; | |
| printf("y = y & mask2 leftmost n bits of y:\t"); | |
| printbc(y); | |
| y <<= target; | |
| printf("y = y << target (moved to target):\t"); | |
| printbc(y); | |
| x &= mask4; | |
| printf("x = x & mask3 (set target to 0s):\t"); | |
| printbc(x); | |
| return x | y; | |
| } | |
| unsigned getbits_knr(unsigned x, int p, int n) | |
| { | |
| // Left clause: shifts x to desired position with leading 0s | |
| // Right clause: creates a ..1111000.., where n is the number of 1s to the right | |
| return (x >> (p + 1 - n)) & ~(~0 << n); | |
| } | |
| void printb(int n) | |
| { | |
| int size = sizeof(n) * 8; | |
| for (int i = size - 1; i >= 0; i--) { | |
| int bit = (n >> i) & 1; | |
| printf("%d", bit); | |
| } | |
| printf("\n"); | |
| } | |
| void printbc(unsigned char n) | |
| { | |
| int size = sizeof(n) * 8; | |
| for (int i = size - 1; i >= 0; i--) { | |
| unsigned char bit = (n >> i) & 1; | |
| printf("%d", bit); | |
| } | |
| printf("\n"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment