├── .gitignore ├── README.md ├── chapter1 ├── README.md ├── ex1-1 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-13 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-2 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-3 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-4 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-5 │ ├── README.md │ ├── solution │ └── solution.c ├── ex1-6 │ ├── README.md │ ├── solution │ └── solution.c └── ex1-7 │ ├── README.md │ ├── solution │ └── solution.c ├── chapter2 ├── README.md ├── ex2-1 │ ├── README.md │ └── solution.c ├── ex2-10 │ ├── README.md │ ├── Solution.c │ └── solution.exe ├── ex2-3 │ ├── README.md │ ├── solution.c │ └── solution.exe └── ex2-8 │ ├── README.md │ ├── Solution.c │ └── solution.exe ├── chapter3 ├── README.md └── ex3-2 │ ├── README.md │ └── solution.c ├── chapter4 ├── README.md ├── ex4-10 │ ├── README.md │ └── solution.c └── ex4-6 │ ├── README.md │ └── solution.c ├── chapter5 └── README.md ├── chapter6 └── README.md ├── chapter7 └── README.md └── chapter8 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The C Programming Language (K&R) Exercises 2 | 3 | This repository contains solutions and exercises from "The C Programming Language" by Brian W. Kernighan and Dennis M. Ritchie (K&R). 4 | 5 | ## Structure 6 | 7 | The repository is organized as follows: 8 | 9 | - `chapter1/` - A Tutorial Introduction 10 | - `chapter2/` - Types, Operators, and Expressions 11 | - `chapter3/` - Control Flow 12 | - `chapter4/` - Functions and Program Structure 13 | - `chapter5/` - Pointers and Arrays 14 | - `chapter6/` - Structures 15 | - `chapter7/` - Input and Output 16 | - `chapter8/` - The UNIX System Interface 17 | 18 | Each chapter directory contains: 19 | - A README.md file describing the chapter's content 20 | - Exercise directories (e.g., `ex1-1/`, `ex1-2/`, etc.) containing the solutions 21 | - Each exercise directory contains: 22 | - `solution.c` - The solution code 23 | - `README.md` - Description of the exercise 24 | 25 | ## How to Use 26 | 27 | 1. Navigate to the chapter you're interested in 28 | 2. Find the exercise you want to work on 29 | 3. Each exercise directory contains both the problem description and solution 30 | 31 | ## Compilation 32 | 33 | To compile any solution, use: 34 | ```bash 35 | gcc solution.c -o solution 36 | ``` 37 | 38 | ## Running 39 | 40 | After compilation, run the program: 41 | ```bash 42 | ./solution 43 | ``` -------------------------------------------------------------------------------- /chapter1/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 1: A Tutorial Introduction 2 | 3 | This chapter introduces the basic elements of C programming through a series of examples and exercises. 4 | 5 | ## Topics Covered 6 | - Getting Started 7 | - Variables and Arithmetic Expressions 8 | - The for statement 9 | - Symbolic Constants 10 | - Character Input and Output 11 | - Arrays 12 | - Functions 13 | - Arguments - Call by Value 14 | - Character Arrays 15 | - External Variables and Scope 16 | 17 | ## Exercises 18 | 1. Run the "hello, world" program on your system. Experiment with leaving out parts of the program, to see what error messages you get. 19 | 2. Experiment to find out what happens when printf's argument string contains \c, where c is some character not listed above. 20 | 3. Modify the temperature conversion program to print a heading above the table. 21 | 4. Write a program to print the corresponding Celsius to Fahrenheit table. 22 | 5. Modify the temperature conversion program to use a function for conversion. 23 | 6. Verify that the expression getchar() != EOF is 0 or 1. 24 | 7. Write a program to print the value of EOF. 25 | 8. Write a program to count blanks, tabs, and newlines. 26 | 9. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank. 27 | 10. Write a program to copy its input to its output, replacing each tab by \t, each backspace by \b, and each backslash by \\\. 28 | 11. Write a program to count lines, words, and characters in input. 29 | 12. Write a program to print its input one word per line. 30 | 13. Write a program to print a histogram of the lengths of words in its input. 31 | 14. Write a program to print a histogram of the frequencies of different characters in its input. 32 | 15. Temperature conversion program with function 33 | 16. Remove trailing blanks and tabs 34 | 17. Remove all comments from a C program 35 | 18. Remove trailing blanks and tabs from each line 36 | 19. Reverse input one line at a time 37 | 20. Replace tabs with spaces 38 | 21. Replace spaces with tabs 39 | 22. Fold long input lines 40 | 23. Remove C comments 41 | 24. Check for rudimentary syntax errors -------------------------------------------------------------------------------- /chapter1/ex1-1/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-1 2 | 3 | Run the "hello, world" program on your system. Experiment with leaving out parts of the program, to see what error messages you get. 4 | 5 | ## Solution 6 | The solution demonstrates the basic "Hello, World" program in C, which is the traditional first program for learning a new programming language. 7 | 8 | ## How to Run 9 | ```bash 10 | gcc solution.c -o solution 11 | ./solution 12 | ``` 13 | 14 | ## Expected Output 15 | ``` 16 | hello, world 17 | ``` -------------------------------------------------------------------------------- /chapter1/ex1-1/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-1/solution -------------------------------------------------------------------------------- /chapter1/ex1-1/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("hello, world\n"); 6 | } 7 | -------------------------------------------------------------------------------- /chapter1/ex1-13/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-2 2 | 3 | Write a program to print a histogram of the lengths of words in its input. It is easy to draw the 4 | histogram with the bars horizontal; a vertical orientation is more challenging. 5 | 6 | ## Solution 7 | The solution demonstrates how a string's length can be calculated and a histogram be built out of it 8 | 9 | ## How to Run 10 | ```bash 11 | gcc solution.c -o solution 12 | ./solution 13 | ``` 14 | 15 | ## Expected Output 16 | The histogram is printed for the words given in the sequences 17 | -------------------------------------------------------------------------------- /chapter1/ex1-13/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-13/solution -------------------------------------------------------------------------------- /chapter1/ex1-13/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define MAX_LIMIT 20 3 | 4 | int main() { 5 | char str[MAX_LIMIT]; 6 | fgets(str, MAX_LIMIT, stdin); 7 | 8 | int w_len[MAX_LIMIT]; 9 | int w_len_idx = 0, temp_len = 0, idx = 0, max_len = 0; 10 | while(str[idx] != '\n') { 11 | if(str[idx] == ' ') { 12 | w_len[w_len_idx++] = temp_len; 13 | temp_len = 0; 14 | } else temp_len++; 15 | max_len = temp_len > max_len ? temp_len : max_len; 16 | idx++; 17 | } 18 | 19 | max_len = temp_len > max_len ? temp_len : max_len; 20 | w_len[w_len_idx++] = temp_len; 21 | 22 | for(int i=0;i 2 | 3 | int main() 4 | { 5 | printf("hello, world\n"); /* \n is valid */ 6 | printf("hello, world\\c is invalid\n"); /* \c is invalid */ 7 | printf("hello, world\\7 is valid\n"); /* \7 is valid (bell) */ 8 | printf("hello, world\\? is valid\n"); /* \? is valid */ 9 | printf("hello, world\\x is invalid\n"); /* \x is invalid */ 10 | } 11 | -------------------------------------------------------------------------------- /chapter1/ex1-3/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-3 2 | 3 | Modify the temperature conversion program to print a heading above the table 4 | 5 | ## Solution 6 | The solution demonstrates how a heading is printed on top of the conversion table. 7 | 8 | ## How to run 9 | ```bash 10 | gcc solution.c -o solution 11 | ./solution 12 | ``` 13 | 14 | ## Expected Output 15 | The temparature conversion table is printed with a heading on top 16 | -------------------------------------------------------------------------------- /chapter1/ex1-3/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-3/solution -------------------------------------------------------------------------------- /chapter1/ex1-3/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* print Farenheit-Celsius table for 4 | * far far = 0, 20, ..., 300 */ 5 | 6 | int main () { 7 | float fahr, celsius; 8 | float lower, upper, step; 9 | 10 | lower = 0; /* lower limit of temperature scale */ 11 | upper = 300; /* upper limit of temperature scale */ 12 | step = 20; /* step size */ 13 | 14 | fahr = lower; 15 | printf("Fahr Celsius\n"); 16 | while (fahr <= upper) { 17 | celsius = (5.0/9.0) * (fahr - 32.0); 18 | printf("%3.0f %6.1f\n", fahr, celsius); 19 | fahr = fahr + step; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter1/ex1-4/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-4 2 | 3 | Write a program to print the corresponding Celsius to Fahrenheit table. 4 | 5 | ## Solution 6 | The solution demonstrates how you can play around with the Fahrenheit-Celsiu 7 | formula and come up with a Celsius-Farenheit formula. 8 | 9 | ## How to Run 10 | ```bash 11 | gcc solution.c -o solution 12 | ./solution 13 | ``` 14 | 15 | ## Expected output 16 | A Celsius-Farenheit table will be printed. 17 | -------------------------------------------------------------------------------- /chapter1/ex1-4/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-4/solution -------------------------------------------------------------------------------- /chapter1/ex1-4/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* print Celsius-Farenheit table for 4 | * cel = 0, 20, ..., 300 */ 5 | 6 | int main() { 7 | float celsius, fahr; 8 | float lower, upper, step; 9 | 10 | lower = 0; 11 | upper = 300; 12 | step = 20; 13 | 14 | celsius = lower; 15 | printf("Celsius Fahr\n"); 16 | while(celsius <= upper) { 17 | fahr = (celsius * 9.0/5.0) + 32; 18 | printf("%3.0f %10.1f\n", celsius, fahr); 19 | celsius = celsius + step; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter1/ex1-5/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-5 2 | 3 | Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0. 4 | 5 | ## Solution 6 | The solution demonstrates how one can change the initialization and the increment step in a for loop so as to print the temperature table in reverse order. 7 | 8 | ## How to Run 9 | ```bash 10 | gcc solution.c -o solution 11 | ./solution 12 | ``` 13 | 14 | ## Expected Output 15 | A Celsius-Fahrenheit table will be printed in the reverse order 16 | -------------------------------------------------------------------------------- /chapter1/ex1-5/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-5/solution -------------------------------------------------------------------------------- /chapter1/ex1-5/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Print Celsius-Fahrenheit table in reverse */ 4 | int main() { 5 | 6 | int celsius; 7 | 8 | printf("Celsius Fahr\n"); 9 | for (celsius = 300; celsius >= 0; celsius = celsius - 20) 10 | printf("%3d %10.1f\n", celsius, (celsius * 9.0/5.0) + 32); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /chapter1/ex1-6/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-6 2 | 3 | Write a program to verify that the expression `getchar() != EOF` is `0` or `1`. 4 | 5 | ## Solution 6 | We assign the variable c with `getchar() != EOF` and print out the value of c so as to know what value it's going to return (`1` or `0`). 7 | 8 | ## Expected output 9 | To get `1` as an output, type any character and press enter.
10 | To get `0` as an output, on Unix/Linux/Mac press `Ctrl + d` and on Windows press `Ctrl + z followed by enter`. These actions will send the `EOF` signal.
11 | * Why is this important? Remeber in our 2nd version of the copy input to output code, we had parenthesis `(c = (getchar()) != EOF)` so our variable c holds our input value and compares it to `EOF`, but without the parenthesis, our variable c holds the comparison of our input value with `EOF` which is terrible since we always want putchar to keep printing our input value until `EOF` is encountered. We want c to hold the value we keyed in, not the result of the character we keyed in with `EOF`. 12 | -------------------------------------------------------------------------------- /chapter1/ex1-6/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-6/solution -------------------------------------------------------------------------------- /chapter1/ex1-6/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* verifying if getchar() != EOF is either 0 or 1 */ 4 | int main() { 5 | int c = getchar() != EOF; 6 | printf("%d\n", c); 7 | } 8 | -------------------------------------------------------------------------------- /chapter1/ex1-7/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1-7 2 | 3 | Write a program to print the value of EOF 4 | 5 | ## Solution 6 | The solution demonstrates how one can print the value of `EOF` 7 | 8 | ## How to Run 9 | ```bash 10 | gcc solution.c -o solution 11 | ./solution 12 | ``` 13 | 14 | ## Expected Output 15 | The value of `EOF` will be printed 16 | -------------------------------------------------------------------------------- /chapter1/ex1-7/solution: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter1/ex1-7/solution -------------------------------------------------------------------------------- /chapter1/ex1-7/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Printing the value of EOF */ 4 | int main() { 5 | 6 | int c = EOF; 7 | 8 | printf("%d\n", c); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /chapter2/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 2: Types, Operators, and Expressions 2 | 3 | This chapter covers the basic building blocks of C programs: variables, constants, data types, and operators. 4 | 5 | ## Topics Covered 6 | - Variable Names 7 | - Data Types and Sizes 8 | - Constants 9 | - Declarations 10 | - Arithmetic Operators 11 | - Relational and Logical Operators 12 | - Type Conversions 13 | - Increment and Decrement Operators 14 | - Bitwise Operators 15 | - Assignment Operators and Expressions 16 | - Conditional Expressions 17 | - Precedence and Order of Evaluation 18 | 19 | ## Exercises 20 | 1. Write a program to determine the ranges of char, short, int, and long variables, both signed and unsigned, by printing appropriate values from standard headers and by direct computation. 21 | 2. Write a loop equivalent to the for loop without using && or ||. 22 | 3. Write the function htoi(s), which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. 23 | 4. Write an alternate version of squeeze(s1, s2) that deletes each character in s1 that matches any character in the string s2. 24 | 5. Write the function any(s1, s2), which returns the first location in the string s1 where any character from the string s2 occurs, or -1 if s1 contains no characters from s2. 25 | 6. Write a function setbits(x, p, n, y) that returns x with the n bits that begin at position p set to the rightmost n bits of y, leaving the other bits unchanged. 26 | 7. Write a function invert(x, p, n) that returns x with the n bits that begin at position p inverted, leaving the others unchanged. 27 | 8. Write a function rightrot(x, n) that returns the value of the integer x rotated to the right by n bit positions. 28 | 9. In a two's complement number system, x &= (x-1) deletes the rightmost 1-bit in x. Explain why. Use this observation to write a faster version of bitcount. 29 | 10. Rewrite the function lower, which converts upper case letters to lower case, using a conditional expression instead of if-else. -------------------------------------------------------------------------------- /chapter2/ex2-1/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 2-1 2 | 3 | **Print ranges of C data types using headers and bitwise computation** 4 | 5 | ## Description 6 | 7 | This program prints the minimum and maximum values of C's `char`, `short`, `int`, `long`, and `long long` types (both signed and unsigned). It uses two methods: 8 | 9 | 1. **Standard Headers**: Values from `` (e.g., `INT_MAX`). 10 | 2. **Direct Computation**: Bitwise operations to calculate ranges manually. 11 | 12 | --- 13 | 14 | ## Usage 15 | 16 | 1. **Compile**: 17 | ```bash 18 | gcc solution.c -o solution 19 | ``` 20 | 2. **RUN** 21 | 22 | ```bash 23 | ./solution 24 | ``` 25 | 26 | ## Expected Output 27 | 28 | ```bash 29 | Ranges from 30 | signed char: -128 to 127 31 | unsigned char: 0 to 255 32 | signed short: -32768 to 32767 33 | unsigned short: 0 to 65535 34 | signed int: -2147483648 to 2147483647 35 | unsigned int: 0 to 4294967295 36 | signed long: -9223372036854775808 to 9223372036854775807 37 | unsigned long: 0 to 18446744073709551615 38 | signed long long: -9223372036854775808 to 9223372036854775807 39 | Unsigned long long: 0 to 18446744073709551615 40 | 41 | Computed Ranges 42 | signed char: -128 to 127 43 | unsigned char: 0 to 255 44 | ... 45 | ``` 46 | -------------------------------------------------------------------------------- /chapter2/ex2-1/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | // Print ranges from standard headers 6 | printf("Ranges from \n"); 7 | printf("signed char: %d to %d\n", SCHAR_MIN, SCHAR_MAX); 8 | printf("unsigned char: 0 to %u\n", UCHAR_MAX); 9 | printf("signed short: %d to %d\n", SHRT_MIN, SHRT_MAX); 10 | printf("unsigned short: 0 to %u\n", USHRT_MAX); 11 | printf("signed int: %d to %d\n", INT_MIN, INT_MAX); 12 | printf("unsigned int: 0 to %u\n", UINT_MAX); 13 | printf("signed long: %ld to %ld\n", LONG_MIN, LONG_MAX); 14 | printf("unsigned long: 0 to %lu\n", ULONG_MAX); 15 | printf("signed long long: %lld to %lld\n", LLONG_MIN, LLONG_MAX); 16 | printf("Unsigned long long: 0 to %llu\n\n", ULLONG_MAX); 17 | 18 | // Compute ranges directly 19 | printf("Computed Ranges\n"); 20 | 21 | // Signed char 22 | unsigned char uc_max = (unsigned char)-1; 23 | signed char c_max = (signed char)(uc_max >> 1); 24 | printf("signed char: %d to %d\n", -((int)c_max + 1), c_max); 25 | 26 | // Unsigned char 27 | printf("unsigned char: 0 to %u\n", uc_max); 28 | 29 | // Signed short 30 | unsigned short us_max = (unsigned short)-1; 31 | signed short s_max = (signed short)(us_max >> 1); 32 | printf("signed short: %d to %d\n", -((int)s_max + 1), s_max); 33 | 34 | // Unsigned short 35 | printf("unsigned short: 0 to %u\n", us_max); 36 | 37 | // Signed int 38 | unsigned int ui_max = (unsigned int)-1; 39 | signed int i_max = (signed int)(ui_max >> 1); 40 | printf("signed int: %d to %d\n", -((int)i_max + 1), i_max); 41 | 42 | // Unsigned int 43 | printf("unsigned int: 0 to %u\n", ui_max); 44 | 45 | // Signed long 46 | unsigned long ul_max = (unsigned long)-1; 47 | signed long l_max = (signed long)(ul_max >> 1); 48 | printf("signed long: %ld to %ld\n", -((long)l_max + 1), l_max); 49 | 50 | // Unsigned long 51 | printf("unsigned long: 0 to %lu\n", ul_max); 52 | 53 | // Signed long long 54 | unsigned long long ull_max = (unsigned long long)-1; 55 | signed long long ll_max = (signed long long)(ull_max >> 1); 56 | printf("signed long long: %lld to %lld\n", -((long long)ll_max + 1), ll_max); 57 | 58 | // Unsigned long long 59 | printf("unsigned long long: 0 to %llu\n", ull_max); 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /chapter2/ex2-10/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 2-10 2 | 3 | Rewrite the function lower, which converts upper case letters to lower case, using a conditional expression instead of if-else. 4 | 5 | ## Description 6 | 7 | This program converts the Upper case ASCII Character(A-Z) to Lower Case ASCII Character(a-z). 8 | 9 | ## Compilation 10 | 11 | To compile, use: 12 | 13 | ```bash 14 | gcc solution.c -o solution 15 | ``` 16 | 17 | ## Running 18 | 19 | After compilation, run the program: 20 | 21 | ```bash 22 | ./solution 23 | ``` 24 | 25 | ## Expected Output 26 | 27 | Upper Case Characters will be converted to lowe case. 28 | -------------------------------------------------------------------------------- /chapter2/ex2-10/Solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /*Function Converts Upper Case letter to lower */ 6 | uint8_t lower(uint8_t letter) 7 | { 8 | return ((letter >='A' && letter <= 'Z') ? ((letter-'A') + 'a'):letter); 9 | } 10 | 11 | 12 | int32_t main(void) 13 | { 14 | printf("%c\t", lower('A')); 15 | printf("%c\t", lower('B')); 16 | printf("%c\t", lower('k')); 17 | printf("%c\t", lower('Z')); 18 | printf("%c\t", lower('M')); 19 | printf("%c\t", lower('W')); 20 | printf("%c\t", lower('a')); 21 | 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /chapter2/ex2-10/solution.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter2/ex2-10/solution.exe -------------------------------------------------------------------------------- /chapter2/ex2-3/README.md: -------------------------------------------------------------------------------- 1 | # Exercise2-3: Hexadecimal to Integer Conversion (`htoi`) 2 | 3 | ## Problem Statement 4 | 5 | ## Write a function `htoi(s)` that converts a string of hexadecimal digits (optionally starting with `0x` or `0X`) to its equivalent integer value. 6 | 7 | ## Build & Run 8 | 9 | ### Steps 10 | 11 | 1. **Compile**: 12 | ```bash 13 | gcc solution.c -o solution 14 | ``` 15 | 2. **Execute**: 16 | ```bash 17 | ./solution 18 | ``` 19 | 20 | ### Expected Output 21 | 22 | ``` 23 | 0x1A -> 26 24 | FF -> 255 25 | 0X3C -> 60 26 | 1z -> 1 (Stops at invalid character 'z') 27 | ``` 28 | 29 | --- 30 | 31 | ## Input Format 32 | 33 | The function `htoi` expects: 34 | 35 | - A string containing: 36 | - Optional prefix `0x` or `0X` 37 | - Hexadecimal digits (`0-9`, `a-f`, or `A-F`) 38 | 39 | **Valid Examples**: 40 | 41 | - `"0x1A"`, `"ff"`, `"0X3C"`, `"123"` 42 | 43 | **Invalid Handling**: 44 | 45 | - Non-hex characters (e.g., `'g'`, `'z'`) will terminate conversion early. 46 | - The prefix `0x`/`0X` is optional but must appear at the start if present. 47 | -------------------------------------------------------------------------------- /chapter2/ex2-3/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int32_t htoi(uint8_t *str) 5 | { 6 | int32_t temp=0, index_i, result=0; 7 | index_i=0; 8 | 9 | if((str[index_i]=='0') && \ 10 | (str[index_i+1] == 'x' || str[index_i+1] == 'X')) 11 | { 12 | index_i+=2; 13 | } 14 | while(str[index_i] != 0) //until '\0' 15 | { 16 | 17 | if(str[index_i] >='0' && str[index_i] <= '9') 18 | { 19 | 20 | temp = (str[index_i]-'0'); 21 | 22 | } 23 | else if((str[index_i] >='A' && str[index_i]<='F') || 24 | ((str[index_i] >='a') && (str[index_i]<='f') )) 25 | { 26 | temp = ((str[index_i]-'A') & (~('A' ^ 'a')))+10; 27 | 28 | } 29 | else 30 | { 31 | break; 32 | } 33 | 34 | result = result *16 + temp; //for hex: 16, 35 | index_i++; 36 | } 37 | return result; 38 | } 39 | 40 | 41 | int main(void) { 42 | printf("%d\n", htoi("0x1A")); // Output: 26 43 | printf("%d\n", htoi("FF")); // Output: 255 44 | printf("%d\n", htoi("0X3C")); // Output: 60 45 | printf("%d\n", htoi("1A")); // Output: 26 46 | printf("%d\n", htoi("A")); // Output: 10 47 | printf("%d\n", htoi("0x80000000")); // Output: -2147483648 48 | return 0; 49 | } 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /chapter2/ex2-3/solution.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter2/ex2-3/solution.exe -------------------------------------------------------------------------------- /chapter2/ex2-8/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 2-8 2 | 3 | **Write a function rightrot(x, n) that returns the value of the integer x rotated to the right by n bit positions.** 4 | 5 | ## Description 6 | 7 | This program rotates right n bit position of value x. 8 | 9 | --- 10 | 11 | ## Usage 12 | 13 | 1. **Compile**: 14 | ```bash 15 | gcc solution.c -o solution 16 | ``` 17 | 2. **RUN** 18 | 19 | ```bash 20 | ./solution 21 | ``` 22 | 23 | ## Expected Output 24 | 25 | ```bash 26 | 27 | rightrot(0x5D78A72E, 1) : //0x2EBC5397 28 | 29 | rightrot(0x5D78A72E, 5)) : //0x72EBC539 30 | ``` 31 | -------------------------------------------------------------------------------- /chapter2/ex2-8/Solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | /* functions */ 4 | 5 | 6 | uint32_t rightrot(uint32_t value, uint8_t pos) 7 | { 8 | uint8_t size=0; 9 | uint32_t bits =0; 10 | 11 | size = sizeof(value)*8; 12 | pos = pos % size; 13 | bits = value & (~(~0 << pos)); 14 | 15 | return (value >> pos ) |(bits<<(size-pos)); 16 | 17 | } 18 | 19 | 20 | int32_t main(void) 21 | { 22 | uint32_t value = 0x5D78A72E; 23 | uint8_t pos; 24 | 25 | pos=1; 26 | 27 | printf("%x\n", rightrot(value, pos)); //0x2EBC5397 28 | pos=5; 29 | 30 | printf("%x\n", rightrot(value, pos)); //0x72EBC539 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /chapter2/ex2-8/solution.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C-Community-Hub/C-Basics/6ded14a7dcf1e6aa9117a4d5afaa0aec824e5a84/chapter2/ex2-8/solution.exe -------------------------------------------------------------------------------- /chapter3/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 3: Control Flow 2 | 3 | This chapter covers the control flow statements in C, which determine the order in which program statements are executed. 4 | 5 | ## Topics Covered 6 | - Statements and Blocks 7 | - If-Else 8 | - Else-If 9 | - Switch 10 | - Loops and While 11 | - For 12 | - Do-While 13 | - Break and Continue 14 | - Goto and Labels 15 | 16 | ## Exercises 17 | 1. Our binary search makes two tests inside the loop, when one would suffice and the test inside the loop is expensive. Write a version with only one test inside the loop and measure the difference in run-time. 18 | 2. Write a function escape(s, t) that converts characters like newline and tab into visible escape sequences like \\n and \\t as it copies the string t to s. Use a switch. Write a function for the other direction as well, converting escape sequences into the real characters. 19 | 3. Write a function expand(s1, s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc...xyz in s2. Allow for letters of either case and digits, and be prepared to handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or trailing - is taken literally. 20 | 4. In a two's complement number representation, our version of itoa does not handle the largest negative number, that is, the value of n equal to -(2^(wordsize-1)). Explain why not. Modify it to print that value correctly, regardless of the machine on which it runs. 21 | 5. Write the function itob(n, s, b) that converts the integer n into a base b character representation in the string s. In particular, itob(n, s, 16) formats n as a hexadecimal integer in s. 22 | 6. Write a version of itoa that accepts three arguments instead of two. The third argument is a minimum field width; the converted number must be padded with blanks on the left if necessary to make it wide enough. 23 | 7. Write a function reverse(s) that reverses the character string s 24 | 8. Write a function expand(s1,s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc...xyz in s2 25 | 9. In a two's complement number representation, our version of itoa does not handle the largest negative number. Modify it to print that value correctly 26 | 10. Write the function itob(n,s,b) that converts the integer n into a base b character representation in the string s -------------------------------------------------------------------------------- /chapter3/ex3-2/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 3-2 2 | 3 | Write a function _escape(s,t)_ that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s. Use a switch. Write a function for the other direction as well, converting escape sequences into the real characters. 4 | 5 | 6 | ## Solution 7 | 8 | This solution only handles tab and newline. 9 | It can be extended to handle other nonprintable characters. 10 | 11 | ## How to run 12 | 13 | ```gcc -o solution solution.c``` 14 | 15 | ```./solution``` 16 | 17 | ## Expected output 18 | 19 | t = "\tHello, World\t" 20 | expect s = "\\tHello, World\\t" 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /chapter3/ex3-2/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define N 256 5 | 6 | 7 | void escape(char *s,char *t); 8 | 9 | 10 | int main(void) 11 | { 12 | char t[N] = "\tHello,\n\t\t World\n"; 13 | char s[N] = {0}; 14 | 15 | escape(s,t); 16 | 17 | printf("%s",s); 18 | } 19 | 20 | 21 | void escape(char *s,char *t) 22 | { 23 | 24 | int i= 0, j=0; 25 | size_t len = strlen(t); 26 | 27 | for(; i < len; ++i) 28 | { 29 | switch(t[i]) 30 | { 31 | case '\n': 32 | //0x5c is the ascii code in hex 33 | //for the forward slash '\'. 34 | //Alternatively one could write 35 | //s[j++] = '\\'. 36 | s[j++] = 0x5c;s[j++]='n'; 37 | break; 38 | case '\t': 39 | s[j++] = 0x5c; s[j++]='t'; 40 | break; 41 | default: 42 | s[j++] = t[i]; 43 | break; 44 | }//switch 45 | 46 | }//for 47 | 48 | } 49 | -------------------------------------------------------------------------------- /chapter4/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 4: Functions and Program Structure 2 | 3 | This chapter covers functions, program structure, and the organization of C programs into multiple files. 4 | 5 | ## Topics Covered 6 | - Basics of Functions 7 | - Functions Returning Non-integers 8 | - External Variables 9 | - Scope Rules 10 | - Header Files 11 | - Static Variables 12 | - Register Variables 13 | - Block Structure 14 | - Initialization 15 | - Recursion 16 | - The C Preprocessor 17 | 18 | ## Exercises 19 | 1. Write the function strrindex(s, t), which returns the position of the rightmost occurrence of t in s, or -1 if there is none. 20 | 2. Extend atof to handle scientific notation of the form 123.45e-6. 21 | 3. Given the basic framework, it's straightforward to extend the calculator. Add the modulus (%) operator and provisions for negative numbers. 22 | 4. Add commands to print the top element of the stack without popping, to duplicate it, and to swap the top two elements. Add a command to clear the stack. 23 | 5. Add access to library functions like sin, exp, and pow. See in Appendix B, Section 4. 24 | 6. Add commands for handling variables. (It's easy to provide twenty-six variables with single-letter names.) 25 | 7. Write a routine ungets(s) that will push back an entire string onto the input. Should ungets know about a buffer, or should it use ungetch? 26 | 8. Suppose that there will never be more than one character of pushback. Modify getch and ungetch accordingly. 27 | 9. Our getch and ungetch do not handle a pushed-back EOF correctly. Decide what their properties ought to be if an EOF is pushed back, then implement your design. 28 | 10. An alternate organization uses getline to read an entire input line; this makes getch and ungetch unnecessary. Revise the calculator to use this approach -------------------------------------------------------------------------------- /chapter4/ex4-10/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 4-10 2 | 3 | An alternate organization uses `getline` to read an entire input line; this makes `getch` and `ungetch` unnecessary. Revise the calculator to use this approach. 4 | 5 | ## Description 6 | This program is a revised version of the reverse Polish notation calculator such that it reads entire lines of input rather than one character at a time. 7 | 8 | ## Compilation 9 | 10 | To compile, use: 11 | ```bash 12 | gcc solution.c -o solution 13 | ``` 14 | 15 | ## Running 16 | 17 | After compilation, run the program: 18 | ```bash 19 | ./solution 20 | ``` 21 | -------------------------------------------------------------------------------- /chapter4/ex4-10/solution.c: -------------------------------------------------------------------------------- 1 | /* --- MAIN MODULE --- */ 2 | #include 3 | 4 | #define LINE_SIZE_MAX 100 5 | 6 | char my_getline(char line[], int line_size_max); 7 | void line_calculate(char line[]); 8 | 9 | /* reverse Polish calculator */ 10 | int main(void) 11 | { 12 | char line[LINE_SIZE_MAX]; 13 | 14 | while((my_getline(line, LINE_SIZE_MAX)) > 0) { 15 | line_calculate(line); 16 | } 17 | return 0; 18 | } 19 | 20 | /* read line, return length */ 21 | char my_getline(char line[], int line_size_max) 22 | { 23 | int c, i; 24 | 25 | i = 0; 26 | while (i < line_size_max - 1 && ((c = getchar()) != EOF) && c !='\n') { 27 | line[i++] = c; 28 | } 29 | if (c == '\n') { 30 | line[i] = c; 31 | i++; 32 | } 33 | line[i] = '\0'; 34 | return i; 35 | } 36 | 37 | /* --- CALCULATION MODULE -- */ 38 | #include 39 | #include 40 | 41 | #define TOKEN_SIZE_MAX LINE_SIZE_MAX 42 | #define NUMBER '0' 43 | #define COMMAND '1' 44 | #define FUNCTION '2' 45 | 46 | int line_index = -1; /* indexes the last character that has been read from line */ 47 | double variables[26]; /* stores the values of variables 'A' - 'Z', mapped to indices 0 - 25 */ 48 | double last_printed_value; /* result from the previous expression / line */ 49 | 50 | int token_type_get(char line[], char token[]); 51 | void calc_stack_push(double value); 52 | double calc_stack_pop(void); 53 | void calc_stack_execute_command(char command[]); 54 | void calc_stack_execute_function(char function[]); 55 | 56 | /* compute the expression stored in line */ 57 | void line_calculate(char line[]) 58 | { 59 | int token_type, last_read_value = 0; 60 | double operand; 61 | char token[TOKEN_SIZE_MAX]; /* blank-separated string of characters */ 62 | 63 | while ((token_type = token_type_get(line, token)) != '\0') { /* for each token in the line... */ 64 | switch (token_type) { 65 | case NUMBER: 66 | calc_stack_push(atof(token)); 67 | break; 68 | case '+': 69 | calc_stack_push(calc_stack_pop() + calc_stack_pop()); 70 | break; 71 | case '*': 72 | calc_stack_push(calc_stack_pop() * calc_stack_pop()); 73 | break; 74 | case '-': 75 | operand = calc_stack_pop(); 76 | calc_stack_push(calc_stack_pop() - operand); 77 | break; 78 | case '/': 79 | operand = calc_stack_pop(); 80 | if (operand != 0.0) 81 | calc_stack_push(calc_stack_pop() / operand); 82 | else 83 | printf("error: zero divisor \n"); 84 | break; 85 | case '%': 86 | operand = calc_stack_pop(); 87 | if (operand != 0.0) 88 | calc_stack_push(fmod(calc_stack_pop(), operand)); 89 | else 90 | printf("error: zero divisor\n"); 91 | break; 92 | case '\n': /* end of calc, pop result from stack */ 93 | last_printed_value = calc_stack_pop(); 94 | printf("\t%.8g\n", last_printed_value); 95 | break; 96 | case COMMAND: /* execute a command on the stack */ 97 | calc_stack_execute_command(token); 98 | break; 99 | case FUNCTION: /* evaluate math function on stack value(s) */ 100 | calc_stack_execute_function(token); 101 | break; 102 | case '=': /* assign a value to a variable - expression is in the form: value variable = */ 103 | calc_stack_pop(); 104 | if (last_read_value >= 'A' && last_read_value <= 'Z') { 105 | operand = calc_stack_pop(); 106 | variables[last_read_value - 'A'] = operand; 107 | calc_stack_push(operand); 108 | } 109 | else 110 | printf("error: unknown input\n"); 111 | break; 112 | default: 113 | if (token_type >= 'A' && token_type <= 'Z') { 114 | calc_stack_push(variables[token_type - 'A']); 115 | } else if (token_type == '$') { 116 | calc_stack_push(last_printed_value); 117 | } else { 118 | printf("error: unknown input %s\n", token); 119 | break; 120 | } 121 | } 122 | last_read_value = token_type; 123 | } 124 | line_index = -1; /* reset for next line */ 125 | } 126 | 127 | /* --- INPUT MODULE ---*/ 128 | #include 129 | #include 130 | 131 | int is_command(char candidate[]); 132 | int is_function(char candidate[]); 133 | 134 | /* read a token from line and store into token, return token type */ 135 | int token_type_get(char line[], char token[]) 136 | { 137 | int c, token_index; 138 | 139 | while ((token[0] = c = line[++line_index]) == ' ' || c == '\t') /* skip whitespace */ 140 | ; 141 | token[1] = '\0'; 142 | token_index = 0; 143 | if (!isdigit(c) && c != '.' && c != '-' && !isalpha(c)) 144 | return c; /* not a number, command, function or variable */ 145 | if (isalpha(c)) { /* command, function, or variable */ 146 | while (isalpha(token[++token_index] = c = line[++line_index])) 147 | ; 148 | token[token_index] = '\0'; /* overwrite the non-alphabet char with termination symbol */ 149 | --line_index; /* back off of the char we over-read */ 150 | if (strlen(token) == 1) { 151 | return token[0]; /* may be a variable */ 152 | } else if (is_command(token)) { 153 | return COMMAND; 154 | } else if (is_function(token)) { 155 | return FUNCTION; 156 | } else { 157 | return '?'; /* unknown alphabet */ 158 | } 159 | } 160 | if (c == '-') { /* negative number or subtraction operator */ 161 | if (isdigit(c = line[++line_index]) || c == '.') 162 | token[++token_index] = c; /* negative number */ 163 | else { 164 | --line_index; 165 | return '-'; /* subtraction operator */ 166 | } 167 | } 168 | if (isdigit(c)) /* collect integer portion */ 169 | while (isdigit(token[++token_index] = c = line[++line_index])) 170 | ; 171 | if (c == '.') /* collect fraction portion */ 172 | while(isdigit(token[++token_index] = c = line[++line_index])) 173 | ; 174 | token[token_index] = '\0'; /* overwrite non-digit */ 175 | --line_index; 176 | return NUMBER; 177 | } 178 | 179 | /* --- STACK MODULE --- */ 180 | #define CALC_STACK_SIZE_MAX 100 181 | 182 | double calc_stack[CALC_STACK_SIZE_MAX]; 183 | int calc_stack_position = 0; /* stores the next free position in the stack */ 184 | 185 | /* push value onto the stack */ 186 | void calc_stack_push(double value) 187 | { 188 | if (calc_stack_position < CALC_STACK_SIZE_MAX) 189 | calc_stack[calc_stack_position++] = value; 190 | else 191 | printf("error: stack full, can't push %g\n", value); 192 | } 193 | 194 | /* pop and return value from the stack */ 195 | double calc_stack_pop(void) 196 | { 197 | if (calc_stack_position > 0) 198 | return calc_stack[--calc_stack_position]; 199 | else { 200 | printf("error: stack empty\n"); 201 | return 0.0; 202 | } 203 | } 204 | 205 | /* commands to be executed on the stack */ 206 | #define PEEK "peek" 207 | #define DUPLICATE "duplicate" 208 | #define SWAP "swap" 209 | #define CLEAR "clear" 210 | 211 | /* execute commands on the stack */ 212 | void calc_stack_execute_command(char command[]) 213 | { 214 | double top, second; 215 | 216 | if (strcmp(command, PEEK) == 0) { 217 | if (calc_stack_position > 0) { 218 | printf("peek: %g at the top of the stack\n", calc_stack[calc_stack_position - 1]); 219 | } else 220 | printf("error: can't peek into empty stack\n"); 221 | } else if (strcmp(command, DUPLICATE) == 0) { 222 | if (calc_stack_position > 0) { 223 | top = calc_stack[calc_stack_position - 1]; /* peek into stack */ 224 | calc_stack_push(top); 225 | printf("duplicate: %g duplicated at the top of stack\n", top); 226 | } else 227 | printf("error: can't duplicate top of empty stack\n"); 228 | } else if (strcmp(command, SWAP) == 0) { 229 | if (calc_stack_position > 1) { 230 | top = calc_stack_pop(); 231 | second = calc_stack_pop(); 232 | calc_stack_push(top); 233 | calc_stack_push(second); 234 | printf("swap: swapped %g and %g, %g at top of stack now\n", top, second, second); 235 | } else 236 | printf("error: can't swap when stack has fewer than two elements\n"); 237 | } else if (strcmp(command, CLEAR) == 0) { 238 | calc_stack_position = 0; 239 | printf("clear: cleared stack\n"); 240 | } else { 241 | printf("error: unkown command\n"); 242 | } 243 | } 244 | 245 | /* math functions to be executed on values from the stack */ 246 | #define SIN "sin" 247 | #define EXP "exp" 248 | #define POW "pow" 249 | 250 | /* execute math functions on the values from the stack */ 251 | void calc_stack_execute_function(char function[]) 252 | { 253 | double top, second; 254 | 255 | if (calc_stack_position < 1) { 256 | printf("error: not enough values in calc stack\n"); 257 | return; 258 | } 259 | if (strcmp(function, SIN) == 0) { 260 | top = calc_stack_pop(); 261 | calc_stack_push(sin(top)); 262 | } else if (strcmp(function, EXP) == 0 ) { 263 | top = calc_stack_pop(); 264 | calc_stack_push(exp(top)); 265 | } else if (strcmp(function, POW) == 0) { 266 | if (calc_stack_position > 1) { 267 | top = calc_stack_pop(); 268 | second = calc_stack_pop(); 269 | calc_stack_push(pow(second, top)); 270 | } else 271 | printf("error: not enough values in stack to compute pow\n"); 272 | } else { 273 | printf("error: unkown function\n"); 274 | } 275 | } 276 | 277 | /* returns 1 if candidate is a valid stack command, 0 otherwise */ 278 | int is_command(char candidate[]) 279 | { 280 | return (strcmp(candidate, PEEK) == 0 281 | || strcmp(candidate, DUPLICATE) == 0 282 | || strcmp(candidate, SWAP) == 0 283 | || strcmp(candidate, CLEAR) == 0); 284 | } 285 | 286 | /* returns 1 if candidate is a valid math function, 0 otherwise */ 287 | int is_function(char candidate[]) 288 | { 289 | return (strcmp(candidate, SIN) == 0 290 | || strcmp(candidate, EXP) == 0 291 | || strcmp(candidate, POW) == 0); 292 | } 293 | -------------------------------------------------------------------------------- /chapter4/ex4-6/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 4-6 2 | 3 | Add commands for handling variables. (It's easy to provide twenty six variables with single-letter names.) Add a variable for the most recently printed value. 4 | 5 | ## Description 6 | This program extends the reverse Polish notation calculator from the book, first introduced in exercise 4-3. 7 | 8 | We can assign values to the variables 'A'-'Z' via a command of the form: 9 | ```bash 10 | 3 A = 11 | ``` 12 | 13 | We can also access to the most recently printed value with the '$' variable: 14 | ```bash 15 | $ 3 + 16 | ``` 17 | 18 | ## Compilation 19 | 20 | To compile, use: 21 | ```bash 22 | gcc solution.c -o solution 23 | ``` 24 | 25 | ## Running 26 | 27 | After compilation, run the program: 28 | ```bash 29 | ./solution 30 | ``` 31 | -------------------------------------------------------------------------------- /chapter4/ex4-6/solution.c: -------------------------------------------------------------------------------- 1 | /* --- MAIN MODULE --- */ 2 | #include 3 | #include 4 | #include 5 | 6 | #define TOKEN_SIZE_MAX 100 7 | #define NUMBER '0' 8 | #define COMMAND '1' 9 | #define FUNCTION '2' 10 | 11 | int token_type_get(char token[]); 12 | void calc_stack_push(double value); 13 | double calc_stack_pop(void); 14 | void calc_stack_execute_command(char command[]); 15 | void calc_stack_execute_function(char function[]); 16 | 17 | /* reverse Polish calculator */ 18 | int main(void) 19 | { 20 | int i, token_type, last_read_value = 0; 21 | double operand, last_printed_value; 22 | char token[TOKEN_SIZE_MAX]; /* stores a token parsed from input, split by ' ', '\t', or '\n' */ 23 | double variables[26]; /* stores the values of variables 'A'-'Z', mapped to indices 0-25 */ 24 | 25 | for (i = 0; i < 26; i++) 26 | variables[i] = 0.0; 27 | 28 | while ((token_type = token_type_get(token)) != EOF) { 29 | switch (token_type) { 30 | case NUMBER: 31 | calc_stack_push(atof(token)); 32 | break; 33 | case '+': 34 | calc_stack_push(calc_stack_pop() + calc_stack_pop()); 35 | break; 36 | case '*': 37 | calc_stack_push(calc_stack_pop() * calc_stack_pop()); 38 | break; 39 | case '-': 40 | operand = calc_stack_pop(); 41 | calc_stack_push(calc_stack_pop() - operand); 42 | break; 43 | case '/': 44 | operand = calc_stack_pop(); 45 | if (operand != 0.0) 46 | calc_stack_push(calc_stack_pop() / operand); 47 | else 48 | printf("error: zero divisor \n"); 49 | break; 50 | case '%': 51 | operand = calc_stack_pop(); 52 | if (operand != 0.0) 53 | calc_stack_push(fmod(calc_stack_pop(), operand)); 54 | else 55 | printf("error: zero divisor\n"); 56 | break; 57 | case '\n': /* end of calc, pop result from stack */ 58 | last_printed_value = calc_stack_pop(); 59 | printf("\t%.8g\n", last_printed_value); 60 | break; 61 | case COMMAND: /* execute a command on the stack */ 62 | calc_stack_execute_command(token); 63 | break; 64 | case FUNCTION: /* calculate math function on stack values */ 65 | calc_stack_execute_function(token); 66 | break; 67 | case '=': /* assign a value to a variable - expression is in the form: value variable = */ 68 | calc_stack_pop(); 69 | if (last_read_value >= 'A' && last_read_value <= 'Z') { 70 | operand = calc_stack_pop(); 71 | variables[last_read_value - 'A'] = operand; 72 | calc_stack_push(operand); 73 | } 74 | else 75 | printf("error: unknown input\n"); 76 | break; 77 | default: 78 | if (token_type >= 'A' && token_type <= 'Z') { 79 | calc_stack_push(variables[token_type - 'A']); 80 | } else if (token_type == '$') { 81 | calc_stack_push(last_printed_value); 82 | } else { 83 | printf("error: unknown input %s\n", token); 84 | break; 85 | } 86 | } 87 | last_read_value = token_type; 88 | } 89 | return 0; 90 | } 91 | 92 | /* --- INPUT MODULE --- */ 93 | #include 94 | #include 95 | 96 | int getch(void); 97 | void ungetch(int c); 98 | int is_command(char candidate[]); 99 | int is_function(char candidate[]); 100 | 101 | /* read a token from input and store into token, return token type */ 102 | int token_type_get(char token[]) 103 | { 104 | int i, c; 105 | 106 | while ((token[0] = c = getch()) == ' ' || c == '\t') /* skip whitespace */ 107 | ; 108 | token[1] = '\0'; 109 | i = 0; 110 | if (!isdigit(c) && c != '.' && c != '-' && !isalpha(c)) 111 | return c; /* not a number, command, function or variable */ 112 | if (isalpha(c)) { /* command, function, or variable */ 113 | while (isalpha(token[++i] = c = getch())) 114 | ; 115 | token[i] = '\0'; /* overwrite the non-alphabet char with termination symbol */ 116 | if (c != EOF) 117 | ungetch(c); 118 | if (strlen(token) == 1) { 119 | return token[0]; /* may be a variable */ 120 | } else if (is_command(token)) { 121 | return COMMAND; 122 | } else if (is_function(token)) { 123 | return FUNCTION; 124 | } else { 125 | return '?'; /* unknown alphabet */ 126 | } 127 | } 128 | if (c == '-') { /* negative number or subtraction operator */ 129 | if (isdigit(c = getch()) || c == '.') 130 | token[++i] = c; /* negative number */ 131 | else { 132 | if (c != EOF) 133 | ungetch(c); 134 | return '-'; /* subtraction operator */ 135 | } 136 | } 137 | if (isdigit(c)) /* collect integer portion */ 138 | while (isdigit(token[++i] = c = getch())) 139 | ; 140 | if (c == '.') /* collect fraction portion */ 141 | while(isdigit(token[++i] = c = getch())) 142 | ; 143 | token[i] = '\0'; /* overwrite non-digit */ 144 | if (c != EOF) 145 | ungetch(c); 146 | return NUMBER; 147 | } 148 | 149 | #define BUFFER_SIZE_MAX 100 150 | 151 | char input_buffer[BUFFER_SIZE_MAX]; /* stores chars that we have un-read */ 152 | int input_buffer_position = 0; /* next free position in the buffer */ 153 | 154 | /* get a (posibly un-read/pushed-back) character */ 155 | int getch(void) 156 | { 157 | return (input_buffer_position > 0) ? input_buffer[--input_buffer_position] : getchar(); 158 | } 159 | 160 | /* un-read, push character back onto input */ 161 | void ungetch(int c) 162 | { 163 | if (input_buffer_position < BUFFER_SIZE_MAX) 164 | input_buffer[input_buffer_position++] = c; 165 | else 166 | printf("error: too many characters\n"); 167 | } 168 | 169 | /* --- STACK MODULE --- */ 170 | #define STACK_SIZE_MAX 100 171 | 172 | double calc_stack[STACK_SIZE_MAX]; 173 | int calc_stack_position = 0; /* stores the next free position in the stack */ 174 | 175 | /* push value onto stack */ 176 | void calc_stack_push(double value) 177 | { 178 | if (calc_stack_position < STACK_SIZE_MAX) 179 | calc_stack[calc_stack_position++] = value; 180 | else 181 | printf("error: stack full, can't push %g\n", value); 182 | } 183 | 184 | /* pop and return top value from stack */ 185 | double calc_stack_pop(void) 186 | { 187 | if (calc_stack_position > 0) 188 | return calc_stack[--calc_stack_position]; 189 | else { 190 | printf("error: stack empty\n"); 191 | return 0.0; 192 | } 193 | } 194 | 195 | /* commands to be executed on the stack */ 196 | #define PEEK "peek" 197 | #define DUPLICATE "duplicate" 198 | #define SWAP "swap" 199 | #define CLEAR "clear" 200 | 201 | /* execute commands on the stack */ 202 | void calc_stack_execute_command(char command[]) 203 | { 204 | double top, second; 205 | 206 | if (strcmp(command, PEEK) == 0) { 207 | if (calc_stack_position > 0) { 208 | printf("peek: %g at the top of the stack\n", calc_stack[calc_stack_position - 1]); 209 | } else 210 | printf("error: can't peek into empty stack\n"); 211 | } else if (strcmp(command, DUPLICATE) == 0) { 212 | if (calc_stack_position > 0) { 213 | top = calc_stack[calc_stack_position - 1]; /* peek into stack */ 214 | calc_stack_push(top); 215 | printf("duplicate: %g duplicated at the top of stack\n", top); 216 | } else 217 | printf("error: can't duplicate top of empty stack\n"); 218 | } else if (strcmp(command, SWAP) == 0) { 219 | if (calc_stack_position > 1) { 220 | top = calc_stack_pop(); 221 | second = calc_stack_pop(); 222 | calc_stack_push(top); 223 | calc_stack_push(second); 224 | printf("swap: swapped %g and %g, %g at top of stack now\n", top, second, second); 225 | } else 226 | printf("error: can't swap when stack has fewer than two elements\n"); 227 | } else if (strcmp(command, CLEAR) == 0) { 228 | calc_stack_position = 0; 229 | printf("clear: cleared stack\n"); 230 | } else { 231 | printf("error: unkown command\n"); 232 | } 233 | } 234 | 235 | /* math functions to be executed on values from the stack */ 236 | #define SIN "sin" 237 | #define EXP "exp" 238 | #define POW "pow" 239 | 240 | /* execute math functions on values in the stack */ 241 | void calc_stack_execute_function(char function[]) 242 | { 243 | double top, second; 244 | 245 | if (calc_stack_position < 1) { 246 | printf("error: not enough values in stack\n"); 247 | return; 248 | } 249 | if (strcmp(function, SIN) == 0) { 250 | top = calc_stack_pop(); 251 | calc_stack_push(sin(top)); 252 | } else if (strcmp(function, EXP) == 0 ) { 253 | top = calc_stack_pop(); 254 | calc_stack_push(exp(top)); 255 | } else if (strcmp(function, POW) == 0) { 256 | if (calc_stack_position > 1) { 257 | top = calc_stack_pop(); 258 | second = calc_stack_pop(); 259 | calc_stack_push(pow(second, top)); 260 | } else 261 | printf("error: not enough values in stack to compute pow\n"); 262 | } else { 263 | printf("error: unkown function\n"); 264 | } 265 | } 266 | 267 | /* returns 1 if candidate matches a valid command, 0 otherwise */ 268 | int is_command(char candidate[]) 269 | { 270 | return (strcmp(candidate, PEEK) == 0 271 | || strcmp(candidate, DUPLICATE) == 0 272 | || strcmp(candidate, SWAP) == 0 273 | || strcmp(candidate, CLEAR) == 0); 274 | } 275 | 276 | /* returns 1 if candidate matches a valid function, 0 otherwise */ 277 | int is_function(char candidate[]) 278 | { 279 | return (strcmp(candidate, SIN) == 0 280 | || strcmp(candidate, EXP) == 0 281 | || strcmp(candidate, POW) == 0); 282 | } 283 | -------------------------------------------------------------------------------- /chapter5/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 5: Pointers and Arrays 2 | 3 | This chapter covers pointers and arrays, which are fundamental to C programming and provide powerful ways to manipulate data. 4 | 5 | ## Topics Covered 6 | - Pointers and Addresses 7 | - Pointers and Function Arguments 8 | - Pointers and Arrays 9 | - Address Arithmetic 10 | - Character Pointers and Functions 11 | - Pointer Arrays; Pointers to Pointers 12 | - Multi-dimensional Arrays 13 | - Initialization of Pointer Arrays 14 | - Pointers vs. Multi-dimensional Arrays 15 | - Command-line Arguments 16 | - Pointers to Functions 17 | - Complicated Declarations 18 | 19 | ## Exercises 20 | 1. Write a function getint that gets the next integer from input into a variable provided by the caller. 21 | 2. Write a function getfloat, analogous to getint, that gets the next floating-point number from input into a variable provided by the caller. 22 | 3. Write a pointer version of the function strcat that we showed in Chapter 2. 23 | 4. Write the function strend(s, t), which returns 1 if the string t occurs at the end of the string s, and zero otherwise. 24 | 5. Write versions of the library functions strncpy, strncat, and strncmp, which operate on at most the first n characters of their argument strings. 25 | 6. Write a program that reads a set of lines, sorts them, and prints them in increasing order. 26 | 7. Modify the sort program to handle a -n flag, which indicates that comparisons should be made numerically rather than lexicographically. 27 | 8. Add the -r flag, which indicates sorting in reverse (decreasing) order, to the sort program. 28 | 9. Add the capability to sort on arbitrary fields within lines, rather than the whole line, to the sort program. 29 | 10. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file -------------------------------------------------------------------------------- /chapter6/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 6: Structures 2 | 3 | This chapter covers structures, which allow you to group related variables together under a single name. 4 | 5 | ## Topics Covered 6 | - Basics of Structures 7 | - Structures and Functions 8 | - Arrays of Structures 9 | - Pointers to Structures 10 | - Self-referential Structures 11 | - Table Lookup 12 | - Typedef 13 | - Unions 14 | - Bit-fields 15 | 16 | ## Exercises 17 | 1. Our version of getword does not properly handle underscores, string constants, comments, or preprocessor control lines. Write a better version. 18 | 2. Write a program that reads a C program and prints in alphabetical order each group of variable names that are identical in the first 6 characters, but different somewhere thereafter. Don't count words within strings and comments. 19 | 3. Write a cross-referencer that prints a list of all words in a document, and, for each word, a list of the line numbers on which it occurs. 20 | 4. Write a program that prints the distinct words in its input sorted into decreasing order of frequency of occurrence. Precede each word by its count. 21 | 5. Modify the undcl program so that it does not add redundant parentheses to declarations. 22 | 6. Implement a simple version of the #define processor (i.e., no arguments) suitable for use with C programs, based on the routines of this section. You may also find getch and ungetch helpful. 23 | 7. Write a program that will print arbitrary input in a sensible way. As a minimum, it should print non-graphic characters in octal or hexadecimal according to local custom, and break long text lines. 24 | 8. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. 25 | 9. Functions like isupper can be implemented to save space or to save time. Explore both possibilities. 26 | 10. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. -------------------------------------------------------------------------------- /chapter7/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 7: Input and Output 2 | 3 | This chapter covers input and output operations in C, including file handling and formatted I/O. 4 | 5 | ## Topics Covered 6 | - Standard Input and Output 7 | - Formatted Output - printf 8 | - Variable-length Argument Lists 9 | - Formatted Input - scanf 10 | - File Access 11 | - Error Handling - Stderr and Exit 12 | - Line Input and Output 13 | - Miscellaneous Functions 14 | 15 | ## Exercises 16 | 1. Write a program that converts upper case to lower or lower case to upper, depending on the name it is invoked with, as found in argv[0]. 17 | 2. Write a program that will print arbitrary input in a sensible way. As a minimum, it should print non-graphic characters in octal or hexadecimal according to local custom, and break long text lines. 18 | 3. Modify the pattern-finding program of Chapter 5 to take its input from a set of named files or, if no files are named as arguments, from the standard input. Should the file name be printed when a matching line is found? 19 | 4. Write a program to compare two files, printing the first line where they differ. 20 | 5. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. 21 | 6. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. 22 | 7. Modify the pattern finding program of Chapter 5 to take its input from a set of named files or, if no files are named as arguments, from the standard input. Should the file name be printed when a matching line is found? 23 | 8. Write a program to compare two files, printing the first line where they differ. 24 | 9. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. 25 | 10. Write a program to print a set of files, starting each new one on a new page, with a title and a running page count for each file. -------------------------------------------------------------------------------- /chapter8/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 8: The UNIX System Interface 2 | 3 | This chapter covers the UNIX system interface, including file operations, process control, and memory management. 4 | 5 | ## Topics Covered 6 | - File Descriptors 7 | - Low Level I/O - read and write 8 | - Open, creat, close, unlink 9 | - Random Access - lseek 10 | - Example - An implementation of Fopen and getc 11 | - Example - Listing Directories 12 | - Example - A Storage Allocator 13 | 14 | ## Exercises 15 | 1. Rewrite the program cat from Chapter 7 using read, write, open, and close instead of their standard library equivalents. Perform experiments to determine the relative speeds of the two versions. 16 | 2. Write a program that, given a directory, prints the names of all files in that directory, one per line. 17 | 3. Write a program to compare two files, printing the first line where they differ. 18 | 4. Write a program to print all lines that are longer than 80 characters. 19 | 5. Modify the fsize program to print the other information contained in the inode entry. 20 | 6. Write a program to print a directory tree, showing all files and subdirectories. 21 | 7. Modify the pattern-finding program of Chapter 5 to take its input from a set of named files or, if no files are named as arguments, from the standard input. Should the file name be printed when a matching line is found? 22 | 8. Write a program to print the last 10 lines of a file (like the UNIX tail command). 23 | 9. Write a program to print the longest input line. 24 | 10. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank. --------------------------------------------------------------------------------