Skip to content

Instantly share code, notes, and snippets.

@soyart
Last active June 12, 2024 19:10
Show Gist options
  • Select an option

  • Save soyart/f8f4b4b50a71f7d3fa105ae69f9e10f5 to your computer and use it in GitHub Desktop.

Select an option

Save soyart/f8f4b4b50a71f7d3fa105ae69f9e10f5 to your computer and use it in GitHub Desktop.
K&R C exercises
#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);
}
}
#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);
}
}
}
#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");
}
}
#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");
}
}
#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;
}
#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;
}
#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;
}
#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);
}
#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);
}
}
#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)
}
#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;
}
#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;
}
#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');
}
#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