Solutions#
Lunar lander control#
Solution to Activity 2
air_conditioner = 1;if (...) else ...a > b5success = a > b;
Solution to Activity 3
#include <stdio.h>
int Control(int altitude) {
int thruster = 0;
//// BEGIN SOLUTION
if (altitude > 100)
thruster = 0;
else if (altitude > 0)
thruster = 1;
else
thruster = 0;
//// END SOLUTION
return thruster;
}
void Test(int altitude) {
int thruster = Control(altitude);
int behaviorCorrect = (altitude > 100 && thruster == 0) ||
(altitude <= 100 && altitude > 0 && thruster == 1) ||
(altitude <= 0 && thruster == 0);
char *behaviorCorrectIcon = behaviorCorrect ? "✅" : "❌";
printf("For altitude %3d, your thruster is %d |%s|\n", altitude, thruster,
behaviorCorrectIcon);
}
int main(void) {
Test(150);
Test(100);
Test(50);
Test(0);
Test(-1);
}
Conveyor belt capacity check#
Solution to Activity 8
#include <stdio.h>
const double packageWeightPerMotor = 5.6;
int main(void) {
printf("How many motors are carrying the packages? ");
int motorCount;
scanf("%d", &motorCount);
printf("How many kg of packages do we expect? ");
double packageWeight;
scanf("%lf", &packageWeight);
puts(packageWeight / motorCount <= packageWeightPerMotor
? "Yes! The conveyor belt can carry the packages."
: "No. The conveyor belt cannot carry the packages.");
}
Spare parts inventory assistant#
Solution to Activity 12
int array[];int array;char[] choices = {"black bird", "great tit", "falcon"};char names[] = {"ird", "grea", "con"};int part_ids[]= {3093, -49318, 3092.812};You will get a warning about implicit type conversion of 3092.812.
string names[] = [];1. We need curly brackets 2. `string` does not exist
double intensity[X][Y][Z];
Solution to Activity 19
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Configurable data
#define LINE_SIZE 100
const char *PARTS[] = {"hydraulic pump", "PLC module", "servo motor"};
const char ASSISTANT_GREETING[] =
"Hej. Welcome to the spare parts inventory!\n";
const char ASSISTANT_QUESTION[] = "Which part do you need? ";
const char ASSISTANT_REPLY_POSITIVE[] = "I have got %s here for you 😊. Bye!\n";
const char ASSISTANT_REPLY_NEGATIVE[] =
"I am afraid we don't have any %s in the inventory 😔\n";
const char *USER_QUESTIONS[] = {
"Do you actually have any parts?",
"Is there anything in stock at all?",
};
const char ASSISTANT_REPLY_NUMBER_OF_PARTS[] = "We have %lu part(s)!\n";
// Program logic
bool user_asked_a_question = false;
int main(void) {
printf(ASSISTANT_GREETING);
while (true) { // Program exits through return
printf("%s ", ASSISTANT_QUESTION);
char line[LINE_SIZE];
fgets(line, sizeof line, stdin);
line[strcspn(line, "\n")] = '\0'; // replace newline
// Part check
for (size_t i = 0; i < _Countof PARTS; ++i) {
if (strcmp(PARTS[i], line) == 0) {
printf(ASSISTANT_REPLY_POSITIVE, line);
return EXIT_SUCCESS;
}
}
// Other question check
for (size_t i = 0; i < _Countof(USER_QUESTIONS); ++i) {
if (strcmp(USER_QUESTIONS[i], line) == 0) {
user_asked_a_question = true;
printf(ASSISTANT_REPLY_NUMBER_OF_PARTS, _Countof(PARTS));
for (size_t i = 0; i < _Countof(PARTS); ++i)
puts(PARTS[i]);
break;
}
}
// If it was not a user question, then it must have been a part
if (!user_asked_a_question) {
printf(ASSISTANT_REPLY_NEGATIVE, line);
user_asked_a_question = false;
}
}
}
Rock paper scissors lizard Spock#
Solution to Activity 29 (RPS resolution logic)
#include <stdio.h>
enum { ROCK, PAPER, SCISSORS, SHAPE_COUNT } p1, p2;
const char *SHAPE_STRINGS[] = {"🪨", "️🗒️", "✂️"};
int main() {
for (size_t p1 = 0; p1 < SHAPE_COUNT; ++p1) {
for (size_t p2 = 0; p2 < SHAPE_COUNT; ++p2) {
printf("If p1: %s and p2: %s => ", SHAPE_STRINGS[p1],
SHAPE_STRINGS[p2]);
//// BEGIN SOLUTION
if (p1 == ROCK && p2 == PAPER)
puts("p1 looses.");
else if (p1 == ROCK && p2 == SCISSORS)
puts("p1 wins.");
else if (p1 == PAPER && p2 == ROCK)
puts("p1 wins.");
else if (p1 == PAPER && p2 == SCISSORS)
puts("p1 looses.");
else if (p1 == SCISSORS && p2 == ROCK)
puts("p1 looses.");
else if (p1 == SCISSORS && p2 == PAPER)
puts("p1 wins.");
else
puts("Tie.");
//// END SOLUTION
}
puts("");
}
}
#include <stdio.h>
enum { ROCK, PAPER, SCISSORS, SHAPE_COUNT } p1, p2;
const char *SHAPE_STRINGS[] = {"🪨", "️🗒️", "✂️"};
int main() {
for (size_t p1 = 0; p1 < SHAPE_COUNT; ++p1) {
for (size_t p2 = 0; p2 < SHAPE_COUNT; ++p2) {
printf("If p1: %s and p2: %s => ", SHAPE_STRINGS[p1],
SHAPE_STRINGS[p2]);
//// BEGIN SOLUTION
switch (p1) {
case ROCK:
switch (p2) {
case PAPER:
puts("p1 looses.");
break;
case SCISSORS:
puts("p1 wins.");
break;
default:
puts("Tie.");
}
break;
case PAPER:
switch (p2) {
case ROCK:
puts("p1 wins.");
break;
case SCISSORS:
puts("p1 looses.");
break;
default:
puts("Tie.");
}
break;
case SCISSORS:
switch (p2) {
case ROCK:
puts("p1 looses.");
break;
case PAPER:
puts("p1 wins.");
break;
default:
puts("Tie.");
}
break;
}
//// END SOLUTION
}
puts("");
}
}
#include <stdio.h>
enum { ROCK, PAPER, SCISSORS, SHAPE_COUNT } p1, p2;
const char *SHAPE_STRINGS[] = {"🪨", "️🗒️", "✂️"};
int main() {
for (size_t p1 = 0; p1 < SHAPE_COUNT; ++p1) {
for (size_t p2 = 0; p2 < SHAPE_COUNT; ++p2) {
printf("If p1: %s and p2: %s => ", SHAPE_STRINGS[p1],
SHAPE_STRINGS[p2]);
//// BEGIN SOLUTION
const enum {
W,
L,
T
} resolution_table[][T + 1] = {
{T, L, W},
{W, T, L},
{L, W, T},
}; // (p1, p2, resolution)
switch (resolution_table[p1][p2]) {
case T:
puts("Tie.");
break;
case W:
puts("p1 wins.");
break;
case L:
puts("p1 loses.");
}
//// END SOLUTION
}
puts("");
}
}
Solution to Activity 21 (Flowchart v1 – overview)
flowchart TD
_s(start) -->b[Welcome user and show menu]
b --> c{menu}
c -->|game| s["print *Starting Game*"]
c -->|exit| f[Say goodbye]--> _e
c -->|else| t[Error message]--> c
s --> g[Game] --> _e
_e(end)
Solution to Activity 30 (RPSSL resolution logic using difference between shapes)
#include <stdio.h>
enum { SPOCK, SCISSORS, PAPER, ROCK, LIZARD, SHAPE_COUNT } player1, player2;
const char *SHAPE_STRINGS[] = {"🖖", "✂️", "️🗒️", "🪨", "🦎"};
int main() {
for (size_t player1 = SPOCK; player1 < SHAPE_COUNT; ++player1) {
for (size_t player2 = SPOCK; player2 < SHAPE_COUNT; ++player2) {
printf("If player1: %s and player2: %s => ", SHAPE_STRINGS[player1],
SHAPE_STRINGS[player2]);
//// BEGIN SOLUTION
switch (player2 - player1) {
case 0:
puts("Tie.");
break;
case -4:
case -2:
case 1:
case 3:
puts("Player1 wins.");
break;
default:
puts("Player1 looses.");
}
//// END SOLUTION
}
puts("");
}
}
Refinement for the Game process:
flowchart TD
_s(start)--> w{winning score reached?}
w -->|no| m[ask the player to act]
m --> s[save players input]
s --> m2[generate a random shape]
m2 --> s2[compare shapes]
s2 --> c{outcome}
c -->|Human won| c1[++human_score] --> p
c -->|Agent won| c2[++agent_score] --> p
c -->|"else (tie)"| p
p[announce scores] --> w
w -->|yes| p2[Announce the winner] --> _e
_e(end)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const unsigned WINNING_SCORE = 5;
// String constants
const char WELCOME[] = R"(
Welcome to 🪨 ✂️ 🗒️ 🖖 🦎 !
(s) Single player
(e) Exit
)";
const char SELECT_MENU_ITEM[] = "Select an item: ";
const char SELECT_SHAPE[] = R"(
Select a shape:
0🪨 || 1🦎 || 2✂️ || 3🗒️ || 4🖖 : )";
const char AGENT_PLAYED[] = "Agent: %d\n";
const char STARTING_GAME[] = "Starting game 🎉";
const char EXITING_GAME[] = "Bye 👋";
const char GAME_SHAPE_KEY_DOES_NOT_EXIST[] =
"❌ Shape key %c does not exist. Try again.\n";
const char HUMAN_REPR[] = "👫 Human";
const char AGENT_REPR[] = "🤖 Agent";
const char SCORE_STATUS[] = "👫:🤖 %d:%d\n";
const char MENU_USE_RIGHT_KEYS[] = "Use the keys`s`, or `e`.";
// Datatypes
typedef enum { ROCK, LIZARD, SCISSORS, PAPER, SPOCK, SHAPE_COUNT } shape_t;
int main() {
srand(time(NULL)); // Use another random sequence every time
printf(WELCOME);
int input_char; // for getchar()
// Menu
bool invalid_menu_key_used;
do {
invalid_menu_key_used = false;
printf(SELECT_MENU_ITEM);
switch (input_char = getchar()) {
case 's':
puts(STARTING_GAME);
break;
case 'e':
puts(EXITING_GAME);
return EXIT_SUCCESS;
default:
invalid_menu_key_used = true;
puts(MENU_USE_RIGHT_KEYS);
}
while (getchar() != '\n')
;
} while (invalid_menu_key_used);
// Game
unsigned human_score = 0, agent_score = 0;
while (human_score < WINNING_SCORE && agent_score < WINNING_SCORE) {
shape_t human_shape, agent_shape;
printf(SELECT_SHAPE);
auto input_char = getc(stdin);
human_shape = input_char - '0';
// Go back to 0, so the chars '0', '1', '2' ... correspond to 0, 1, 2 ...
while (getchar() != '\n')
; // Flush \n and other characters
if (human_shape >= SHAPE_COUNT) {
printf(GAME_SHAPE_KEY_DOES_NOT_EXIST, input_char);
continue;
}
agent_shape = rand() % SHAPE_COUNT;
printf(AGENT_PLAYED, agent_shape);
// Resolution
auto difference = (agent_shape - human_shape + SHAPE_COUNT) % SHAPE_COUNT;
if (difference == 0) {
;
} else if (difference <= 2)
++human_score;
else
++agent_score;
printf(SCORE_STATUS, human_score, agent_score);
}
// Announce the winner
printf("%s won!\n", human_score > agent_score ? HUMAN_REPR : AGENT_REPR);
}
Knight’s tour#
Solution to Activity 35 (A shorter tour on a 4x4 board)
Here is a solution with 15 squares generated by ChatGPT after thinking ~40s. It is not a closed-loop, so it applies only to starts from corners.
10 7 12 3
13 4 9 6
8 11 2 15
1 14 5 .
Maze#
Solution to Activity 42 (Meaning of pointer operators)
a == 42*a == 42&a == 42&*b == 42*&b == 42
Output of the last two expressions and repeated dereferencing:
#include <stdio.h>
int main() {
int b = 42;
int *a = &b;
// printf("&*b: %d\n", &*b); ❌ Does not work, `b` must be a pointer
printf("*&b: %d\n", *&b);
// For the curious:
// printf("&&b: %p\n", &(&b));❌ Does not work, `&` expects a variable (an
// lvalue)
// printf("&&b: %p\n", &&b);❌ Does not work, `**` gets the address of a
// label, `b` must be a label
}
*&b: 42
Solution to Activity 41 (Pointing to a collage vs recreating it)
Advantages of 1
Only one poster exists
No synchronization needed
You save space
Each friend must be cautious when they work with the poster. They will be stressed about breaking something.
Disadvantages of 1
Your friends must come to your room
You have to recreate the poster for each friend
Solution to Activity 44 (Pointer arithmetic with char vs int)
If we increment a pointer, then it points to the start of the next data. The start of the next data is dependent on the size, in our case sizeof(int).
So pointer arithmetic scales automatically based on the size of the type.
Solution to Activity 45 (Calculating pointer + n)
address + index * size_of(datatype)
Warning
Following code scales twice: we have to convert the pointer to a number to make it work:
double arr[] = {100.1, 2, 3.43};
double *target_addr(double *base_addr, size_t index) {
return base_addr + index * sizeof(double);
}
Solution to Activity 46 (Pass by address vs value using scalar values and array)
#include <stdio.h>
void set_to_42(int *n) {
//// BEGIN SOLUTION
*n = 42;
//// END SOLUTION
}
void set_to_58(int n) {
//// BEGIN SOLUTION
n = 58;
//// END SOLUTION
}
void set_first_element_to_58(int *arr) { // Same as int arr[]
//// BEGIN SOLUTION
arr[0] = 58;
//// END SOLUTION
}
int main() {
int n;
int arr[10];
// Use the first function
//// BEGIN SOLUTION
set_to_42(&n);
//// END SOLUTION
printf("n: %d\n", n);
// Use the second function
//// BEGIN SOLUTION
set_to_58(n);
//// END SOLUTION
printf("n: %d\n", n);
// Use the third function
//// BEGIN SOLUTION
set_first_element_to_58(arr);
//// END SOLUTION
printf("arr[0]: %d\n", arr[0]);
}
Filter CSV by age#
Solution to Activity 59 (Processing temperature data)
#include <stdio.h>
#include <stdlib.h>
#define LINE_SIZE 20
#define TEMPERATURE_MAX 19
void p1() {
#define LINES_READ 5
auto filename = "temperatures.txt";
auto fp = fopen("temperatures.txt", "r");
if (!fp)
perror("file cannot be opened.");
char line[LINE_SIZE];
for (auto _ = 0; _ < LINES_READ; ++_) {
fgets(line, LINE_SIZE, fp);
fputs(line, stdout);
// same as
// 1. fprintf(stdout, "%s", line);
// 2. puts(line) => puts extra newline
}
fclose(fp);
}
void p2() {
auto fp = fopen("temperatures-today.txt", "w");
fputs("25\n", fp);
fputs("24\n", fp);
fputs("21\n", fp);
fclose(fp);
}
void p3() {
auto fp = fopen("temperatures-today.txt", "a");
fputs("19\n", fp);
fclose(fp);
}
void p4() {
auto fp = fopen("measurements-done.txt", "w");
fclose(fp);
}
void p5() {
auto fpi = fopen("temperatures.txt", "r");
auto fpo = fopen("temperatures-filtered-some.txt", "w");
char line[LINE_SIZE];
for (auto _ = 0; _ < LINES_READ; ++_) {
fgets(line, LINE_SIZE, fpi);
int temp = strtol(line, nullptr, 10);
if (temp > TEMPERATURE_MAX)
fputs(line, fpo);
// or fscanf and then fprintf(fpo, "%i\n", temp);
}
fclose(fpi);
fclose(fpo);
}
void p6() {
auto fpi = fopen("temperatures.txt", "r");
auto fpo = fopen("temperatures-filtered-all.txt", "w");
char line[LINE_SIZE];
while (fgets(line, LINE_SIZE, fpi)) {
fgets(line, LINE_SIZE, fpi);
int temp = strtol(line, nullptr, 10);
if (temp > TEMPERATURE_MAX)
fputs(line, fpo);
}
fclose(fpi);
fclose(fpo);
}
int main() {
p1();
p2();
p3();
p4();
p5();
p6();
}
Solution to Activity 60 (An error in a file processing program)
Using the
call stackor iteratively placing breakpoints from bottom to the top.Looking at the values of variables
Problem:
fpisnullptr, so theFILEstruct does not exist.
fopen returns a nullptr if the file cannot be opened.
perror() is useful for printing the last happened error.
Error handling code:
--- /builds/fpga-lab/c-programming/code-error/file-opening-error.c
+++ /builds/fpga-lab/c-programming/code-error/file-opening-error-with-error-check.c
@@ -1,9 +1,14 @@
#include <stdio.h>
+#include <stdlib.h>
#define LINE_MAX 100
#define FILE_ "data.txt"
int main() {
auto fp = fopen(FILE_, "r");
+ if (!fp) {
+ perror(FILE_ " cannot be opened.");
+ return EXIT_FAILURE;
+ }
char line[LINE_MAX];
fgets(line, LINE_MAX, fp);
puts(line);
Output:
data.txt cannot be opened.: No such file or directory
Data structures#
Solution to Activity 63 (Appropriate data structure for FrankenText)
According to:
#define MAX_WORD_COUNT 15'000 #define MAX_SUCCESSOR_COUNT MAX_WORD_COUNT / 2 char book[] = { #embed "pg84.txt" /// Stores the content of the file as an array of chars. , '\0'}; /// Makes `book` a string. /// Array of tokens registered so far. /// No duplicates are allowed. char *tokens[MAX_WORD_COUNT]; /// `tokens`'s current size size_t tokens_size = 0; /// Array of successor tokens /// One token can have many successor tokens. `succs[x]` corresponds to /// `token[x]`'s successors. /// We store directly tokens instead of token_ids, because we will directly /// print them. If we wanted to delete the book, then it would make more sense /// to store `token_id`s char *succs[MAX_WORD_COUNT][MAX_SUCCESSOR_COUNT]; /// `succs`'s current size size_t succs_sizes[MAX_WORD_COUNT];
bookfile explorer: 448.9 kB
or can be obtained in
Debug Consoleafter starting the program in debugging mode:p sizeof(book)448930 byte
tokens(
MAX_WORD_COUNT) 15,000 pointers = 8 byte (64 bit) * 15,000 = 120,000 byte = 120 kB
succs15,000 * 7,500 pointers = 900,000,000 bytes = 900 MB
succs_sizes15,000 * 8 = 120,000 byte = 120 kB
In total, our program will use about 1 GB of memory. The actual memory usage can be visualized using
htopand searching for the process id. Process id can be found on theDebug Console.This memory is placed mostly on the RAM. OS may put part of the memory to the virtual memory. Typically hard drive is used as virtual memory.
If one program uses large amount of memory, then memory may become scarce. This could make the program self or other programs slower or even stop them.
We could reduce
MAX_WORD_COUNTandMAX_SUCCESSOR_COUNT, but especially the wordtherequires many successors.The largest memory is used by
succs, which we should focus on.In FrankenText, we reserve fixed amount of successors for each word, but most words have probably much less successors than
the. Having dynamic size for each word would decrease the memory consumption.The same idea could be applied also to
tokens.Two viable options and their trade-offs:
Linked list
Arrays that grow in chunks, e.g., each array starts with 16 elements, and grow by 16 elements if needed.
Linked list is good for dynamic scenarios where deletions occur, but is slow to access elements. Dynamically grown arrays are much faster, but do not support deletion in the middle of an array, which we don’t need in FrankenText.
All in all option 2 will be probably the best performance-wise.
Solution to Activity 62 (Implementing a singly linked list)
// TODO this code is not complete. I just copy pasted from the lecture.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
int data;
struct node *next;
} Node;
struct node b, c;
struct node a = {12, &b}, b = {99, &c}, c = {37, nullptr};
struct node *head = &a;
void print_elements() {
auto address = head;
while (address) {
printf("%d ", address->data);
address = address->next;
}
}
void add_first_node(Node **head, int val) {
// Node n = {43, nullptr};
Node *node_ptr = malloc(sizeof(Node));
node_ptr->data = val;
*head = node_ptr;
}
void insert(Node **head, size_t index, Node *nodeptr) {
Node *current = *head;
// for navigating to the node where we want to insert
for (size_t i = 0; i < index; ++i)
current = current->next;
// We insert the node
nodeptr->next = current->next;
current->next = nodeptr;
}
int main() {
print_elements();
Node n = {10, nullptr};
insert(&head, 2, &n);
;
}
Review problems#
Solution to Activity 64 (Suitable datatype for states of a state machine)
all
Solution to Activity 65 (Typical layout of a C program)
included libraries, constants, global variable & function declarations (and initialization & definitions), main, [function definitions]
Definition: we set the type of an identifier and allocate space for the object it represents.
Initialization: the value stored in the storage when a program a starts.
Using
includewe can include functionality implemented by others. Technically#includeincludes the content of a file, i.e., function declarations (and sometimes definitions) in case of a header file.It iterates over the elements of
arrand prints each character; finally a newline at the end.tmpis not meaningfulWhat is
4?int=>size_t, because it is used to iterate over an arrayint ican be directly declared inside theforbelow#includeshould be used on the top of the file. This is a wide convention.
flowchart LR s( ) --> init[i = 0] --> condition{i < array size} --> body[print array i] body --> condition --> n[print newline] --> e( )
Solution to Activity 66 (Flowchart to statement)
1
Solution to Activity 67 (Flowchart to statement 2)
2
Solution to Activity 68 (Implementable flowcharts)
Contains a process that leads to two processing blocks as follows:
flowchart LR s( ) --> body[ ] --> p1[ ] --> e( ) body[ ] --> p2[ ] --> eEven this is possible to implement in C, it is not part of structured programming rules, which only contains (1) sequence (concatenation) (2) selection (branching), and (3) iteration (loops).
Contains a decision that branches to the parent decision as follows:
flowchart LR s( ) --> if1{ } --> if2{ } --> e( ) if2 --> if1 if1 --> eThis can only be implemented with a
goto#include <stdlib.h> int main() { if1: if (rand() % 2) { if (rand() % 2) ; else goto if1; } }
Contains a process that has two output branches as follows:
flowchart LR s( ) --> p1[ ] --> p2[ ] --> e( ) p2 --> p1Output branches are only possible in decisions.
is an
if-elseis an
if-else-if
Solution to Activity 71 (Two dice sum distribution)
Idea for the analytical solution:
The unit occurrences for the sums:
1x 2: 11
2x 3: 12 21
3x 4: 13 22 31
..
6x 7: 16 .. 61
5x 8: 26 35 44 53 62
..
1x 12: 66
Total: 36x units
50000 / 36x should equal to the occurrence count of 2 or 12 in the long run. If we increase the the number of simulation, we will almost reach this number.
// Simulates the distribution of two dice sum
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define THROW_COUNT 50000
#define BIN_COUNT 12 - 2 + 1
/// Sum can be 2 to 12. For each of them we have a bin that counts their
/// occurrences.
/// Convert sum to bin id and vice-versa
size_t sum_to_bin(int sum) { return sum - 2; }
int bin_to_sum(size_t bin) { return bin + 2; }
unsigned dice_sum_occurrences[BIN_COUNT];
int throw_dice() { return rand() % 6 + 1; }
int main() {
srand(time(nullptr));
// Throw dice
for (int i = 0; i < THROW_COUNT; ++i) {
++dice_sum_occurrences[sum_to_bin(throw_dice() + throw_dice())];
asm("nop");
}
// Show results
for (size_t bin = 0; bin < BIN_COUNT; ++bin)
printf("%2d: %4d\n", bin_to_sum(bin), dice_sum_occurrences[bin]);
}
Review problems 2#
Solution to Activity 72 (Substitute words in a dictionary)
// Substitutes strings in the stdin according to a dictionary
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define LINE_SIZE 100
char line_in[LINE_SIZE], line_out[LINE_SIZE];
typedef struct {
char *key;
char *val; // value
} Entry;
Entry dict[] = {
{"imho", "in my humble opinion"},
{"ig", "Instagram"},
{"worried", "😟"},
{"happy", "☺️"},
};
#define KEY_NOT_FOUND SIZE_MAX
size_t key2index(char *key) {
for (size_t i = 0; i < _Countof(dict); ++i)
if (!strcasecmp(key, dict[i].key))
return i;
return KEY_NOT_FOUND;
}
void substitute_if_word_is_in_dict(char *word) {
auto index = key2index(word);
if (index == KEY_NOT_FOUND)
strcat(line_out, word);
else
strcat(line_out, dict[index].val);
strcat(line_out, " ");
}
int main() {
while (fgets(line_in, LINE_SIZE, stdin)) {
if (line_in[0] == '\n')
continue;
*strchr(line_in, '\n') = '\0'; // Replace newline
auto word = strtok(line_in, " ");
substitute_if_word_is_in_dict(word);
while ((word = strtok(nullptr, " "))) {
substitute_if_word_is_in_dict(word);
}
puts(line_out);
line_out[0] = '\0'; // Initialize buffer for next run.
};
}
Solution to Activity 73 (Is there a bug?)
&=>&&.&is a bitwise operation. Iflengthis 2, 4 or even in general, then the result cannot betrue.Correct. For lunch and and dinner, you eat the same
There is no memory reserved for
line.stdout=>stdin.
puts(a > b ? "yes!" : "no!")There is no bug, just the code style is not readable.
putcs should be better in the body of theforloop.
Additional exercises#
Solution to Activity 78 (Fizz buzz)
// Finds the Fizz buzz numbers less than N
#include <stdio.h>
#define N 40
int main() {
for (int i = 0; i < N; ++i) {
if (!(i % 3) && !(i % 5))
printf("Fizz buzz💚, ");
else if (!(i % 3))
printf("Fizz💙, ");
else if (!(i % 5))
printf("Buzz💛, ");
else
printf("%d, ", i);
}
}
Solution to Activity 79 (Is there a bug? (2))
0-indexing,
strlenshould be usedsizeof=>strlen,"a"=>'a'