├── .gitignore ├── LICENSE ├── README.md ├── ch01 ├── 1-10.c ├── 1-12.c ├── 1-13.c ├── 1-16.c ├── 1-17.c ├── 1-18.c ├── 1-19.c ├── 1-20.c ├── 1-21.c ├── 1-23.c ├── 1-3.c ├── 1-4.c ├── 1-5.c ├── 1-8.c └── 1-9.c ├── ch02 ├── 2-1.c ├── 2-10.c ├── 2-3.c ├── 2-4.c ├── 2-5.c ├── 2-6.c ├── 2-7.c ├── 2-8.c └── 2-9.c ├── ch03 ├── 3-2.c ├── 3-3.c ├── 3-4.c ├── 3-5.c └── 3-6.c ├── ch04 ├── 4-1.c ├── 4-12-itoa │ ├── itoa.c │ ├── itoa.h │ ├── itoa.test.c │ └── makefile ├── 4-13-reverse │ ├── makefile │ ├── reverse.c │ ├── reverse.h │ └── reverse.test.c ├── 4-2.c ├── 4-8-getch │ ├── getch.c │ ├── getch.h │ ├── getch.test.c │ └── makefile └── calculator │ ├── getline2.c │ ├── getline2.h │ ├── getop.c │ ├── getop.h │ ├── isnumfmt.c │ ├── isnumfmt.h │ ├── main.c │ ├── makefile │ ├── stack.c │ ├── stack.h │ └── tests │ ├── getline2.input.txt │ ├── getline2.test.c │ ├── getop.test.c │ ├── isnumfmt.test.c │ └── stack.test.c ├── ch05 ├── 5-1-getint │ ├── getch.c │ ├── getch.h │ ├── getint.c │ ├── getint.h │ ├── getint.input.txt │ ├── getint.test.c │ └── makefile ├── 5-10-calculator │ ├── calculate.c │ ├── calculate.h │ ├── isnumfmt.c │ ├── isnumfmt.h │ ├── makefile │ ├── stack.c │ ├── stack.h │ └── tests │ │ ├── calculate.test.c │ │ ├── isnumfmt.test.c │ │ └── stack.test.c ├── 5-11-detab │ ├── detab.c │ ├── detab.h │ ├── detab.input.txt │ ├── entab.c │ ├── entab.h │ ├── entab.input.txt │ ├── main.detab.c │ ├── main.entab.c │ ├── makefile │ ├── settab.c │ ├── settab.h │ ├── tabpos.c │ └── tabpos.h ├── 5-12-detab │ ├── entab.c │ ├── entab.h │ ├── entab.input.txt │ ├── main.c │ ├── makefile │ ├── settab.c │ ├── settab.h │ ├── tabpos.c │ └── tabpos.h ├── 5-13-tail │ ├── input.txt │ ├── makefile │ └── tail.c ├── 5-14-qsort │ ├── cmp.c │ ├── cmp.h │ ├── cmp.test.c │ ├── getlines.c │ ├── getlines.h │ ├── getlines.input.txt │ ├── getlines.test.c │ ├── main.c │ ├── main.input.txt │ ├── makefile │ ├── qsort2.c │ ├── qsort2.h │ ├── qsort2.test.c │ ├── swap.c │ ├── swap.h │ └── swap.test.c ├── 5-18-dcl │ ├── gettoken.c │ ├── gettoken.h │ ├── gettoken.input.txt │ ├── gettoken.test.c │ ├── main.c │ ├── main.input.txt │ ├── makefile │ ├── parse.c │ ├── parse.h │ └── sdt.md ├── 5-2-getfloat │ ├── getfloat.c │ ├── getfloat.h │ ├── getfloat.input.txt │ ├── getfloat.test.c │ └── makefile ├── 5-3-strcat │ ├── makefile │ ├── strcat.c │ ├── strcat.h │ └── strcat.test.c ├── 5-4-strend │ ├── makefile │ ├── strend.c │ ├── strend.h │ └── strend.test.c ├── 5-7-readlines │ ├── alloc.c │ ├── alloc.h │ ├── main.c │ ├── makefile │ ├── qsort.c │ ├── qsort.h │ ├── qsort.test.c │ ├── readlines.c │ ├── readlines.h │ ├── readlines.input.txt │ └── readlines.test.c └── 5-8-monthday │ ├── makefile │ ├── monthday.c │ ├── monthday.h │ └── monthday.test.c ├── ch06 └── 6-5-lookup │ ├── lookup.c │ ├── lookup.h │ ├── lookup.test.c │ └── makefile ├── ch07 ├── 7-3-minprintf │ ├── makefile │ └── minprintf.c └── 7-6-diff │ ├── a.txt │ ├── b.txt │ ├── diff.c │ └── makefile └── key-note ├── init-arr.c ├── init-global.c ├── key-note.md └── scope ├── main.c ├── scope.c └── scope.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | 15 | # Executables 16 | *.exe 17 | *.out 18 | *.app 19 | 20 | .DS_Store 21 | temp.c 22 | *.swp 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Zhouxuan Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The C programming language (Second Edition) exercise answers 2 | # C 程序设计语言(第2版)习题答案 3 | 4 | If it is helpful, please `watch` or `star` this repo. 5 | 6 | Questions and discussion are welcome. 7 | 8 | I'll be very glad if you tell me you have a better idea on some exercise by [issue](https://github.com/fool2fish/the-c-programming-language-exercise-answers/issues/new) or pull request. 9 | 10 | ### Style Guide 11 | 12 | - [LinuxKernelCodingStyle](http://www.maultech.com/chrislott/resources/cstyle/LinuxKernelCodingStyle.txt) 13 | - [GNU Coding Standards](http://www.gnu.org/prep/standards/standards.html) 14 | - [google style guid](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) 15 | - [cstyle](http://www.maultech.com/chrislott/resources/cstyle/) 16 | -------------------------------------------------------------------------------- /ch01/1-10.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-10 3 | * Write a program to copy its input to its output, 4 | * replacing each tab by \t, each backspace by \b, and each backslash by \\. 5 | * This makes tabs and backspaces visible in an unambiguous way. 6 | */ 7 | 8 | #include 9 | 10 | int main() { 11 | char c; 12 | while ((c = getchar()) != EOF) { 13 | if (c == '\t') { 14 | putchar('\\'); 15 | putchar('t'); 16 | } else if (c == '\b') { 17 | putchar('\\'); 18 | putchar('b'); 19 | } else if (c == '\\') { 20 | putchar('\\'); 21 | putchar('\\'); 22 | } else { 23 | putchar(c); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch01/1-12.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-12 3 | * Write a program that prints its input one word per line. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int main() { 10 | int isIn = 0; 11 | char c; 12 | 13 | while ((c = getchar()) != EOF) { 14 | if (isIn) { 15 | if (isspace(c)) { 16 | isIn = 0; 17 | putchar('\n'); 18 | } else { 19 | putchar(c); 20 | } 21 | } else { 22 | if (!isspace(c)) { 23 | isIn = 1; 24 | putchar(c); 25 | } 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /ch01/1-13.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-13. 3 | * Write a program to print a histogram of the lengths of words in its input. 4 | * It is easy to draw the histogram with the bars horizontal; 5 | * a vertical orientation is more challenging. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | void updatecounts(int counts[], int len, int wordlen); 12 | int getpeak(int counts[], int len); 13 | void painth(int counts[], int len); 14 | void paintv(int counts[], int len); 15 | 16 | int main() { 17 | int len = 10; 18 | int counts[len]; 19 | int i; 20 | for (i = 0; i < len; counts[i++] = 0) 21 | ; 22 | 23 | int isIn = 0; 24 | int wordlen = 0; 25 | char c; 26 | while ((c = getchar()) != EOF) { 27 | if (isIn) { 28 | if (isspace(c)) { 29 | updatecounts(counts, len, wordlen); 30 | isIn = 0; 31 | wordlen = 0; 32 | } else { 33 | wordlen++; 34 | } 35 | } else { 36 | if (!isspace(c)) { 37 | isIn = 1; 38 | wordlen = 1; 39 | } 40 | } 41 | } 42 | if (wordlen > 0) 43 | updatecounts(counts, len, wordlen); 44 | 45 | painth(counts, len); 46 | 47 | paintv(counts, len); 48 | } 49 | 50 | void updatecounts(int counts[], int len, int wordlen) { 51 | wordlen = wordlen < len ? wordlen : len; 52 | counts[wordlen - 1]++; 53 | } 54 | 55 | int getpeak(int counts[], int len) { 56 | int peak = 0; 57 | int i; 58 | for (i = 0; i < len; i++) { 59 | peak = peak > counts[i] ? peak : counts[i]; 60 | } 61 | return peak; 62 | } 63 | 64 | void painth(int counts[], int len) { 65 | printf("\nHorizontal histogram:\n\n"); 66 | int peak = getpeak(counts, len); 67 | 68 | int i; 69 | for (i = 0; i < len; i++) { 70 | int barlen = counts[i] * 20 / peak + 1; 71 | char bar[barlen]; 72 | int j; 73 | for (j = 0; j < barlen - 1; j++) { 74 | bar[j] = '+'; 75 | } 76 | bar[j] = '\0'; 77 | 78 | char *format = " %2d: %s %d\n"; 79 | if (i == len - 1) { 80 | format = ">=%2d: %s %d\n"; 81 | } 82 | printf(format, i + 1, bar, counts[i]); 83 | } 84 | } 85 | 86 | void paintv(int counts[], int len) { 87 | printf("\nVertical histogram:\n\n"); 88 | int peak = getpeak(counts, len); 89 | int i, j, h = 20; 90 | 91 | int bars[len]; 92 | for (i = 0; i < len; i++) { 93 | bars[i] = counts[i] * h / peak; 94 | } 95 | 96 | for (i = 0; i <= h; i++) { 97 | for (j = 0; j < len; j++) { 98 | if (h - i == bars[j]) { 99 | printf("%-5d", counts[j]); 100 | } else if (h - i < bars[j]) { 101 | printf("%-5c", '+'); 102 | } else { 103 | printf("%-5c", ' '); 104 | } 105 | } 106 | printf("\n"); 107 | } 108 | 109 | for (i = 0; i < len; i++) { 110 | printf("====="); 111 | } 112 | printf("\n"); 113 | 114 | for (i = 0; i < len; i++) { 115 | char *format = "%-5d"; 116 | if (i == len - 1) { 117 | format = ">=%-5d"; 118 | } 119 | printf(format, i + 1); 120 | } 121 | printf("\n"); 122 | } 123 | -------------------------------------------------------------------------------- /ch01/1-16.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-16 3 | * Revise the main routine of the longest-line program 4 | * so it will correctly print the length of arbitrary long input lines, 5 | * and as much as possible of the text. 6 | */ 7 | 8 | #include 9 | 10 | #define MAXLINE 1000 11 | 12 | int getlinex(char line[], int maxline); 13 | 14 | int main() { 15 | int len; 16 | char line[MAXLINE]; 17 | while ((len = getlinex(line, MAXLINE)) > 0) { 18 | printf("%5d: %s", len, line); 19 | } 20 | } 21 | 22 | int getlinex(char s[], int lim) { 23 | int c, i; 24 | for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++) { 25 | s[i] = c; 26 | } 27 | if (c == '\n') { 28 | s[i] = c; 29 | i++; 30 | } 31 | s[i] = '\0'; 32 | return i; 33 | } 34 | -------------------------------------------------------------------------------- /ch01/1-17.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-17 3 | * Write a program to print all input lines that are longer than 80 characters. 4 | */ 5 | 6 | #include 7 | 8 | #define MAXLINE 1000 9 | 10 | int getlinex(char line[], int maxline); 11 | 12 | int main() { 13 | int len; 14 | char line[MAXLINE]; 15 | while ((len = getlinex(line, MAXLINE)) > 0) { 16 | if (len > 80) { 17 | printf("%s", line); 18 | } 19 | } 20 | } 21 | 22 | int getlinex(char s[], int lim) { 23 | int c, i; 24 | for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++) { 25 | s[i] = c; 26 | } 27 | if (c == '\n') { 28 | s[i] = c; 29 | i++; 30 | } 31 | s[i] = '\0'; 32 | return i; 33 | } 34 | -------------------------------------------------------------------------------- /ch01/1-18.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-18 3 | * Write a program to remove trailing blanks and tabs from each line of input, 4 | * and to delete entirely blank lines. 5 | */ 6 | 7 | #include 8 | 9 | #define MAXLINE 1000 10 | 11 | int getlinex(char line[], int maxline); 12 | void trimr(char line[]); 13 | 14 | int main() { 15 | int len; 16 | char line[MAXLINE]; 17 | while ((len = getlinex(line, MAXLINE)) > 0) { 18 | trimr(line); 19 | if (line[0] != '\n' && line[0] != '\0') { 20 | printf("%s", line); 21 | } 22 | } 23 | } 24 | 25 | int getlinex(char s[], int lim) { 26 | int c, i; 27 | for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++) { 28 | s[i] = c; 29 | } 30 | if (c == '\n') { 31 | s[i] = c; 32 | i++; 33 | } 34 | s[i] = '\0'; 35 | return i; 36 | } 37 | 38 | void trimr(char line[]) { 39 | char c; 40 | int i; 41 | int mark = -1; 42 | for (i = 0; (c = line[i]) != '\n' && c != '\0'; i++) { 43 | if (c == ' ' || c == '\t') { 44 | if (mark == -1) { 45 | mark = i; 46 | } 47 | } else { 48 | mark = -1; 49 | } 50 | } 51 | 52 | if (mark != -1 && i > 0) { 53 | if (line[i] == '\n') { 54 | line[mark++] = '\n'; 55 | } 56 | line[mark] = '\0'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ch01/1-19.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-19 3 | * Write a function reverse(s) that reverses the character string s. 4 | * Use it to write a program that reverses its input a line at a time. 5 | */ 6 | 7 | #include 8 | 9 | #define MAXLEN 1000 10 | 11 | int line(char s[], int maxlen); 12 | void reverse(char s[]); 13 | 14 | int main() { 15 | char s[MAXLEN + 1]; 16 | while (line(s, MAXLEN)) { 17 | reverse(s); 18 | printf("%s", s); 19 | } 20 | } 21 | 22 | int line(char s[], int maxlen) { 23 | char c; 24 | int i; 25 | for (i = 0; (c = getchar()) != EOF && i < maxlen - 1; i++) { 26 | s[i] = c; 27 | if (c == '\n') 28 | break; 29 | } 30 | s[i] = '\0'; 31 | return i; 32 | } 33 | 34 | void reverse(char s[]) { 35 | int len = 0; 36 | for (len = 0; s[len] != '\0'; len++) 37 | ; 38 | 39 | // Not change the last char if it is '\n' 40 | if (len > 0 && (s[len - 1] == '\n')) { 41 | len--; 42 | } 43 | 44 | char temp; 45 | int i; 46 | for (i = 0; i < len / 2; i++) { 47 | int j = len - 1 - i; 48 | temp = s[i]; 49 | s[i] = s[j]; 50 | s[j] = temp; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ch01/1-20.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-20 3 | * Write a program detab that replaces tabs in the input 4 | * with the proper number of blanks to space to the next tab stop. 5 | * Assume a fixed set of tab stops, say every n columns. 6 | * Should n be a variable or a symbolic parameter? 7 | */ 8 | 9 | #include 10 | 11 | #define TABW 8 12 | #define MAXL 1000 13 | 14 | int line(char s[], int lim); 15 | void detab(char src[], char tar[]); 16 | 17 | int main() { 18 | int len; 19 | char s[MAXL]; 20 | char t[MAXL * TABW]; 21 | 22 | printf("Note: for the sake of clarity, all tabs will be replaced with '-'.\n"); 23 | while (line(s, MAXL)) { 24 | detab(s, t); 25 | printf("%s", t); 26 | } 27 | } 28 | 29 | int line(char s[], int lim) { 30 | char c; 31 | int i = 0; 32 | while ((c = getchar()) != EOF && c != '\n' && i < lim - 1) { 33 | s[i++] = c; 34 | } 35 | if (c == '\n') { 36 | s[i++] = '\n'; 37 | } 38 | s[i] = '\0'; 39 | return i; 40 | } 41 | 42 | void detab(char src[], char tar[]) { 43 | int i; 44 | int j = 0; 45 | int spacew; 46 | char c; 47 | for (i = 0; (c = src[i]) != '\0'; i++) { 48 | if (c != '\t') { 49 | tar[j++] = c; 50 | } else { 51 | spacew = TABW - j % TABW; 52 | while (spacew-- > 0) { 53 | tar[j++] = '-'; 54 | } 55 | } 56 | } 57 | tar[j] = '\0'; 58 | } 59 | -------------------------------------------------------------------------------- /ch01/1-21.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-21 3 | * Write a program entab that replaces strings of blanks 4 | * by the minimum number of tabs and blanks to achieve the same spacing. 5 | * Use the same tab stops as for detab. 6 | * When either a tab or a single blank would suffice to reach a tab stop, 7 | * which should be given preference? 8 | */ 9 | 10 | #include 11 | 12 | #define TABW 8 13 | #define MAXL 1000 14 | 15 | int line(char s[], int lim); 16 | void entab(char s[]); 17 | 18 | int main() { 19 | int len; 20 | char s[MAXL]; 21 | 22 | printf("Note: for the sake of clarity, all tabs will be represented by '-'.\n"); 23 | while (line(s, MAXL)) { 24 | entab(s); 25 | printf("%s", s); 26 | } 27 | } 28 | 29 | int line(char s[], int lim) { 30 | char c; 31 | int i = 0; 32 | while ((c = getchar()) != EOF && c != '\n' && i < lim - 1) { 33 | s[i++] = c; 34 | } 35 | if (c == '\n') { 36 | s[i++] = '\n'; 37 | } 38 | s[i] = '\0'; 39 | return i; 40 | } 41 | 42 | void entab(char s[]) { 43 | int i; 44 | int j; 45 | int tp = -1; // position of current char in a tab range 46 | int sp = -1; // start position of tailed space in a tab range, -1 means no tailed space 47 | char c; 48 | for (i = 0, j = 0; (c = s[i]) != '\0'; i++, j++) { 49 | s[j] = c; 50 | 51 | if (c == '\t') { 52 | tp = TABW - 1; 53 | } else { 54 | tp++; 55 | } 56 | 57 | if (c == ' ') { 58 | if (sp == -1) { 59 | sp = tp; 60 | } 61 | } else { 62 | sp = -1; 63 | } 64 | 65 | // reach a tab end 66 | if (tp == TABW - 1) { 67 | // with tailed space 68 | if (sp != -1) { 69 | int spacew = TABW - sp; 70 | j = j - spacew + 1; 71 | s[j] = '-'; 72 | sp = -1; 73 | } 74 | tp = -1; 75 | } 76 | } 77 | s[j] = '\0'; 78 | } 79 | -------------------------------------------------------------------------------- /ch01/1-23.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-23 3 | * Write a program to remove all comments from a C program. 4 | * Don't forget to handle quoted strings and character constants properly. 5 | * C comments don't nest. 6 | */ 7 | 8 | #include 9 | 10 | int main() { 11 | char prevc; 12 | char c; 13 | char nextc; 14 | while ((c = getchar()) != EOF) { 15 | if (c == '"') { 16 | putchar(prevc = c); // print start double quotation mark 17 | while ((c = getchar()) != '"' || prevc == '\\') { 18 | putchar(prevc = c); 19 | } 20 | putchar(prevc = c); // print end double quotation mark 21 | 22 | } else if (c == '/') { 23 | nextc = getchar(); 24 | if (nextc == '/') { 25 | while ((c = getchar()) != '\n') 26 | ; 27 | putchar('\n'); 28 | } else if (nextc == '*') { 29 | prevc = getchar(); 30 | while ((c = getchar()) != '/' || prevc != '*') { 31 | prevc = c; 32 | } 33 | } else { 34 | putchar(c); 35 | putchar(prevc = nextc); 36 | } 37 | 38 | } else { 39 | putchar(prevc = c); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch01/1-3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-3 3 | * Modify the temperature conversion program to print a heading above the table. 4 | */ 5 | 6 | #include 7 | 8 | int fahr2celsius(int degree) { 9 | return 5 * (degree - 32) / 9; 10 | } 11 | 12 | int printFahrList(int start, int end, int step, int withHead) { 13 | if (start <= end && step < 0 || start >= end && step > 0 || step == 0) { 14 | printf("params error!\n"); 15 | return 1; 16 | } 17 | 18 | if (withHead) { 19 | printf("fahr\tcelsius\n"); 20 | } 21 | 22 | int i = start; 23 | while (start <= end ? i <= end : i >= end) { 24 | printf("%d\t%d\n", i, fahr2celsius(i)); 25 | i += step; 26 | } 27 | } 28 | 29 | int main() { 30 | printFahrList(0, 300, 20, 1); 31 | } 32 | -------------------------------------------------------------------------------- /ch01/1-4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-4 3 | * Write a program to print the corresponding Celsius to Fahrenheit table. 4 | */ 5 | 6 | #include 7 | 8 | int celsius2fahr(int degree) { 9 | return degree * 9 / 5 + 32; 10 | } 11 | 12 | int printFahrList(int start, int end, int step, int withHead) { 13 | if (start <= end && step < 0 || start >= end && step > 0 || step == 0) { 14 | printf("params error!\n"); 15 | return 1; 16 | } 17 | 18 | if (withHead) { 19 | printf("celsius\tfahr\n"); 20 | } 21 | 22 | int i = start; 23 | while (start <= end ? i <= end : i >= end) { 24 | printf("%d\t%d\n", i, celsius2fahr(i)); 25 | i += step; 26 | } 27 | } 28 | 29 | int main() { 30 | printFahrList(-17, 148, 11, 1); 31 | } 32 | -------------------------------------------------------------------------------- /ch01/1-5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-5 3 | * Modify the temperature conversion program to print the table in reverse order, 4 | * that is, from 300 degrees to 0. 5 | */ 6 | 7 | #include 8 | 9 | int fahr2celsius(int degree) { 10 | return 5 * (degree - 32) / 9; 11 | } 12 | 13 | int printFahrList(int start, int end, int step, int withHead) { 14 | if (start <= end && step < 0 || start >= end && step > 0 || step == 0) { 15 | printf("params error!\n"); 16 | return 1; 17 | } 18 | 19 | if (withHead) { 20 | printf("fahr\tcelsius\n"); 21 | } 22 | 23 | int i = start; 24 | while (start <= end ? i <= end : i >= end) { 25 | printf("%d\t%d\n", i, fahr2celsius(i)); 26 | i += step; 27 | } 28 | } 29 | 30 | int main() { 31 | printFahrList(300, 0, -20, 1); 32 | } 33 | -------------------------------------------------------------------------------- /ch01/1-8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-8 3 | * Write a program to count blanks, tabs, and newlines. 4 | */ 5 | 6 | #include 7 | 8 | int space = 0; 9 | int tab = 0; 10 | int newline = 0; 11 | 12 | int main() { 13 | int c; 14 | while ((c = getchar()) != EOF) { 15 | switch (c) { 16 | case ' ': 17 | space++; 18 | break; 19 | case '\t': 20 | tab++; 21 | break; 22 | case '\n': 23 | newline++; 24 | break; 25 | default: 26 | break; 27 | } 28 | } 29 | printf("space:%d, tab:%d, newline:%d\n", space, tab, newline); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /ch01/1-9.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 1-9 3 | * Write a program to copy its input to its output, 4 | * replacing each string of one or more blanks by a single blank. 5 | */ 6 | 7 | #include 8 | 9 | int main() { 10 | char prev; 11 | char c; 12 | while ((c = getchar()) != EOF) { 13 | if (c != ' ' || prev != ' ') { 14 | putchar(prev = c); 15 | } 16 | } 17 | 18 | /* 19 | char *s; 20 | int p = 0; 21 | char prev; 22 | char c; 23 | 24 | while((c = getchar()) != EOF) { 25 | if (c != ' ' || prev != ' ') { 26 | *(s + p++) = prev = c; 27 | } 28 | } 29 | 30 | printf("\n%s", s); 31 | */ 32 | } 33 | -------------------------------------------------------------------------------- /ch02/2-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | printf("Unsigned char max: %d\n", UCHAR_MAX); 6 | printf("Signed char max: %d\n", SCHAR_MAX); 7 | printf("Signed char min: %d\n", SCHAR_MIN); 8 | 9 | unsigned int i = ~0; 10 | printf("Unsigned int max: %u\n", i); 11 | printf("Signed int max: %d\n", i / 2); 12 | printf("Signed int min: %d\n", - (i / 2) - 1); 13 | } 14 | -------------------------------------------------------------------------------- /ch02/2-10.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-10 3 | * Rewrite the function lower, which converts upper case letters to lower case, 4 | * with a conditional expression instead of if-else. 5 | */ 6 | 7 | #include 8 | 9 | char lower(char c); 10 | 11 | int main() { 12 | char c; 13 | while ((c = getchar()) != EOF) { 14 | putchar(lower(c)); 15 | } 16 | } 17 | 18 | char lower(char c) { 19 | return 'A' <= c && c <= 'Z' ? c - 'A' + 'a' : c; 20 | } 21 | -------------------------------------------------------------------------------- /ch02/2-3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-3 3 | * Write a function htoi(s), 4 | * which converts a string of hexadecimal digits (including an optional 0x or 0X) 5 | * into its equivalent integer value. 6 | * The allowable digits are 0 through 9, a through f, and A through F. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | int htoi(char s[]); 13 | 14 | int main(int argc, char *argv[]) { 15 | if (argc > 1) { 16 | if (argc != 2) { 17 | printf("Warn: too many args."); 18 | } 19 | printf("%d\n", htoi(argv[1])); 20 | } else { 21 | char s[] = "0xff"; 22 | printf( 23 | "Info: not specified hexadecimal digits, will use default value: %s.\n", 24 | s); 25 | printf("%d\n", htoi(s)); 26 | } 27 | } 28 | 29 | int htoi(char s[]) { 30 | int rt = 0; 31 | int start = 0; 32 | 33 | if (strlen(s) > 2) { 34 | char first = s[0]; 35 | char second = s[1]; 36 | 37 | if (first == '0' && (second == 'x' || second == 'X')) { 38 | start = 2; 39 | } 40 | } 41 | 42 | int i; 43 | char c; 44 | for (i = start; (c = s[i]) != '\0'; i++) { 45 | int v; 46 | if ('0' <= c && c <= '9') { 47 | v = c - '0'; 48 | } else if ('a' <= c && c <= 'f') { 49 | v = 10 + c - 'a'; 50 | } else if ('A' <= c && c <= 'F') { 51 | v = 10 + c - 'A'; 52 | } else { 53 | printf("Error: Illegal hexadecimal digits: %s\n", s); 54 | return 0; 55 | } 56 | rt = rt * 16 + v; 57 | } 58 | return rt; 59 | } 60 | -------------------------------------------------------------------------------- /ch02/2-4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-4 3 | * Write an alternative version of squeeze(s1,s2) 4 | * that deletes each character in s1 that matches any character in the string s2. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #define SIZE 0xff 11 | 12 | void squeeze(char s1[], char s2[]); 13 | 14 | int main() { 15 | char s1[] = "abcdefabcghi"; 16 | char s2[] = "aaabc"; 17 | squeeze(s1, s2); 18 | printf("%s\n", s1); 19 | } 20 | 21 | void squeeze(char s1[], char s2[]){ 22 | char symbol[SIZE] = {}; 23 | int i, j; 24 | 25 | for (i = 0; s2[i] != '\0'; ++i) { 26 | symbol[s2[i]] = 1; 27 | } 28 | 29 | i = j = 0; 30 | 31 | while (s1[i] != '\0') { 32 | while (symbol[s1[i]]) { 33 | i++; 34 | } 35 | s1[j++] = s1[i++]; 36 | } 37 | 38 | s1[j] = '\0'; 39 | } 40 | -------------------------------------------------------------------------------- /ch02/2-5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-5 3 | * Write the function any(s1,s2), 4 | * which returns the first location in a string s1 5 | * where any character from the string s2 occurs, 6 | * or -1 if s1 contains no characters from s2. 7 | * (The standard library function strpbrk does the same job but returns a pointer to the location.) 8 | */ 9 | 10 | #include 11 | 12 | int indexof(char s[], char c); 13 | int any(char s1[], char s2[]); 14 | 15 | 16 | int main() { 17 | printf("any(\"hello fool2fish!\", \"f2f\") -> %d\n", any("hello fool2fish", "f2f")); 18 | printf("any(\"hello fool2fish!\", \"yzx\") -> %d\n", any("hello fool2fish", "yzx")); 19 | } 20 | 21 | 22 | // This is not a effective way. 23 | // We can sort s[] alphabetically and then find c by binary search. 24 | int indexof(char s[], char c) { 25 | int i = 0; 26 | char ch; 27 | while((ch = s[i++]) != '\0') { 28 | if (ch == c) { 29 | return --i; 30 | } 31 | } 32 | return -1; 33 | } 34 | 35 | int any(char s1[], char s2[]) { 36 | int i = 0; 37 | char c; 38 | while ((c = s1[i++]) != '\0') { 39 | int idx = indexof(s2, c); 40 | if (idx != -1) { 41 | return --i; 42 | } 43 | } 44 | return -1; 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /ch02/2-6.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-6 3 | * Write a function setbits(x,p,n,y) 4 | * that returns x with the n bits that begin at position p 5 | * set to the rightmost n bits of y, 6 | * leaving the other bits unchanged. 7 | */ 8 | 9 | #include 10 | 11 | int bitlen(unsigned d); 12 | unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y); 13 | 14 | int main() { 15 | printf("setbits(11, 1, 2, 6) -> %u\n", setbits(11, 1, 2, 6)); 16 | printf("setbits(11, 3, 2, 6) -> %u\n", setbits(11, 3, 2, 6)); 17 | } 18 | 19 | int bitlen(unsigned d) { 20 | int len = 0; 21 | for (; d; d >>= 1) { 22 | len++; 23 | } 24 | return len; 25 | } 26 | 27 | unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y) { 28 | unsigned lenx = bitlen(x); 29 | unsigned leny = bitlen(y); 30 | 31 | if (lenx < p + n || leny < n) { 32 | printf("Error: illegal p<%u> or n<%u>.\n", p, n); 33 | return 0; 34 | 35 | } else { 36 | unsigned tail = lenx - p - n; 37 | unsigned right = x & ~(~0 << tail); 38 | unsigned replacement = y & ~(~0 << n); 39 | x >>= lenx - p; 40 | x <<= n; 41 | x |= replacement; 42 | x <<= tail; 43 | x |= right; 44 | return x; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ch02/2-7.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-7 3 | * Write a function invert(x,p,n) that 4 | * returns x with the n bits that begin at position p inverted 5 | * (i.e., 1 changed into 0 and vice versa), 6 | * leaving the others unchanged. 7 | */ 8 | 9 | #include 10 | 11 | int bitlen(unsigned d); 12 | unsigned invert(unsigned x, unsigned p, unsigned n); 13 | 14 | int main() { 15 | printf("invert(5, 1, 1) -> %u\n", invert(5, 1, 1)); 16 | printf("invert(5, 4, 1) -> %u\n", invert(5, 4, 1)); 17 | } 18 | 19 | int bitlen(unsigned d) { 20 | int len = 0; 21 | for (; d; d >>= 1) { 22 | len++; 23 | } 24 | return len; 25 | } 26 | 27 | unsigned invert(unsigned x, unsigned p, unsigned n) { 28 | int len = bitlen(x); 29 | 30 | if (len < p + n) { 31 | printf("Error: illegal p<%u> or n<%u>.\n", p, n); 32 | return 0; 33 | 34 | } else { 35 | unsigned tail = len - p - n; 36 | unsigned right = x & ~(~0 << tail); 37 | x >>= tail; 38 | x ^= ~(~0 << n); 39 | x <<= tail; 40 | x |= right; 41 | return x; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ch02/2-8.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int bitlen(unsigned d); 4 | unsigned rightrot(unsigned d, unsigned x); 5 | 6 | int main() { 7 | printf("rightrot(11, 1) -> %u\n", rightrot(11, 1)); 8 | printf("rightrot(1024, 14) -> %u\n", rightrot(1024, 14)); 9 | } 10 | 11 | int bitlen(unsigned d) { 12 | int len = 0; 13 | for (; d; d >>= 1) { 14 | len++; 15 | } 16 | return len; 17 | } 18 | 19 | unsigned rightrot(unsigned d, unsigned x) { 20 | int len = bitlen(d); 21 | if (len) { 22 | x %= len; 23 | if (x) { 24 | unsigned right = d & ~(~0 << x); 25 | return right << len - x ^ d >> x; 26 | } else { 27 | return d; 28 | } 29 | } else { 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch02/2-9.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 2-9 3 | * In a two's complement number system, 4 | * x &= (x-1) deletes the rightmost 1-bit in x. 5 | * Explain why. Use this observation to write a faster version of bitcount. 6 | */ 7 | 8 | #include 9 | 10 | int bitcount(unsigned x); 11 | 12 | int main() { 13 | printf("%d's bit count is: %d\n", 1023, bitcount(1023)); 14 | printf("%d's bit count is: %d\n", 1024, bitcount(1024)); 15 | } 16 | 17 | int bitcount(unsigned x) { 18 | int len = 0; 19 | for (; x; x &= x - 1) { 20 | len++; 21 | } 22 | return len; 23 | } 24 | -------------------------------------------------------------------------------- /ch03/3-2.c: -------------------------------------------------------------------------------- 1 | /* Exercise 3-2 2 | * Write a function escape(s,t) that 3 | * converts characters like newline and tab into visible escape sequences like \n and \t 4 | * as it copies the string t to s. Use a switch. 5 | * Write a function for the other direction as well, 6 | * converting escape sequences into the real characters. 7 | */ 8 | 9 | #include 10 | 11 | void escape(char s[], char t[]); 12 | 13 | int main() { 14 | char s[] = "abc\tdef\tghi\njkl\tmno\tpqr\n"; 15 | char t[1000]; 16 | escape(s, t); 17 | printf("%s\n", t); 18 | } 19 | 20 | void escape(char s[], char t[]) { 21 | char c; 22 | int i = 0; 23 | int j = 0; 24 | while ((c = s[i]) != '\0') { 25 | switch (c) { 26 | case '\n': 27 | t[j++] = '\\'; 28 | t[j] = 'n'; 29 | break; 30 | case '\t': 31 | t[j++] = '\\'; 32 | t[j] = 't'; 33 | break; 34 | default: 35 | t[j] = s[i]; 36 | break; 37 | } 38 | i++; 39 | j++; 40 | } 41 | t[j] = '\0'; 42 | } 43 | -------------------------------------------------------------------------------- /ch03/3-3.c: -------------------------------------------------------------------------------- 1 | /* Exercise 3-3 2 | * Write a function expand(s1,s2) that 3 | * expands shorthand notations like a-z in the string s1 4 | * into the equivalent complete list abc...xyz in s2. 5 | * Allow for letters of either case and digits, 6 | * and be prepared to handle cases like a-b-c and a-z0-9 and -a-z. 7 | * Arrange that a leading or trailing - is taken literally. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | void expand(char s1[], char s2[]); 14 | 15 | int main() { 16 | char s1[] = "-a-c, e-c-a, a-a, a-Z, a-9\n-A-C, E-C-a, A-A, A-z, A-9\n-0-2, 4-2-0, 0-0, 0-z, 0-Z\n"; 17 | char s2[1000]; 18 | expand(s1, s2); 19 | printf("source string:\n%s\nresult string:\n%s\n", s1, s2); 20 | } 21 | 22 | void expand(char s1[], char s2[]) { 23 | char c; 24 | int i = 0; 25 | int j = 0; 26 | while ((c = s1[i]) != '\0') { 27 | char nextc = s1[i + 1]; 28 | if (nextc == '-') { 29 | char thirdc = s1[i + 2]; 30 | if ( 31 | isdigit(c) && isdigit(thirdc) 32 | || 33 | isupper(c) && isupper(thirdc) 34 | || 35 | islower(c) && islower(thirdc) 36 | ) { 37 | if (c < thirdc) { 38 | while (c <= thirdc) { 39 | s2[j++] = c; 40 | c++; 41 | } 42 | } else { 43 | while (c >= thirdc) { 44 | s2[j++] = c; 45 | c--; 46 | } 47 | } 48 | i += 3; 49 | } else { 50 | s2[j++] = s1[i++]; 51 | } 52 | } else { 53 | s2[j++] = s1[i++]; 54 | } 55 | } 56 | s2[j] = '\0'; 57 | } 58 | -------------------------------------------------------------------------------- /ch03/3-4.c: -------------------------------------------------------------------------------- 1 | /* Exercise 3-4 2 | * In a two's complement number representation, 3 | * our version of itoa does not handle the largest negative number, 4 | * that is, the value of n equal to -(2^(wordsize-1)). 5 | * Explain why not. 6 | * Modify it to print that value correctly, 7 | * regardless of the machine on which it runs. 8 | */ 9 | 10 | 11 | /* 12 | * Why not: 13 | * 14 | * assume that wordsize is 2, we can know: 15 | * binary: 00 01 10 11 16 | * integer: 0 1 -2 -1 17 | * 18 | * largest negative number is -2 19 | * 20 | * because -2 < 0, so line 6 `n = -n` will run 21 | * n = -(-2) = 2 22 | * 23 | * in 2's complement number representation 24 | * 2 -> 10(binary) -> -2 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | int getwordsize(); 31 | void reverse(char s[]); 32 | void itoa(int n, char s[]); 33 | 34 | int main() { 35 | char s[1000]; 36 | 37 | int i = 0; 38 | itoa(i, s); 39 | printf("%d to string is: %s\n", i, s); 40 | 41 | i = -128; 42 | itoa(i, s); 43 | printf("%d to string is: %s\n", i, s); 44 | 45 | i = 256; 46 | itoa(i, s); 47 | printf("%d to string is: %s\n", i, s); 48 | 49 | i = 1 << (getwordsize() - 1); 50 | itoa(i, s); 51 | printf("%d to string is: %s\n", i, s); 52 | } 53 | 54 | int getwordsize() { 55 | int i = 1; 56 | int j = 1; 57 | while ((i <<= 1) != 0) { 58 | j++; 59 | } 60 | } 61 | 62 | void reverse(char s[]) { 63 | int c, i, j; 64 | for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { 65 | c = s[i]; 66 | s[i] = s[j]; 67 | s[j] = c; 68 | } 69 | } 70 | 71 | void itoa(int n, char s[]) { 72 | int i = 0; 73 | int sign = n % 10; 74 | s[i++] = (sign < 0 ? -sign : sign) + '0'; 75 | 76 | n /= 10; 77 | if (n < 0) { 78 | sign = n; 79 | n = -n; 80 | } 81 | 82 | while (n > 0) { 83 | s[i++] = n % 10 + '0'; 84 | n /= 10; 85 | } 86 | 87 | if (sign < 0) { 88 | s[i++] = '-'; 89 | } 90 | 91 | s[i] = '\0'; 92 | 93 | reverse(s); 94 | } 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /ch03/3-5.c: -------------------------------------------------------------------------------- 1 | /* Exercise 3-5 2 | * Write the function itob(n,s,b) that 3 | * converts the integer n into a base b character representation in the string s. 4 | * In particular, itob(n,s,16) formats s as a hexadecimal integer in s. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | void reverse(char s[]); 11 | char itoc(int i); 12 | void itob(int n, char s[], int b); 13 | 14 | int main() { 15 | char s[1000]; 16 | 17 | int i = 0; 18 | int b = 2; 19 | itob(i, s, b); 20 | printf("%d into string base %d is: %s\n", i, b, s); 21 | 22 | i = 256; 23 | b = 16; 24 | itob(i, s, b); 25 | printf("%d into string base %d is: %s\n", i, b, s); 26 | 27 | i = -256; 28 | b = 16; 29 | itob(i, s, b); 30 | printf("%d into string base %d is: %s\n", i, b, s); 31 | 32 | i = 1023; 33 | b = 8; 34 | itob(i, s, b); 35 | printf("%d into string base %d is: %s\n", i, b, s); 36 | } 37 | 38 | void reverse(char s[]) { 39 | int c, i, j; 40 | for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { 41 | c = s[i]; 42 | s[i] = s[j]; 43 | s[j] = c; 44 | } 45 | } 46 | 47 | char itoc(int i) { 48 | if (i < 10) { 49 | return i + '0'; 50 | } else { 51 | return i - 10 + 'a'; 52 | } 53 | } 54 | 55 | void itob(int n, char s[], int b) { 56 | int i = 0; 57 | int sign = n % b; 58 | s[i++] = itoc(sign < 0 ? -sign : sign); 59 | 60 | n /= b; 61 | if (n < 0) { 62 | sign = n; 63 | n = -n; 64 | } 65 | 66 | while (n > 0) { 67 | s[i++] = itoc(n % b); 68 | n /= b; 69 | } 70 | 71 | if (sign < 0) { 72 | s[i++] = '-'; 73 | } 74 | 75 | s[i] = '\0'; 76 | reverse(s); 77 | } 78 | 79 | -------------------------------------------------------------------------------- /ch03/3-6.c: -------------------------------------------------------------------------------- 1 | /* Exercise 3-6 2 | * Write a version of itoa that accepts three arguments instead of two. 3 | * The third argument is a minimum field width; 4 | * the converted number must be padded with blanks on the left 5 | * if necessary to make it wide enough. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int getwordsize(); 12 | void reverse(char s[]); 13 | void itoa(int n, char s[], int w); 14 | 15 | int main() { 16 | char s[1000]; 17 | 18 | int i = 0; 19 | int w = 8; 20 | itoa(i, s, w); 21 | printf("%d to string width %d is: %s\n", i, w, s); 22 | 23 | i = -128; 24 | w = 8; 25 | itoa(i, s, w); 26 | printf("%d to string width %d is: %s\n", i, w, s); 27 | 28 | i = 256; 29 | w = 16; 30 | itoa(i, s, w); 31 | printf("%d to string width %d is: %s\n", i, w, s); 32 | 33 | i = 1 << (getwordsize() - 1); 34 | w = 16; 35 | itoa(i, s, w); 36 | printf("%d to string width %d is: %s\n", i, w, s); 37 | } 38 | 39 | int getwordsize() { 40 | int i = 1; 41 | int j = 1; 42 | while ((i <<= 1) != 0) { 43 | j++; 44 | } 45 | } 46 | 47 | void reverse(char s[]) { 48 | int c, i, j; 49 | for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { 50 | c = s[i]; 51 | s[i] = s[j]; 52 | s[j] = c; 53 | } 54 | } 55 | 56 | void itoa(int n, char s[], int w) { 57 | int i = 0; 58 | int sign = n % 10; 59 | s[i++] = (sign < 0 ? -sign : sign) + '0'; 60 | 61 | n /= 10; 62 | if (n < 0) { 63 | sign = n; 64 | n = -n; 65 | } 66 | 67 | while (n > 0) { 68 | s[i++] = n % 10 + '0'; 69 | n /= 10; 70 | } 71 | 72 | if (sign < 0) { 73 | s[i++] = '-'; 74 | } 75 | 76 | if (i < w) { 77 | while (w > i) { 78 | s[i++] = '~'; 79 | } 80 | } 81 | 82 | s[i] = '\0'; 83 | 84 | reverse(s); 85 | } 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /ch04/4-1.c: -------------------------------------------------------------------------------- 1 | /* Exercise 4-1 2 | * Write the function strindex(s,t) 3 | * which returns the position of the rightmost occurrence of t in s, 4 | * or -1 if there is none. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | int strindex(char s[], char t[]); 11 | 12 | int main() { 13 | printf("strindex(\"abcabc\", \"ab\") -> %d\n", strindex("abcabc", "ab")); 14 | printf("strindex(\"abcabc\", \"def\") -> %d\n", strindex("abcabc", "def")); 15 | } 16 | 17 | int strindex(char s[], char t[]) { 18 | int lens = strlen(s); 19 | int lent = strlen(t); 20 | 21 | int i; 22 | int j; 23 | int k; 24 | 25 | for (i = lens - lent; i >= 0; i--) { 26 | for (j = 0, k = i; t[j] != '\0' && t[j] == s[k]; j++, k++) 27 | ; 28 | if (j > 0 && t[j] == '\0') { 29 | return i; 30 | } 31 | } 32 | 33 | return -1; 34 | } 35 | -------------------------------------------------------------------------------- /ch04/4-12-itoa/itoa.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void _itoa(int n, char s[], int *p) { 4 | int m = n % 10; 5 | n /= 10; 6 | 7 | if (n) { 8 | _itoa(n, s, p); 9 | s[(*p)++] = (m > 0 ? m : -m) + '0'; 10 | } else { 11 | if (m >= 0) { 12 | int idx = *p; 13 | s[idx] = m + '0'; 14 | (*p)++; 15 | } else { 16 | s[(*p)++] = '-'; 17 | s[(*p)++] = -m + '0'; 18 | } 19 | } 20 | } 21 | 22 | void itoa(int n, char s[]) { 23 | int idx = 0; 24 | _itoa(n, s, &idx); 25 | s[idx] = '\0'; 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ch04/4-12-itoa/itoa.h: -------------------------------------------------------------------------------- 1 | #ifndef _ITOA_H_ 2 | #define _ITOA_H_ 3 | void itoa(int n, char s[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch04/4-12-itoa/itoa.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "./itoa.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char s[100]; 9 | 10 | itoa(0, s); 11 | assert(!strcmp("0", s)); 12 | 13 | itoa(-0, s); 14 | assert(!strcmp("0", s)); 15 | 16 | itoa(1234, s); 17 | assert(!strcmp("1234", s)); 18 | 19 | itoa(-1234, s); 20 | assert(!strcmp("-1234", s)); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch04/4-12-itoa/makefile: -------------------------------------------------------------------------------- 1 | name = itoa 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c 6 | ./${name}.test.out 7 | rm ${name}.test.out 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch04/4-13-reverse/makefile: -------------------------------------------------------------------------------- 1 | name = reverse 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c 6 | ./${name}.test.out 7 | rm ${name}.test.out 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch04/4-13-reverse/reverse.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void _reverse(char *s, int *idx, int *p) { 4 | char c = s[(*idx)++]; 5 | if (c != '\0') { 6 | _reverse(s, idx, p); 7 | s[(*p)++] = c; 8 | } 9 | } 10 | 11 | void reverse(char *s) { 12 | int idx = 0; 13 | int p = 0; 14 | _reverse(s, &idx, &p); 15 | } 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ch04/4-13-reverse/reverse.h: -------------------------------------------------------------------------------- 1 | #ifndef _REVERSE_H_ 2 | #define _REVERSE_H_ 3 | void reverse(char *s); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch04/4-13-reverse/reverse.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "./reverse.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char s1[4] = {'a', 'b', 'c', '\0'}; 9 | 10 | reverse(s1); 11 | assert(!strcmp("cba", s1)); 12 | 13 | char s2[1] = {'\0'}; 14 | reverse(s2); 15 | assert(!strcmp("", s2)); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch04/4-2.c: -------------------------------------------------------------------------------- 1 | /* Exercise 4-2 2 | * Extend atof to handle scientific notation of the form 3 | * 123.45e-6 4 | * where a floating-point number may be followed by e or E 5 | * and an optionally signed exponent. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | double atof(char s[]); 12 | 13 | int main() { 14 | printf("0 -> %e\n", atof("0")); 15 | printf("123.456 -> %g\n", atof("123.456")); 16 | printf("-67.890 -> %g\n", atof("-67.89")); 17 | printf("1.23e+20 -> %g\n", atof("1.23e+20")); 18 | printf("-4.56E-6 -> %g\n", atof("-4.56E-6")); 19 | } 20 | 21 | double atof(char s[]) { 22 | double val; 23 | double power; 24 | int i; 25 | int sign; 26 | 27 | for (i = 0; isspace(s[i]); i++) 28 | ; 29 | 30 | sign = (s[i] == '-') ? -1 : 1; 31 | 32 | if (s[i] == '-' || s[i] == '+') { 33 | i++; 34 | } 35 | 36 | for (val = 0.0; isdigit(s[i]); i++) { 37 | val = 10.0 * val + (s[i] - '0'); 38 | } 39 | 40 | if(s[i] == '.') { 41 | i++; 42 | } 43 | 44 | for (power = 1.0; isdigit(s[i]); i++, power *= 10.0) { 45 | val = 10 * val + (s[i] - '0'); 46 | } 47 | 48 | val = sign * val / power; 49 | 50 | if(s[i] == 'e' || s[i] == 'E') { 51 | i++; 52 | int expsign = 1; 53 | int exp; 54 | 55 | if (s[i] == '-') { 56 | expsign = -1; 57 | } 58 | 59 | if(s[i] == '-' || s[i] == '+') { 60 | i++; 61 | } 62 | 63 | for (exp = 0; isdigit(s[i]); i++) { 64 | exp = 10 * exp + (s[i] - '0'); 65 | } 66 | 67 | exp = exp * expsign; 68 | 69 | if (exp > 0) { 70 | while (exp-- > 0) { 71 | val = 10.0 * val; 72 | } 73 | } else if (exp < 0) { 74 | while (exp++ < 0) { 75 | val = val / 10.0; 76 | } 77 | } 78 | } 79 | 80 | return val; 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /ch04/4-8-getch/getch.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUFSIZE 100 4 | 5 | static char c; 6 | 7 | int getch() { 8 | char rt = c ? c : getchar(); 9 | c = '\0'; 10 | return rt; 11 | } 12 | 13 | int ungetch(char ch) { 14 | if (c) { 15 | printf("Error: more than one char unget.\n"); 16 | return 0; 17 | } else { 18 | c = ch; 19 | return 1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch04/4-8-getch/getch.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETCH_H_ 2 | #define _GETCH_H_ 3 | int getch(); 4 | int ungetch(char ch); 5 | #endif 6 | -------------------------------------------------------------------------------- /ch04/4-8-getch/getch.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | char c1 = getch(); 5 | assert(c1 == '#'); 6 | 7 | char c2 = getch(); 8 | assert(c2 == 'i'); 9 | 10 | assert(ungetch(c2)); 11 | 12 | assert(!ungetch(c1)); 13 | } 14 | -------------------------------------------------------------------------------- /ch04/4-8-getch/makefile: -------------------------------------------------------------------------------- 1 | test: 2 | 3 | gcc -o getch.test.out getch.test.c getch.c 4 | ./getch.test.out 2 | 3 | int getline2(char s[]) { 4 | static int c; 5 | int i = 0; 6 | 7 | if (c == EOF) { 8 | return 0; 9 | } 10 | 11 | while((c = getchar()) != '\n' && c != EOF) { 12 | s[i++] = c; 13 | } 14 | if (c == '\n') { 15 | s[i++] = c; 16 | } 17 | s[i] = '\0'; 18 | 19 | return 1; 20 | } 21 | -------------------------------------------------------------------------------- /ch04/calculator/getline2.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETLINE_H_ 2 | #define _GETLINE_H_ 3 | int getline2(char s[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch04/calculator/getop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * Get token seperated by space from s 6 | * Return index if found or 0 if not found 7 | */ 8 | int getop(char s[], int i, char t[]) { 9 | int j = 0; 10 | int c; 11 | 12 | for (; isspace(s[i]); i++); 13 | 14 | for (; !isspace(c = s[i]) && c != '\0'; i++, t[j++] = c); 15 | t[j] = '\0'; 16 | 17 | return j ? i : -1; 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /ch04/calculator/getop.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETOP_H_ 2 | #define _GETOP_H_ 3 | int getop(char s[], int i, char t[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch04/calculator/isnumfmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Check if a string in number format. 5 | * [+|-]?\d*(\.\d*)?([e|E][+|-]?\d+)? 6 | */ 7 | int isnumfmt(char s[]) { 8 | int i = 0, c; 9 | 10 | if ((c = s[i]) == '+' || c == '-') { 11 | i++; 12 | } 13 | 14 | if (s[i] == '\0') { 15 | return 0; 16 | } 17 | 18 | for (; isdigit(c = s[i]); i++); 19 | 20 | if (c == '.') { 21 | i++; 22 | } 23 | 24 | for (; isdigit(c = s[i]); i++); 25 | 26 | if (c == 'e' || c == 'E') { 27 | int c2 = s[i + 1]; 28 | int c3 = s[i + 2]; 29 | if ((c2 == '+' || c2 == '-') && isdigit(c3)) { 30 | i += 2; 31 | } else if (isdigit(c2)) { 32 | i++; 33 | } 34 | } 35 | 36 | for (; isdigit(c = s[i]); i++); 37 | 38 | return c == '\0'; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /ch04/calculator/isnumfmt.h: -------------------------------------------------------------------------------- 1 | #ifndef _ISNUMFMT_H_ 2 | #define _ISNUMFMT_H_ 3 | int isnumfmt(char s[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch04/calculator/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "getop.h" 7 | #include "isnumfmt.h" 8 | #include "stack.h" 9 | #include "getline2.h" 10 | 11 | #define MAX 100 12 | 13 | int main(int argc, char *argv[]) { 14 | char line[MAX]; 15 | char t[MAX]; 16 | double tmp; 17 | 18 | while(getline2(line)) { 19 | int start = 0; 20 | while ((start = getop(line, start, t)) != -1) { 21 | if (isnumfmt(t)) { 22 | push(atof(t)); 23 | } else if (!strcmp(t, "+")) { 24 | push(pop() + pop()); 25 | } else if (!strcmp(t, "*")) { 26 | push(pop() * pop()); 27 | } else if (!strcmp(t, "-")) { 28 | swap(); 29 | push(pop() - pop()); 30 | } else if (!strcmp(t, "/")) { 31 | tmp = pop(); 32 | if (tmp != 0) { 33 | push(pop() / tmp); 34 | } else { 35 | pop(); 36 | push(0.0); 37 | printf("Error: divisor is 0\n"); 38 | } 39 | } else if (!strcmp(t, "%")) { 40 | tmp = pop(); 41 | if (tmp != 0) { 42 | push((int) pop() % (int) tmp); 43 | } else { 44 | pop(); 45 | push(0.0); 46 | printf("Error: divisor is 0\n"); 47 | } 48 | 49 | } else if (!strcmp(t, "pow")) { 50 | double tmp = pop(); 51 | push(pow(pop(), tmp)); 52 | 53 | } else if (!strcmp(t, "exp")) { 54 | push(exp(pop())); 55 | 56 | } else if (!strcmp(t, "sin")) { 57 | push(sin(pop())); 58 | 59 | } else { 60 | printf("Error: unknown token %s\n", t); 61 | } 62 | } 63 | 64 | printf("result: %g\n", gettop()); 65 | clearstack(); 66 | } 67 | 68 | 69 | 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /ch04/calculator/makefile: -------------------------------------------------------------------------------- 1 | output = calculator.out 2 | 3 | all: 4 | 5 | gcc -o ${output} main.c getop.c isnumfmt.c stack.c getline2.c 6 | ./${output} 7 | 8 | test: 9 | 10 | gcc -o getline2.out getline2.c tests/getline2.test.c 11 | ./getline2.out 2 | 3 | #define LEN 100 4 | 5 | static int p = 0; 6 | static double val[LEN]; 7 | 8 | void push(double n) { 9 | if (p < LEN) { 10 | val[p++] = n; 11 | } else { 12 | printf("Error: stack full."); 13 | } 14 | } 15 | 16 | double pop() { 17 | if (p > 0) { 18 | return val[--p]; 19 | } else { 20 | printf("Error: stack empty."); 21 | return 0.0; 22 | } 23 | } 24 | 25 | void swap() { 26 | if (p > 1) { 27 | double tmp = val[p - 1]; 28 | val[p - 1] = val[p - 2]; 29 | val[p - 2] = tmp; 30 | } else { 31 | printf("Error: on enough stack elements to swap."); 32 | } 33 | } 34 | 35 | double gettop() { 36 | return val[p - 1]; 37 | } 38 | 39 | void clearstack() { 40 | p = 0; 41 | } 42 | -------------------------------------------------------------------------------- /ch04/calculator/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _STACK_H_ 2 | #define _STACK_H_ 3 | void push(double n); 4 | double pop(); 5 | void swap(); 6 | double gettop(); 7 | void clearstack(); 8 | #endif 9 | -------------------------------------------------------------------------------- /ch04/calculator/tests/getline2.input.txt: -------------------------------------------------------------------------------- 1 | line1 2 | 3 | line3 -------------------------------------------------------------------------------- /ch04/calculator/tests/getline2.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../getline2.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char s[1000]; 9 | 10 | getline2(s); 11 | assert(!strcmp(s, "line1\n")); 12 | 13 | getline2(s); 14 | assert(!strcmp(s, "\n")); 15 | 16 | getline2(s); 17 | assert(!strcmp(s, "line3")); 18 | 19 | assert(!getline2(s)); 20 | } 21 | -------------------------------------------------------------------------------- /ch04/calculator/tests/getop.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../getop.h" 4 | 5 | int main(int argc, char *argv[]) { 6 | char *s = "12.3 4.5 +\n"; 7 | char t[100]; 8 | int i = 0; 9 | 10 | assert(i = getop(s, i, t)); 11 | assert(!strcmp(t,"12.3")); 12 | 13 | assert(i = getop(s, i, t)); 14 | assert(!strcmp(t,"4.5")); 15 | 16 | assert(i = getop(s, i, t)); 17 | assert(!strcmp(t,"+")); 18 | 19 | assert(getop(s, i, t) == -1); 20 | 21 | s = " a b c \n"; 22 | i = 0; 23 | 24 | assert(i = getop(s, i, t)); 25 | assert(!strcmp(t,"a")); 26 | 27 | assert(i = getop(s, i, t)); 28 | assert(!strcmp(t,"b")); 29 | 30 | assert(i = getop(s, i, t)); 31 | assert(!strcmp(t,"c")); 32 | 33 | assert(getop(s, i, t) == -1); 34 | } 35 | -------------------------------------------------------------------------------- /ch04/calculator/tests/isnumfmt.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../isnumfmt.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | assert(isnumfmt("0")); 6 | assert(isnumfmt("-1")); 7 | assert(isnumfmt("2.")); 8 | assert(isnumfmt(".3")); 9 | assert(isnumfmt("4e5")); 10 | assert(isnumfmt("6E-7")); 11 | assert(!isnumfmt("+")); 12 | assert(!isnumfmt("1a")); 13 | assert(!isnumfmt("a1")); 14 | assert(!isnumfmt("12e")); 15 | assert(!isnumfmt("34E-")); 16 | } 17 | -------------------------------------------------------------------------------- /ch04/calculator/tests/stack.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../stack.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | double n1 = 12.34; 6 | double n2 = 56.2; 7 | double n3 = -78.9; 8 | 9 | push(n1); 10 | push(n2); 11 | assert(pop() == n2); 12 | push(n3); 13 | assert(pop() == n3); 14 | assert(pop() == n1); 15 | 16 | push(n1); 17 | push(n2); 18 | assert(gettop() == n2); 19 | swap(); 20 | assert(pop() == n1); 21 | assert(pop() == n2); 22 | } 23 | -------------------------------------------------------------------------------- /ch05/5-1-getint/getch.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAX 100 4 | 5 | static char s[MAX]; 6 | static int p = 0; 7 | 8 | char getch() { 9 | return p ? s[--p] : getchar(); 10 | } 11 | 12 | void ungetch(char c) { 13 | if (p < MAX) { 14 | s[p++] = c; 15 | } else { 16 | printf("Error: buf is full."); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch05/5-1-getint/getch.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETCH_H_ 2 | #define _GETCH_H_ 3 | char getch(); 4 | void ungetch(char c); 5 | #endif 6 | -------------------------------------------------------------------------------- /ch05/5-1-getint/getint.c: -------------------------------------------------------------------------------- 1 | /* Exercise 5-1 2 | * As written, getint treats a + or - not followed by a digit as a valid representation of zero. 3 | * Fix it to push such a character back on the input. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "./getch.h" 10 | 11 | int getint(int *pn) { 12 | int c, sign; 13 | 14 | while (isspace(c = getch())); 15 | 16 | if (!isdigit(c) && c != EOF && c != '+' && c != '-') { 17 | ungetch(c); 18 | return 0; 19 | } 20 | 21 | sign = (c == '-') ? -1 : 1; 22 | 23 | if (c == '+' || c == '-') { 24 | int nextc = getch(); 25 | if (isdigit(nextc)) { 26 | c = nextc; 27 | } else { 28 | ungetch(nextc); 29 | ungetch(c); 30 | return 0; 31 | } 32 | } 33 | 34 | for (*pn = 0; isdigit(c); c = getch()) { 35 | *pn = 10 * *pn + (c - '0'); 36 | } 37 | 38 | *pn *= sign; 39 | if (c != EOF) { 40 | ungetch(c); 41 | } 42 | 43 | return c; 44 | } 45 | -------------------------------------------------------------------------------- /ch05/5-1-getint/getint.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETINT_H_ 2 | #define _GETINT_H_ 3 | int getint(int *pn); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-1-getint/getint.input.txt: -------------------------------------------------------------------------------- 1 | 0 -0 123 -123 +abc -------------------------------------------------------------------------------- /ch05/5-1-getint/getint.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "./getint.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | int i; 9 | 10 | assert(getint(&i)); 11 | assert(i == 0); 12 | 13 | assert(getint(&i)); 14 | assert(i == 0); 15 | 16 | assert(getint(&i)); 17 | assert(i == 123); 18 | 19 | assert(getint(&i)); 20 | assert(i == -123); 21 | 22 | assert(!getint(&i)); 23 | assert(getch() == '+'); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ch05/5-1-getint/makefile: -------------------------------------------------------------------------------- 1 | name = getint 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c getch.c 6 | ./${name}.test.out 2 | #include 3 | #include 4 | #include 5 | 6 | #include "isnumfmt.h" 7 | #include "stack.h" 8 | 9 | double calculate(char *tokens[], int len) { 10 | char *t; 11 | int i; 12 | for (i = 0; i < len; i++) { 13 | t = tokens[i]; 14 | if (isnumfmt(t)) { 15 | push(atof(t)); 16 | } else if (!strcmp(t, "+")) { 17 | push(pop() + pop()); 18 | } else if (!strcmp(t, "*")) { 19 | push(pop() * pop()); 20 | } else if (!strcmp(t, "-")) { 21 | swap(); 22 | push(pop() - pop()); 23 | } else if (!strcmp(t, "/")) { 24 | double tmp = pop(); 25 | if (tmp != 0) { 26 | push(pop() / tmp); 27 | } else { 28 | pop(); 29 | push(0.0); 30 | printf("Error: divisor is 0\n"); 31 | } 32 | } else if (!strcmp(t, "%")) { 33 | double tmp = pop(); 34 | if (tmp != 0) { 35 | push((int) pop() % (int) tmp); 36 | } else { 37 | pop(); 38 | push(0.0); 39 | printf("Error: divisor is 0\n"); 40 | } 41 | 42 | } else if (!strcmp(t, "pow")) { 43 | double tmp = pop(); 44 | push(pow(pop(), tmp)); 45 | 46 | } else if (!strcmp(t, "exp")) { 47 | push(exp(pop())); 48 | 49 | } else if (!strcmp(t, "sin")) { 50 | push(sin(pop())); 51 | 52 | } else { 53 | printf("Error: unknown token %s\n", t); 54 | } 55 | } 56 | 57 | double rt = gettop(); 58 | clearstack(); 59 | return rt; 60 | } 61 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/calculate.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALCULATE_H_ 2 | #define _CALCULATE_H_ 3 | double calculate(char *tokens[], int len); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/isnumfmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Check if a string in number format. 5 | * [+|-]?\d*(\.\d*)?([e|E][+|-]?\d+)? 6 | */ 7 | int isnumfmt(char s[]) { 8 | int i = 0, c; 9 | 10 | if ((c = s[i]) == '+' || c == '-') { 11 | i++; 12 | } 13 | 14 | if (s[i] == '\0') { 15 | return 0; 16 | } 17 | 18 | for (; isdigit(c = s[i]); i++); 19 | 20 | if (c == '.') { 21 | i++; 22 | } 23 | 24 | for (; isdigit(c = s[i]); i++); 25 | 26 | if (c == 'e' || c == 'E') { 27 | int c2 = s[i + 1]; 28 | int c3 = s[i + 2]; 29 | if ((c2 == '+' || c2 == '-') && isdigit(c3)) { 30 | i += 2; 31 | } else if (isdigit(c2)) { 32 | i++; 33 | } 34 | } 35 | 36 | for (; isdigit(c = s[i]); i++); 37 | 38 | return c == '\0'; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/isnumfmt.h: -------------------------------------------------------------------------------- 1 | #ifndef _ISNUMFMT_H_ 2 | #define _ISNUMFMT_H_ 3 | int isnumfmt(char s[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/makefile: -------------------------------------------------------------------------------- 1 | test: 2 | 3 | gcc -o isnumfmt.out isnumfmt.c tests/isnumfmt.test.c 4 | ./isnumfmt.out 5 | rm isnumfmt.out 6 | 7 | gcc -o stack.out stack.c tests/stack.test.c 8 | ./stack.out 9 | rm stack.out 10 | 11 | gcc -o calculate.out calculate.c isnumfmt.c stack.c tests/calculate.test.c 12 | ./calculate.out 2 3 4 + '*' 13 | rm calculate.out 14 | 15 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LEN 100 4 | 5 | static int p = 0; 6 | static double val[LEN]; 7 | 8 | void push(double n) { 9 | if (p < LEN) { 10 | val[p++] = n; 11 | } else { 12 | printf("Error: stack full."); 13 | } 14 | } 15 | 16 | double pop() { 17 | if (p > 0) { 18 | return val[--p]; 19 | } else { 20 | printf("Error: stack empty."); 21 | return 0.0; 22 | } 23 | } 24 | 25 | void swap() { 26 | if (p > 1) { 27 | double tmp = val[p - 1]; 28 | val[p - 1] = val[p - 2]; 29 | val[p - 2] = tmp; 30 | } else { 31 | printf("Error: on enough stack elements to swap."); 32 | } 33 | } 34 | 35 | double gettop() { 36 | return val[p - 1]; 37 | } 38 | 39 | void clearstack() { 40 | p = 0; 41 | } 42 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _STACK_H_ 2 | #define _STACK_H_ 3 | void push(double n); 4 | double pop(); 5 | void swap(); 6 | double gettop(); 7 | void clearstack(); 8 | #endif 9 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/tests/calculate.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../calculate.h" 4 | 5 | int main(int argc, char *argv[]) { 6 | double rt = calculate(++argv, --argc); 7 | assert(rt == 14); 8 | } 9 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/tests/isnumfmt.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../isnumfmt.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | assert(isnumfmt("0")); 6 | assert(isnumfmt("-1")); 7 | assert(isnumfmt("2.")); 8 | assert(isnumfmt(".3")); 9 | assert(isnumfmt("4e5")); 10 | assert(isnumfmt("6E-7")); 11 | assert(!isnumfmt("+")); 12 | assert(!isnumfmt("1a")); 13 | assert(!isnumfmt("a1")); 14 | assert(!isnumfmt("12e")); 15 | assert(!isnumfmt("34E-")); 16 | } 17 | -------------------------------------------------------------------------------- /ch05/5-10-calculator/tests/stack.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../stack.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | double n1 = 12.34; 6 | double n2 = 56.2; 7 | double n3 = -78.9; 8 | 9 | push(n1); 10 | push(n2); 11 | assert(pop() == n2); 12 | push(n3); 13 | assert(pop() == n3); 14 | assert(pop() == n1); 15 | 16 | push(n1); 17 | push(n2); 18 | assert(gettop() == n2); 19 | swap(); 20 | assert(pop() == n1); 21 | assert(pop() == n2); 22 | } 23 | -------------------------------------------------------------------------------- /ch05/5-11-detab/detab.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tabpos.h" 4 | 5 | void detab(int *tab) { 6 | int c; 7 | int p = 1; 8 | while ((c = getchar()) != EOF) { 9 | if (c == '\t') { 10 | do { 11 | putchar('-'); 12 | } while (!tabpos(p++, tab)); 13 | } else if (c == '\n') { 14 | putchar(c); 15 | p = 1; 16 | } else { 17 | putchar(c); 18 | p++; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch05/5-11-detab/detab.h: -------------------------------------------------------------------------------- 1 | #ifndef _DETAB_H_ 2 | #define _DETAB_H_ 3 | void detab(int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-11-detab/detab.input.txt: -------------------------------------------------------------------------------- 1 | a b c d e 2 | -------------------------------------------------------------------------------- /ch05/5-11-detab/entab.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tabpos.h" 4 | 5 | void entab(int *tab) { 6 | int c; 7 | int pos = 0; 8 | int space = 0; 9 | while ((c = getchar()) != EOF) { 10 | pos++; 11 | if (c == ' ') { 12 | space++; 13 | } else { 14 | if (c == '\t') { 15 | space = 0; // forget spaces 16 | while (!tabpos(pos, tab)) { 17 | pos++; 18 | } 19 | putchar('\\'); 20 | putchar('t'); 21 | } else if (c == '\n') { 22 | space = 0; // forget tailed space 23 | pos = 0; 24 | putchar(c); 25 | } else { 26 | while (space > 0) { 27 | putchar('-'); 28 | space--; 29 | } 30 | putchar(c); 31 | } 32 | } 33 | 34 | if (tabpos(pos, tab) && space > 0) { 35 | space = 0; 36 | putchar('\\'); 37 | putchar('t'); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ch05/5-11-detab/entab.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENTAB_H_ 2 | #define _ENTAB_H_ 3 | void entab(int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-11-detab/entab.input.txt: -------------------------------------------------------------------------------- 1 | ab cd ef gh ij 2 | ab cd ef gh ij 3 | -------------------------------------------------------------------------------- /ch05/5-11-detab/main.detab.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "detab.h" 3 | #include "settab.h" 4 | 5 | #define MAXLINE 100 6 | 7 | int main(int argc, char *argv[]) { 8 | int tab[MAXLINE]; 9 | 10 | settab(argc, argv, tab); 11 | detab(tab); 12 | } 13 | -------------------------------------------------------------------------------- /ch05/5-11-detab/main.entab.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "entab.h" 3 | #include "settab.h" 4 | 5 | #define MAXLINE 100 6 | 7 | int main(int argc, char *argv[]) { 8 | int tab[MAXLINE]; 9 | 10 | settab(argc, argv, tab); 11 | /* 12 | int i = 0; 13 | for(; i < MAXLINE; i++) { 14 | printf("%d ", tab[i]); 15 | }*/ 16 | entab(tab); 17 | } 18 | -------------------------------------------------------------------------------- /ch05/5-11-detab/makefile: -------------------------------------------------------------------------------- 1 | name = main.detab.out 2 | name2 = maiin.entab.out 3 | 4 | run: 5 | gcc -o ${name} main.detab.c detab.c settab.c tabpos.c 6 | ./${name} 4 8 16 32 2 | 3 | #define MAXLINE 100 4 | #define TABING 8 5 | 6 | void settab(int argc, char *argv[], int *tab) { 7 | int i; 8 | int p; 9 | if (argc <= 1) { 10 | for (i = 1; i < MAXLINE; i++) { 11 | tab[i] = i % TABING == 0 ? 1 : 0; 12 | } 13 | } else { 14 | for (i = 1; i < MAXLINE; i++) { 15 | tab[i] = 0; 16 | } 17 | while (--argc) { 18 | p = atoi(*++argv); 19 | if (p > 0 && p <= MAXLINE) { 20 | tab[p] = 1; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch05/5-11-detab/settab.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETTAB_H_ 2 | #define _SETTAB_H_ 3 | void settab(int argc, char *argv[], int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-11-detab/tabpos.c: -------------------------------------------------------------------------------- 1 | #define MAXLINE 100 2 | #define TABING 8 3 | 4 | int tabpos(int pos, int *tab) { 5 | return tab[pos] || pos >= MAXLINE; 6 | } 7 | -------------------------------------------------------------------------------- /ch05/5-11-detab/tabpos.h: -------------------------------------------------------------------------------- 1 | #ifndef _TABPOS_H_ 2 | #define _TABPOS_H_ 3 | int tabpos(int pos, int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-12-detab/entab.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tabpos.h" 4 | 5 | void entab(int *tab) { 6 | int c; 7 | int pos = 0; 8 | int space = 0; 9 | while ((c = getchar()) != EOF) { 10 | pos++; 11 | if (c == ' ') { 12 | space++; 13 | } else { 14 | if (c == '\t') { 15 | space = 0; // forget spaces 16 | while (!tabpos(pos, tab)) { 17 | pos++; 18 | } 19 | putchar('\\'); 20 | putchar('t'); 21 | } else if (c == '\n') { 22 | space = 0; // forget tailed space 23 | pos = 0; 24 | putchar(c); 25 | } else { 26 | while (space > 0) { 27 | putchar('-'); 28 | space--; 29 | } 30 | putchar(c); 31 | } 32 | } 33 | 34 | if (tabpos(pos, tab) && space > 0) { 35 | space = 0; 36 | putchar('\\'); 37 | putchar('t'); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ch05/5-12-detab/entab.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENTAB_H_ 2 | #define _ENTAB_H_ 3 | void entab(int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-12-detab/entab.input.txt: -------------------------------------------------------------------------------- 1 | ab cd ef gh ij 2 | ab cd ef gh ij 3 | -------------------------------------------------------------------------------- /ch05/5-12-detab/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "entab.h" 5 | #include "settab.h" 6 | 7 | #define MAXLINE 100 8 | 9 | int main(int argc, char *argv[]) { 10 | int start = 0; 11 | int step = 8; 12 | while (--argc > 0) { 13 | char *s = *++argv; 14 | if (*s == '-') { 15 | start = atoi(++s); 16 | } else if (*s == '+') { 17 | step = atoi(++s); 18 | } 19 | } 20 | 21 | int tab[MAXLINE]; 22 | settab(start, step, tab); 23 | 24 | entab(tab); 25 | } 26 | -------------------------------------------------------------------------------- /ch05/5-12-detab/makefile: -------------------------------------------------------------------------------- 1 | name = main.entab.out 2 | 3 | run: 4 | 5 | gcc -o ${name} main.c entab.c settab.c tabpos.c 6 | ./${name} -2 +8 2 | 3 | #define MAXLINE 100 4 | #define TABING 8 5 | 6 | void settab(int start, int step, int *tab) { 7 | if (start < 0 || start >= MAXLINE) start = 0; 8 | if (step <= 0) step = 8; 9 | 10 | int i; 11 | for (i = 1; i < MAXLINE; i++) { 12 | tab[i] = 0; 13 | } 14 | 15 | while ((start += step) < MAXLINE) { 16 | tab[start] = 1; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch05/5-12-detab/settab.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETTAB_H_ 2 | #define _SETTAB_H_ 3 | void settab(int start, int step, int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-12-detab/tabpos.c: -------------------------------------------------------------------------------- 1 | #define MAXLINE 100 2 | #define TABING 8 3 | 4 | int tabpos(int pos, int *tab) { 5 | return tab[pos] || pos >= MAXLINE; 6 | } 7 | -------------------------------------------------------------------------------- /ch05/5-12-detab/tabpos.h: -------------------------------------------------------------------------------- 1 | #ifndef _TABPOS_H_ 2 | #define _TABPOS_H_ 3 | int tabpos(int pos, int *tab); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-13-tail/input.txt: -------------------------------------------------------------------------------- 1 | line1 2 | line2 3 | line3 4 | line4 5 | line5 6 | line6 7 | line7 8 | line8 9 | line9 10 | line10 11 | line11 12 | line12 13 | -------------------------------------------------------------------------------- /ch05/5-13-tail/makefile: -------------------------------------------------------------------------------- 1 | run: 2 | 3 | gcc tail.c -o tail.out 4 | ./tail.out -6 2 | #include 3 | #include 4 | 5 | #define MAXLINE 1000 6 | 7 | void tail(int n); 8 | static int getline2(char *s, int len); 9 | static void strcpy2(char *from, char *to); 10 | 11 | int main(int argc, char *argv[]) { 12 | int n = 10; 13 | while (--argc > 0) { 14 | char *arg = *++argv; 15 | if (*arg == '-') { 16 | n = atoi(++arg); 17 | } 18 | } 19 | tail(n); 20 | } 21 | 22 | void tail(int n) { 23 | int count = 0; 24 | char *lines[n]; 25 | 26 | char s[MAXLINE]; 27 | int w; 28 | char *p; 29 | 30 | while (w = getline2(s, MAXLINE)) { 31 | p = malloc(w); 32 | 33 | if (p == NULL) { 34 | printf("Memory allocation error."); 35 | return; 36 | 37 | } else { 38 | strcpy(p, s); 39 | if (count >= n) { 40 | free(lines[count % n]); 41 | } 42 | lines[count % n] = p; 43 | count++; 44 | } 45 | } 46 | 47 | int start = 0; 48 | int end = count; 49 | if (count >= n) { 50 | start = count; 51 | end = count + n; 52 | } 53 | printf("---->\n"); 54 | for (; start < end; start++) { 55 | printf("%s", lines[start % n]); 56 | free(lines[start % n]); 57 | } 58 | printf("<----\n"); 59 | } 60 | 61 | static int getline2(char *s, int len) { 62 | static char c; 63 | if (c == EOF) { 64 | return 0; 65 | } 66 | 67 | int i = 0; 68 | while ((c = getchar()) != '\n' && c != EOF && i < len - 1) { 69 | *(s + i++) = c; 70 | } 71 | if (c == '\n') { 72 | *(s + i++) = c; 73 | } 74 | *(s + i) = '\0'; 75 | return i; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/cmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static int charcmp(char c1, char c2, int caseSensitive); 6 | static int getch(char *s, int i, int isdir); 7 | static int basecmp(char *s1, char *s2, int caseSensitive, int isdir); 8 | 9 | int numcmp(char *s1, char *s2) { 10 | float n1 = atof(s1); 11 | float n2 = atof(s2); 12 | if (n1 < n2) { 13 | return -1; 14 | } else if (n1 > n2) { 15 | return 1; 16 | } else { 17 | return 0; 18 | } 19 | } 20 | 21 | int strcmpi(char *s1, char *s2) { 22 | return basecmp(s1, s2, 0, 0); 23 | } 24 | 25 | int dircmp(char *s1, char *s2) { 26 | return basecmp(s1, s2, 1, 1); 27 | } 28 | 29 | int dircmpi(char *s1, char *s2) { 30 | return basecmp(s1, s2, 0, 1); 31 | } 32 | 33 | 34 | static int basecmp(char *s1, char *s2, int caseSensitive, int isdir) { 35 | int i = getch(s1, 0, isdir); 36 | int j = getch(s2, 0, isdir); 37 | int cmp; 38 | 39 | for (; i != -1 && j != -1; i = getch(s1, ++i, isdir), j = getch(s2, ++j, isdir)) { 40 | cmp = charcmp(s1[i], s2[j], caseSensitive); 41 | if (cmp != 0) { 42 | return cmp; 43 | } 44 | } 45 | 46 | if (i == -1 && j == -1) { 47 | return 0; 48 | } else if (i == -1) { 49 | return -1; 50 | } else { 51 | return 1; 52 | } 53 | } 54 | 55 | 56 | static int getch(char *s, int i, int isdir) { 57 | char c; 58 | do { 59 | c = *(s + i++); 60 | } while (isdir && !isalnum(c) && c != ' ' && c != '\0'); 61 | 62 | if (c == '\0') { 63 | return -1; 64 | } else { 65 | return --i; 66 | } 67 | } 68 | 69 | 70 | static int charcmp(char c1, char c2, int caseSensitive) { 71 | if (!caseSensitive && isalpha(c1) && isalpha(c2)) { 72 | c1 = tolower(c1); 73 | c2 = tolower(c2); 74 | } 75 | 76 | if (c1 < c2) { 77 | return -1; 78 | } else if (c1 > c2) { 79 | return 1; 80 | } else { 81 | return 0; 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/cmp.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPM_H_ 2 | #define _CPM_H_ 3 | int numcmp(char *s1, char *s2); 4 | int strcmpi(char *s1, char *s2); 5 | int dircmp(char *s1, char *s2); 6 | int dircmpi(char *s1, char *s2); 7 | #endif 8 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/cmp.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "cmp.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | 9 | assert(numcmp("abc", "9ab") == -1); 10 | assert(numcmp("9ab", "10c") == -1); 11 | assert(numcmp("10c", "10d") == 0); 12 | 13 | assert(strcmpi("abc", "ABC") == 0); 14 | assert(strcmpi("ab", "A") == 1); 15 | assert(strcmpi("AB", "c") == -1); 16 | 17 | char s1[] = {'\t', 'a', ' ', '\0'}; 18 | char s2[] = {'a', ' ', '\t', '\0'}; 19 | char s3[] = {'A', '\t', ' ', '\0'}; 20 | 21 | assert(dircmp(s1, s2) == 0); 22 | assert(dircmp(s3, s2) == -1); 23 | assert(dircmp(s1, s3) == 1); 24 | 25 | assert(dircmpi(s1, s3) == 0); 26 | assert(dircmpi(s2, s3) == 0); 27 | } 28 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/getlines.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAXLINE 1000 6 | 7 | int getlines(char *lines[], int nline, FILE *stream) { 8 | int i = 0; 9 | char s[MAXLINE]; 10 | char *p; 11 | while(fgets(s, MAXLINE, stream) && i < nline) { 12 | p = malloc(strlen(s) + 1); 13 | strcpy(p, s); 14 | lines[i++] = p; 15 | } 16 | return i; 17 | } 18 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/getlines.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETLINES_H_ 2 | #define _GETLINES_H_ 3 | int getlines(char *lines[], int nline, FILE *stream); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/getlines.input.txt: -------------------------------------------------------------------------------- 1 | line1 2 | line2 3 | line3 4 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/getlines.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "getlines.h" 6 | 7 | #define MAXLINES 1000 8 | 9 | int main(int argc, char *argv[]) { 10 | char *lines[MAXLINES]; 11 | int len; 12 | if (len = getlines(lines, MAXLINES, stdin)) { 13 | assert(len == 3); 14 | assert(strcmp(lines[0], "line1\n") == 0); 15 | assert(strcmp(lines[1], "line2\n") == 0); 16 | assert(strcmp(lines[2], "line3\n") == 0); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "getlines.h" 8 | #include "cmp.h" 9 | 10 | #define MAXLINES 1000 11 | 12 | enum sortRules { STR, DIR, NUM }; 13 | 14 | int main(int argc, char *argv[]) { 15 | int sortBy = STR; 16 | int reverse = 0; 17 | int caseSensitive = 1; 18 | FILE *stream = stdin; 19 | 20 | int c; 21 | while ((c = getopt(argc, argv, "dfnr")) != -1) { 22 | if (c == 'd') { 23 | sortBy = DIR; 24 | } else if (c == 'f') { 25 | caseSensitive = 0; 26 | } else if (c == 'n') { 27 | sortBy = NUM; 28 | } else if (c == 'r') { 29 | reverse = 1; 30 | } else if (c == '?') { 31 | if (isprint (optopt)) { 32 | fprintf(stderr, "Error: unknown option '%c'.\n", optopt); 33 | } else { 34 | fprintf(stderr, "Error: unkown character '\\x%x'.\n", optopt); 35 | } 36 | } else { 37 | abort(); 38 | } 39 | } 40 | 41 | char *lines[MAXLINES]; 42 | int len; 43 | if (len = getlines(lines, MAXLINES, stream)) { 44 | int (*cmp)(char *, char *); 45 | if (sortBy == STR) { 46 | cmp = caseSensitive ? strcmp : strcmpi; 47 | } else if (sortBy == DIR) { 48 | cmp = caseSensitive ? dircmp : dircmpi; 49 | } else { 50 | cmp = numcmp; 51 | } 52 | qsort2(lines, 0, len - 1, cmp, reverse); 53 | 54 | int i; 55 | for (i = 0; i < len; i++) { 56 | printf("%s", lines[i]); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/main.input.txt: -------------------------------------------------------------------------------- 1 | abcd 2 | abc 3 | ABC 4 | 3 5 | 12 6 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/makefile: -------------------------------------------------------------------------------- 1 | run: 2 | 3 | gcc main.c getlines.c cmp.c qsort2.c swap.c 4 | ./a.out 2 | #include 3 | 4 | #include "cmp.h" 5 | #include "swap.h" 6 | 7 | void qsort2(char *arr[], int start, int end, int (*cmp)(void *, void *), int reverse) { 8 | if (start >= end) return; 9 | swap(arr, start, (start + end) / 2); 10 | 11 | int i, last = start; 12 | for (i = start + 1; i <= end; i++) { 13 | if (reverse ? cmp(arr[start], arr[i]) < 0 : cmp(arr[start], arr[i]) > 0) { 14 | swap(arr, ++last, i); 15 | } 16 | } 17 | 18 | swap(arr, start, last); 19 | qsort2(arr, start, last - 1, cmp, reverse); 20 | qsort2(arr, last + 1, end, cmp, reverse); 21 | } 22 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/qsort2.h: -------------------------------------------------------------------------------- 1 | #ifndef _QSORT2_H_ 2 | #define _QSORT2_H_ 3 | void qsort2(char *arr[], int start, int end, int (*cmp)(void *, void *), int reverse); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/qsort2.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "cmp.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char s[] = {'t', '\t', 'h', 'r', 'e', 'e', '\t', '\0'}; 9 | char *arr[] = {"one", "TWO", "three", s}; 10 | 11 | qsort2(arr, 0, 3, strcmp); 12 | assert(strcmp(arr[1], "one") == 0); 13 | assert(strcmp(arr[0], "TWO") == 0); 14 | assert(strcmp(arr[2], s) == 0); 15 | assert(strcmp(arr[3], "three") == 0); 16 | 17 | qsort2(arr, 0, 3, strcmpi); 18 | assert(strcmp(arr[0], "one") == 0); 19 | assert(strcmp(arr[3], "TWO") == 0); 20 | assert(strcmp(arr[1], s) == 0); 21 | assert(strcmp(arr[2], "three") == 0); 22 | 23 | qsort2(arr, 0, 3, dircmp); 24 | assert(strcmp(arr[1], "one") == 0); 25 | assert(strcmp(arr[0], "TWO") == 0); 26 | assert(strcmp(arr[2], s) == 0); 27 | assert(strcmp(arr[3], "three") == 0); 28 | 29 | qsort2(arr, 0, 3, dircmpi); 30 | assert(strcmp(arr[0], "one") == 0); 31 | assert(strcmp(arr[3], "TWO") == 0); 32 | assert(strcmp(arr[2], "three") == 0); 33 | assert(strcmp(arr[1], s) == 0); 34 | } 35 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/swap.c: -------------------------------------------------------------------------------- 1 | void swap(char *arr[], int i, int j) { 2 | char *temp = arr[i]; 3 | arr[i] = arr[j]; 4 | arr[j] = temp; 5 | } 6 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/swap.h: -------------------------------------------------------------------------------- 1 | #ifndef _SWAP_H_ 2 | #define _SWAP_H_ 3 | void swap(char *arr[], int i, int j); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-14-qsort/swap.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "swap.h" 5 | 6 | int main(int argc, char *argv[]) { 7 | char *s1 = "one"; 8 | char *s2 = "two"; 9 | char *s3 = "three"; 10 | char *s[] = {s1, s2, s3}; 11 | 12 | swap(s, 0, 2); 13 | 14 | assert(!strcmp(s[0], "three")); 15 | assert(!strcmp(s[2], "one")); 16 | } 17 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/gettoken.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "gettoken.h" 6 | 7 | static int has_unget_token = 0; 8 | 9 | static char *storage_class_specifier[] = { 10 | "auto", "register", "static", "extern", "" 11 | }; 12 | 13 | static char *type_specifier[] = { 14 | "void", "char", "short", "int", 15 | "long", "float", "double", 16 | "signed", "unsigned", "" 17 | }; 18 | 19 | static char *type_qualifier[] = { 20 | "const", "volatile", "" 21 | }; 22 | 23 | static int isinlist(char *s, char *list[]) { 24 | int i; 25 | for (i = 0; strcmp(list[i], "") != 0; i++) { 26 | if (strcmp(s, list[i]) == 0) { 27 | return 1; 28 | } 29 | } 30 | return 0; 31 | } 32 | 33 | static int gettokentype(char *s) { 34 | if (isinlist(s, storage_class_specifier)) { 35 | return STORAGE_CLASS_SPECIFIER; 36 | } else if (isinlist(s, type_specifier)) { 37 | return TYPE_SPECIFIER; 38 | } else if (isinlist(s, type_qualifier)) { 39 | return TYPE_QUALIFIER; 40 | } else { 41 | return IDENTIFIER; 42 | } 43 | } 44 | 45 | 46 | static int nextiseof = 0; 47 | static int charline = 1; 48 | static int charcol = 0; 49 | 50 | static int getch() { 51 | if (nextiseof) { 52 | return EOF; 53 | } 54 | 55 | int c = getc(stream); 56 | if (c == '\n') { 57 | charline++; 58 | charcol = 0; 59 | } else { 60 | charcol++; 61 | } 62 | return c; 63 | } 64 | 65 | static int ungetch(char c) { 66 | if (c == EOF) { 67 | nextiseof = 1; 68 | } else { 69 | if (c == '\n') { 70 | charline--; 71 | charcol = 0; 72 | } else { 73 | charcol--; 74 | } 75 | return ungetc(c, stream); 76 | } 77 | } 78 | 79 | 80 | int gettoken() { 81 | if (has_unget_token) { 82 | has_unget_token = 0; 83 | return tokentype; 84 | } 85 | 86 | int c; 87 | char *p = tokenval; 88 | 89 | while ((c = getch(stream)) == ' ' || c == '\t'); 90 | tokenline = charline; 91 | tokencol = charcol; 92 | 93 | if (c == EOF) { 94 | return tokentype = c; 95 | } else if (c == '(' || c == ')' || c == '[' || c == ']' || c == '*' || c == ',' || c == '\n') { 96 | return tokentype = c; 97 | } else if (isalpha(c)) { 98 | for (*p++ = c; isalnum(c = getch(stream));) { 99 | *p++ = c; 100 | } 101 | *p = '\0'; 102 | ungetch(c); 103 | return tokentype = gettokentype(tokenval); 104 | } else if (isdigit(c)) { 105 | for (*p++ = c; isdigit(c = getch(stream));) { 106 | *p++ = c; 107 | } 108 | *p = '\0'; 109 | ungetch(c); 110 | return tokentype = DIGITS; 111 | } else { 112 | return tokentype = ILLEGAL; 113 | } 114 | } 115 | 116 | 117 | int ungettoken() { 118 | if (has_unget_token) { 119 | printf("Error: call ungettoken() repeatly."); 120 | return 1; 121 | } else { 122 | has_unget_token = 1; 123 | return 0; 124 | } 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/gettoken.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETTOKEN_H_ 2 | #define _GETTOKEN_H_ 3 | 4 | #include 5 | 6 | #define MAXTOKEN 100 7 | 8 | FILE *stream; 9 | 10 | int tokentype; 11 | char tokenval[MAXTOKEN]; 12 | int tokenline; 13 | int tokencol; 14 | 15 | enum tokentypes { 16 | ILLEGAL, 17 | IDENTIFIER, 18 | STORAGE_CLASS_SPECIFIER, 19 | TYPE_SPECIFIER, 20 | TYPE_QUALIFIER, 21 | DIGITS 22 | }; 23 | 24 | int gettoken(); 25 | int ungettoken(); 26 | #endif 27 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/gettoken.input.txt: -------------------------------------------------------------------------------- 1 | const char *( *foo( void *p, int param))[100] -------------------------------------------------------------------------------- /ch05/5-18-dcl/gettoken.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "gettoken.h" 6 | 7 | int main() { 8 | /* 9 | int tokentype; 10 | while ((tokentype = gettoken()) != EOF) { 11 | printf("%s (line:%d, col:%d)\n", tokenval, tokenline, tokencol); 12 | } 13 | */ 14 | stream = stdin; 15 | 16 | assert(gettoken() == TYPE_QUALIFIER); 17 | assert(strcmp(tokenval, "const") == 0); 18 | 19 | ungettoken(); 20 | assert(gettoken() == TYPE_QUALIFIER); 21 | assert(strcmp(tokenval, "const") == 0); 22 | 23 | assert(gettoken() == TYPE_SPECIFIER); 24 | assert(strcmp(tokenval, "char") == 0); 25 | 26 | assert(gettoken() == '*'); 27 | assert(gettoken() == '('); 28 | assert(gettoken() == '*'); 29 | 30 | assert(gettoken() == IDENTIFIER); 31 | assert(strcmp(tokenval, "foo") == 0); 32 | 33 | assert(gettoken() == '('); 34 | 35 | assert(gettoken() == TYPE_SPECIFIER); 36 | assert(strcmp(tokenval, "void") == 0); 37 | 38 | assert(gettoken() == '*'); 39 | 40 | assert(gettoken() == IDENTIFIER); 41 | assert(strcmp(tokenval, "p") == 0); 42 | 43 | assert(gettoken() == ','); 44 | 45 | assert(gettoken() == TYPE_SPECIFIER); 46 | assert(strcmp(tokenval, "int") == 0); 47 | 48 | assert(gettoken() == IDENTIFIER); 49 | assert(strcmp(tokenval, "param") == 0); 50 | 51 | assert(gettoken() == ')'); 52 | assert(gettoken() == ')'); 53 | 54 | assert(gettoken() == '['); 55 | 56 | assert(gettoken() == DIGITS); 57 | assert(strcmp(tokenval, "100") == 0); 58 | 59 | assert(gettoken() == ']'); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gettoken.h" 4 | #include "parse.h" 5 | 6 | int main() { 7 | stream = stdin; 8 | parse(); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/main.input.txt: -------------------------------------------------------------------------------- 1 | char **(*foo())[100] -------------------------------------------------------------------------------- /ch05/5-18-dcl/makefile: -------------------------------------------------------------------------------- 1 | run: 2 | 3 | gcc main.c parse.c gettoken.c 4 | ./a.out 2 | #include 3 | 4 | #include "gettoken.h" 5 | #include "parse.h" 6 | 7 | char specifiers[MAXTOKEN]; 8 | 9 | static void declaration_specifiers(); 10 | static void declarator(); 11 | static int pointers(); 12 | static void direct_declarator(); 13 | static void direct_declarator_simple(); 14 | static void direct_declarator_arr_fn(); 15 | static void director_declarator_postfix(); 16 | static void printError(char *s); 17 | static void expectNext(int c, char *s); 18 | 19 | 20 | void parse() { 21 | declaration_specifiers(); 22 | declarator(); 23 | printf("%s\n", specifiers); 24 | } 25 | 26 | static void declaration_specifiers() { 27 | while (gettoken(), STORAGE_CLASS_SPECIFIER <= tokentype && tokentype <= TYPE_QUALIFIER) { 28 | strcat(specifiers, tokenval); 29 | strcat(specifiers, " "); 30 | } 31 | ungettoken(); 32 | } 33 | 34 | static void declarator() { 35 | gettoken(); 36 | if (tokentype == '*') { 37 | ungettoken(); 38 | int i = pointers(); 39 | direct_declarator(); 40 | while(--i >= 0) { 41 | printf("pointer to "); 42 | } 43 | } else { 44 | ungettoken(); 45 | direct_declarator(); 46 | } 47 | } 48 | 49 | static int pointers() { 50 | int i = 0; 51 | while (gettoken(), tokentype == '*') { 52 | i++; 53 | } 54 | ungettoken(); 55 | return i; 56 | } 57 | 58 | static void direct_declarator() { 59 | direct_declarator_simple(); 60 | direct_declarator_arr_fn(); 61 | } 62 | 63 | static void direct_declarator_simple() { 64 | char s[] = "direct_declarator_simple"; 65 | gettoken(); 66 | if (tokentype == '(') { 67 | declarator(); 68 | expectNext(')', s); 69 | } else if (tokentype == IDENTIFIER) { 70 | printf("%s: ", tokenval); 71 | } else { 72 | printError(s); 73 | } 74 | } 75 | 76 | static void direct_declarator_arr_fn() { 77 | gettoken(); 78 | if (tokentype == '[' || tokentype == '(') { 79 | ungettoken(); 80 | director_declarator_postfix(); 81 | direct_declarator_arr_fn(); 82 | } else { 83 | // epsilon 84 | ungettoken(); 85 | } 86 | } 87 | 88 | static void director_declarator_postfix() { 89 | char s[] ="director_declarator_postfix"; 90 | gettoken(); 91 | if (tokentype == '[') { 92 | gettoken(); 93 | if (tokentype == ']') { 94 | printf("array[] of "); 95 | } else if (tokentype == DIGITS) { 96 | printf("array[%s] of ", tokenval); 97 | expectNext(']', s); 98 | } else { 99 | printError(s); 100 | } 101 | } else if (tokentype == '(') { 102 | while (gettoken(), tokentype != ')') { 103 | } 104 | printf("function() returning "); 105 | } else { 106 | printError(s); 107 | } 108 | } 109 | 110 | 111 | static void printError(char *fn) { 112 | printf("\nParse error: %s\n tokentype: %d,", fn, tokentype); 113 | if (ILLEGAL <= tokentype && tokentype <= DIGITS) { 114 | printf(" tokenval: %s,", tokenval); 115 | } else { 116 | printf(" tokenval: %c,", tokentype); 117 | } 118 | printf(" line: %d, col: %d\n", tokenline, tokencol); 119 | } 120 | 121 | static void expectNext(int c, char *fn) { 122 | gettoken(); 123 | if (tokentype != c) { 124 | printError(fn); 125 | ungettoken(); 126 | } 127 | } 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARSE_H_ 2 | #define _PARSE_H_ 3 | 4 | void parse(); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /ch05/5-18-dcl/sdt.md: -------------------------------------------------------------------------------- 1 | # Simplified Syntax-directed Translation Scheme 2 | 3 | ``` 4 | declaration: 5 | declaration_specifiers declarator {printf("%s", declaration_specifiers)} 6 | 7 | declaration_specifiers: 8 | storage_class_specifier declaration_specifiers? 9 | | type_specifier declaration_specifiers? 10 | | type_qualifier declaration_specifiers? 11 | 12 | storage_class_specifier: 13 | "auto" 14 |  | "register" 15 | | "static" 16 | | "extern" 17 | 18 | type_specifier: 19 | "void" 20 | | "char" 21 | | "short" 22 | | "int" 23 | | "long" 24 | | "float" 25 | | "double" 26 | | "signed" 27 | | "unsigned" 28 | 29 | type_qualifier: 30 | "const" 31 | | "volatile" 32 | 33 | declarator: 34 | direct_declarator 35 | | pointers direct_declarator {printf("%s"), pointers} 36 | 37 | direct_declarator: 38 | identifier 39 | | (declarator) 40 | | direct_declarator "[" digits? "]" 41 | | direct_declarator "(" params? ")" 42 | 43 | pointers: 44 | "*" pointers? 45 | 46 | params: 47 | [^)]* 48 | ``` 49 | 50 | 提取左公因子 51 | 52 | ``` 53 | direct_declarator: 54 | direct_declarator_simple 55 | | direct_declarator director_declarator_postfix 56 | 57 | direct_declarator_simple: 58 | identifier 59 | | (declarator) 60 | 61 | director_declarator_postfix: 62 | "[" digits? "]" 63 | | "(" params? ")" 64 | ``` 65 | 66 | 消除左递归 67 | 68 | ``` 69 | direct_declarator: 70 | direct_declarator_simple direct_declarator_arr_fn 71 | 72 | direct_declarator_simple: 73 | identifier {printf("%s: ", identifier)} 74 | | (declarator) 75 | 76 | direct_declarator_arr_fn: 77 | director_declarator_postfix direct_declarator_arr_fn 78 | | epsilon 79 | 80 | director_declarator_postfix: 81 | "[" digits? "]" {printf("array[%s] of ", digits)} 82 | | "(" params? ")" {printf("function(%s) returning ", params)} 83 | ``` 84 | -------------------------------------------------------------------------------- /ch05/5-2-getfloat/getfloat.c: -------------------------------------------------------------------------------- 1 | /* Exercise 5-2 2 | * Write getfloat, the floating-point analog of getint. 3 | * What type does getfloat return as its function value? 4 | */ 5 | 6 | #include 7 | #include 8 | #include "../5-1-getint/getch.h" 9 | 10 | 11 | int getfloat(double *p) { 12 | int c, sign, nextc, power = 1; 13 | 14 | while (isspace(c = getch())); 15 | 16 | if (!isdigit(c) && c != EOF && c != '-' && c != '+' && c != '.') { 17 | ungetch(c); 18 | return 0; 19 | } 20 | 21 | sign = c == '-' ? -1 : 1; 22 | 23 | if (c == '-' || c == '+') { 24 | nextc = getch(); 25 | if (isdigit(nextc)) { 26 | c = nextc; 27 | } else { 28 | ungetch(nextc); 29 | ungetch(c); 30 | return 0; 31 | } 32 | } 33 | 34 | for (*p = 0.0; isdigit(c); c = getch()) { 35 | //printf("--> %c\n", c); 36 | *p = 10.0 * *p + (c - '0'); 37 | } 38 | 39 | 40 | if (c == '.') { 41 | //printf("==> %c\n", c); 42 | c = getch(); 43 | } 44 | 45 | for (; isdigit(c); c = getch()) { 46 | //printf("--> %c\n", c); 47 | *p = 10.0 * *p + (c - '0'); 48 | power = power * 10.0; 49 | } 50 | 51 | *p = sign * *p / power; 52 | 53 | if (c != EOF) { 54 | ungetch(c); 55 | } 56 | 57 | return c; 58 | } 59 | -------------------------------------------------------------------------------- /ch05/5-2-getfloat/getfloat.h: -------------------------------------------------------------------------------- 1 | #ifndef _GETFLOAT_H_ 2 | #define _GETFLOAT_H_ 3 | int getfloat(double *p); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-2-getfloat/getfloat.input.txt: -------------------------------------------------------------------------------- 1 | 0 -0 123.45 -123.45 +abc -------------------------------------------------------------------------------- /ch05/5-2-getfloat/getfloat.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "./getfloat.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | double d; 9 | 10 | assert(getfloat(&d)); 11 | assert(d == 0.0); 12 | 13 | assert(getfloat(&d)); 14 | assert(d == 0.0); 15 | 16 | assert(getfloat(&d)); 17 | assert(d == 123.45); 18 | 19 | assert(getfloat(&d)); 20 | assert(d == -123.45); 21 | 22 | assert(!getfloat(&d)); 23 | assert(getch() == '+'); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ch05/5-2-getfloat/makefile: -------------------------------------------------------------------------------- 1 | name = getfloat 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c ../5-1-getint/getch.c 6 | ./${name}.test.out <${name}.input.txt 7 | rm ${name}.test.out 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch05/5-3-strcat/makefile: -------------------------------------------------------------------------------- 1 | name = strcat 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c 6 | ./${name}.test.out 7 | rm ${name}.test.out 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch05/5-3-strcat/strcat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Exercise 5-3. 3 | * Write a pointer version of the function strcat that we showed in Chapter 2: strcat(s,t) 4 | * copies the string t to the end of s. 5 | */ 6 | 7 | #include 8 | 9 | void strcat2(char s[], char t[]) { 10 | int i = strlen(s); 11 | char c; 12 | while ((c = *t) != '\0') { 13 | *(s + i++) = c; 14 | t++; 15 | } 16 | *(s + i) = '\0'; 17 | } 18 | -------------------------------------------------------------------------------- /ch05/5-3-strcat/strcat.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRCAT_H_ 2 | #define _STRCAT_H_ 3 | void strcat2(char s[], char t[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-3-strcat/strcat.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "strcat.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char s[100] = {'a', 'b', '\0'}; 9 | char t[100] = {'c', 'd', '\0'}; 10 | 11 | printf("%s\n", s); 12 | assert(!strcmp(s, "abcd")); 13 | } 14 | -------------------------------------------------------------------------------- /ch05/5-4-strend/makefile: -------------------------------------------------------------------------------- 1 | name = strend 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c 6 | ./${name}.test.out 7 | rm ${name}.test.out 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch05/5-4-strend/strend.c: -------------------------------------------------------------------------------- 1 | /* Exercise 5-4. 2 | * Write the function strend(s,t), 3 | * which returns 1 if the string t occurs at the end of the string s, and zero otherwise. 4 | */ 5 | 6 | #include 7 | 8 | int strend(char s[], char t[]) { 9 | int lens = strlen(s); 10 | int lent = strlen(t); 11 | 12 | if (!lent || lens < lent) return 0; 13 | 14 | while (lent > 1) { 15 | if (*(t + lent--) != *(s + lens--)) { 16 | return 0; 17 | } 18 | } 19 | 20 | return 1; 21 | } 22 | -------------------------------------------------------------------------------- /ch05/5-4-strend/strend.h: -------------------------------------------------------------------------------- 1 | #ifndef _STREND_H_ 2 | #define _STREND_H_ 3 | int strend(char s[], char t[]); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-4-strend/strend.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "strend.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | assert(strend("abcde", "cde")); 9 | assert(!strend("abcde", "cdef")); 10 | } 11 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/alloc.c: -------------------------------------------------------------------------------- 1 | #define ALLOCSIZE 10000 2 | 3 | static char allocbuf[ALLOCSIZE]; 4 | static char *allocp = allocbuf; 5 | 6 | char *alloc(int n) { 7 | if (allocbuf + ALLOCSIZE - allocp >= n) { 8 | allocp += n; 9 | return allocp - n; 10 | } else { 11 | return 0; 12 | } 13 | } 14 | 15 | static char allocbuf2[ALLOCSIZE]; 16 | static int allocp2 = 0; 17 | 18 | char *alloc2(int n) { 19 | if (ALLOCSIZE - allocp2 >= n) { 20 | allocp2 += n; 21 | return &allocbuf2[allocp2 - n]; 22 | } else { 23 | return 0; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_C_ 2 | #define _ALLOC_C_ 3 | char *alloc(int n); 4 | char *alloc2(int n); 5 | #endif 6 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "readlines.h" 4 | #include "qsort.h" 5 | 6 | #define MAXLINES 5000 7 | 8 | char *lineptr[MAXLINES]; 9 | 10 | int main(int argc, char *argv[]) { 11 | int nlines; 12 | 13 | if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { 14 | qsort(lineptr, 0, nlines - 1); 15 | writelines(lineptr, nlines); 16 | return 0; 17 | } else { 18 | printf("Error: input too big to sort.\n"); 19 | return 1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/makefile: -------------------------------------------------------------------------------- 1 | name = readlines 2 | 3 | all: 4 | 5 | gcc -o main.out main.c readlines.c qsort.c alloc.c 6 | ./main.out <${name}.input.txt 7 | 8 | test: 9 | 10 | gcc -o ${name}.test.out ${name}.test.c ${name}.c alloc.c 11 | ./${name}.test.out <${name}.input.txt 12 | rm ${name}.test.out 13 | 14 | gcc -o qsort.test.out qsort.test.c qsort.c alloc.c 15 | ./qsort.test.out 16 | rm qsort.test.out 17 | 18 | 19 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/qsort.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static swap(char *v[], int i, int j) { 4 | char *temp = v[i]; 5 | v[i] = v[j]; 6 | v[j] = temp; 7 | } 8 | 9 | void qsort(char *v[], int left, int right) { 10 | int i, last; 11 | if (left >= right) { 12 | return; 13 | } 14 | swap(v, left, (left + right) / 2); 15 | last = left; 16 | for (i = left + 1; i <= right; i++) { 17 | if (strcmp(v[i], v[left]) < 0) { 18 | swap(v, ++last, i); 19 | } 20 | } 21 | swap(v, left, last); 22 | qsort(v, left, last - 1); 23 | qsort(v, last + 1, right); 24 | } 25 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/qsort.h: -------------------------------------------------------------------------------- 1 | #ifndef _QSORT_H_ 2 | #define _QSORT_H_ 3 | void qsort(char *v[], int left, int right); 4 | #endif 5 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/qsort.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qsort.h" 6 | 7 | int main(int argc, char *argv[]) { 8 | char *arr[4] = { 9 | "abc", 10 | "aaa", 11 | "aab", 12 | "abb" 13 | }; 14 | qsort(arr, 0, 3); 15 | assert(!strcmp(arr[0], "aaa")); 16 | assert(!strcmp(arr[3], "abc")); 17 | } 18 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/readlines.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "alloc.h" 5 | 6 | #define MAXLEN 1000 7 | 8 | int readlines(char *lineptr[], int maxlines) { 9 | int len, nlines = 0; 10 | char *p, line[MAXLEN]; 11 | while (gets(line)) { 12 | len = strlen(line); 13 | if (nlines >= maxlines || !(p = alloc(len + 1))) { 14 | return -1; 15 | } else { 16 | strcpy(p, line); 17 | lineptr[nlines++] = p; 18 | } 19 | } 20 | return nlines; 21 | } 22 | 23 | void writelines(char *lineptr[], int nlines) { 24 | while (nlines-- > 0) { 25 | printf("%s\n", *lineptr++); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/readlines.h: -------------------------------------------------------------------------------- 1 | #ifndef _READLINE_H_ 2 | #define _READLINE_H_ 3 | int readlines(char *lineptr[], int maxlines); 4 | void writelines(char *lineptr[], int nlines); 5 | #endif 6 | -------------------------------------------------------------------------------- /ch05/5-7-readlines/readlines.input.txt: -------------------------------------------------------------------------------- 1 | first line 2 | second line 3 | third line 4 | last line -------------------------------------------------------------------------------- /ch05/5-7-readlines/readlines.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "readlines.h" 6 | 7 | #define MAX 100 8 | int main(int argc, char *argv[]) { 9 | char *lineptr[MAX]; 10 | int nlines = readlines(lineptr, MAX); 11 | assert(nlines == 4); 12 | assert(!strcmp(lineptr[0], "first line")); 13 | assert(!strcmp(lineptr[3], "last line")); 14 | 15 | printf("--- start write lines ---\n"); 16 | writelines(lineptr, nlines); 17 | } 18 | -------------------------------------------------------------------------------- /ch05/5-8-monthday/makefile: -------------------------------------------------------------------------------- 1 | name = monthday 2 | 3 | test: 4 | 5 | gcc -o ${name}.test.out ${name}.test.c ${name}.c 6 | ./${name}.test.out 7 | rm ${name}.test.out 8 | -------------------------------------------------------------------------------- /ch05/5-8-monthday/monthday.c: -------------------------------------------------------------------------------- 1 | static char daytab[2][13] = { 2 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 3 | {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 4 | }; 5 | 6 | static int isleap(int year) { 7 | return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; 8 | } 9 | 10 | void monthday(int y, int d, int *pm, int *pd) { 11 | int i, leap = isleap(y); 12 | 13 | if (d <= 0) { 14 | *pm = 0; 15 | *pd = 0; 16 | return; 17 | } 18 | 19 | for (i = 1; d > daytab[leap][i]; i++) { 20 | if (i == 12) { 21 | *pm = 0; 22 | *pd = 0; 23 | return; 24 | } 25 | d -= daytab[leap][i]; 26 | } 27 | 28 | *pm = i; 29 | *pd = d; 30 | } 31 | 32 | int dayofyear(int y, int m, int d) { 33 | int i, leap = isleap(y); 34 | 35 | if (m < 1 || m > 12 || d < 1 || d > *(*(daytab + leap) + m)) { 36 | return 0; 37 | } 38 | 39 | for (i = 1; i < m; i++) { 40 | d += *(*(daytab + leap) + i); 41 | } 42 | 43 | return d; 44 | } 45 | -------------------------------------------------------------------------------- /ch05/5-8-monthday/monthday.h: -------------------------------------------------------------------------------- 1 | #ifndef _MONTHDAY_H_ 2 | #define _MONTHDAY_H_ 3 | void monthday(int y, int d, int *pm, int *pd); 4 | int dayofyear(int y, int m, int d); 5 | #endif 6 | -------------------------------------------------------------------------------- /ch05/5-8-monthday/monthday.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "monthday.h" 4 | 5 | int main(int argc, char *argv[]) { 6 | int m; 7 | int d; 8 | 9 | monthday(0, 0, &m, &d); 10 | assert(m == 0 && d == 0); 11 | 12 | monthday(0, 367, &m, &d); 13 | assert(m == 0 && d == 0); 14 | 15 | monthday(0, 60, &m, &d); 16 | assert(m == 2 && d == 29); 17 | 18 | assert(dayofyear(0, -1, 0) == 0); 19 | 20 | assert(dayofyear(0, 13, 1) == 0); 21 | 22 | assert(dayofyear(0, 12, 32) == 0); 23 | 24 | assert(dayofyear(2013, 2, 13) == 44); 25 | } 26 | -------------------------------------------------------------------------------- /ch06/6-5-lookup/lookup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "lookup.h" 6 | 7 | #define LEN 1000 8 | 9 | static struct item *htable[LEN]; 10 | 11 | static char *strdup2(char *s) { 12 | char *p = (char *) malloc(strlen(s) + 1); 13 | if (p != NULL) { 14 | strcpy(p, s); 15 | } 16 | return p; 17 | } 18 | 19 | static unsigned hash(char *name) { 20 | unsigned val; 21 | for(val = 0; *name != '\0'; name++) { 22 | val = *name + 31 * val; 23 | } 24 | return val % LEN; 25 | } 26 | 27 | struct item *lookup(char *name) { 28 | unsigned hashval = hash(name); 29 | struct item *itemp; 30 | for (itemp = htable[hashval]; itemp != NULL; itemp = itemp->next) { 31 | if (strcmp(name, itemp->name) == 0) { 32 | return itemp; 33 | } 34 | } 35 | return NULL; 36 | } 37 | 38 | struct item *install(char *name, char *value) { 39 | struct item *itemp; 40 | if ((itemp = lookup(name)) == NULL) { 41 | itemp = (struct item *) malloc(sizeof(struct item)); 42 | 43 | if (itemp == NULL) { 44 | return NULL; 45 | } 46 | 47 | if ((itemp->name = strdup2(name)) == NULL) { 48 | free((void *) itemp); 49 | return NULL; 50 | } 51 | 52 | unsigned hashval = hash(name); 53 | itemp->next = htable[hashval]; 54 | htable[hashval] = itemp; 55 | } else { 56 | free((void *) itemp->value); 57 | } 58 | 59 | if ((itemp->value = strdup2(value)) == NULL) { 60 | return NULL; 61 | } 62 | 63 | return itemp; 64 | } 65 | 66 | void undef(char *name) { 67 | unsigned hashval = hash(name); 68 | struct item *itemp; 69 | struct item *previtemp; 70 | for (itemp = htable[hashval]; itemp != NULL; previtemp = itemp, itemp = itemp->next) { 71 | if (strcmp(name, itemp->name) == 0) { 72 | if (previtemp == NULL) { 73 | htable[hashval] = itemp->next; 74 | } else { 75 | previtemp->next = itemp->next; 76 | } 77 | free(itemp->name); 78 | free(itemp->value); 79 | free(itemp); 80 | } 81 | } 82 | } 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /ch06/6-5-lookup/lookup.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOOCKUP_H_ 2 | #define _LOOCKUP_H_ 3 | struct item { 4 | char *name; 5 | char *value; 6 | struct item *next; 7 | }; 8 | 9 | struct item *lookup(char *name); 10 | struct item *install(char *name, char *value); 11 | void undef(char *name); 12 | #endif 13 | -------------------------------------------------------------------------------- /ch06/6-5-lookup/lookup.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "lookup.h" 6 | 7 | int main() { 8 | assert(lookup("name") == NULL); 9 | 10 | install("name", "fool2fish"); 11 | assert(strcmp(lookup("name")->value, "fool2fish") == 0); 12 | 13 | install("name", "chenyu"); 14 | assert(strcmp(lookup("name")->value, "chenyu") == 0); 15 | 16 | undef("name"); 17 | assert(lookup("name") == NULL); 18 | } 19 | -------------------------------------------------------------------------------- /ch06/6-5-lookup/makefile: -------------------------------------------------------------------------------- 1 | test: 2 | 3 | gcc lookup.test.c lookup.c 4 | ./a.out 5 | rm a.out -------------------------------------------------------------------------------- /ch07/7-3-minprintf/makefile: -------------------------------------------------------------------------------- 1 | run: 2 | 3 | gcc minprintf.c 4 | ./a.out 5 | rm a.out -------------------------------------------------------------------------------- /ch07/7-3-minprintf/minprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void minprintf(char *fmt, ...) { 5 | va_list ap; 6 | char *p, *sval; 7 | int ival; 8 | double dval; 9 | 10 | va_start(ap, fmt); 11 | for (p = fmt; *p; p++) { 12 | if (*p != '%') { 13 | putchar(*p); 14 | continue; 15 | } 16 | switch (*++p) { 17 | case 'd': 18 | ival = va_arg(ap, int); 19 | printf("%d", ival); 20 | break; 21 | case 'o': 22 | ival = va_arg(ap, int); 23 | printf("%o", ival); 24 | break; 25 | case 'x': 26 | case 'X': 27 | ival = va_arg(ap, int); 28 | printf("%x", ival); 29 | break; 30 | case 'u': 31 | ival = va_arg(ap, int); 32 | printf("%u", ival); 33 | break; 34 | case 'c': 35 | ival = va_arg(ap, int); 36 | putchar(ival); 37 | break; 38 | case 'f': 39 | dval = va_arg(ap, double); 40 | printf("%f", dval); 41 | break; 42 | case 's': 43 | printf("%s", va_arg(ap, char *)); 44 | break; 45 | case '%': 46 | putchar('%'); 47 | break; 48 | default: 49 | putchar(*p); 50 | break; 51 | } 52 | } 53 | va_end(ap); 54 | } 55 | 56 | int main() { 57 | minprintf( 58 | "%%, %d, %o, %x, %u, %c, %s, %f\n", 59 | 63, 63, 63, 63, 63, "abc", 63.0 60 | ); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /ch07/7-6-diff/a.txt: -------------------------------------------------------------------------------- 1 | text 2 | text 3 | text different 4 | text -------------------------------------------------------------------------------- /ch07/7-6-diff/b.txt: -------------------------------------------------------------------------------- 1 | text 2 | text 3 | text 4 | text 5 | -------------------------------------------------------------------------------- /ch07/7-6-diff/diff.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define LEN 1000 6 | 7 | static void rmlb(char *p) { 8 | int len = strlen(p); 9 | if (len > 1 && p[len - 1] == '\n') { 10 | p[len - 1] = '\0'; 11 | } 12 | } 13 | 14 | int diff(char *name1, char *name2) { 15 | FILE *f1, *f2; 16 | if ((f1 = fopen(name1, "r")) == NULL || (f2 = fopen(name2, "r")) == NULL) { 17 | fprintf(stderr, "Error: cannot open file: %s\n", f1 == NULL ? name1 : name2); 18 | exit(1); 19 | } 20 | 21 | char s1[LEN], s2[LEN], *p1, *p2; 22 | int line = 0; 23 | while (++line, p1 = fgets(s1, LEN, f1), p2 = fgets(s2, LEN, f2), p1 != NULL && p2 != NULL) { 24 | rmlb(s1); 25 | rmlb(s2); 26 | if (strcmp(s1, s2) != 0) { 27 | printf("First different at line:%d\n", line); 28 | printf("%s: %s\n%s: %s\n", name1, s1, name2, s2); 29 | return line; 30 | } 31 | } 32 | 33 | if (p1 != NULL || p2 != NULL) { 34 | printf("File: %s reached EOF or encounters an error.\n", f1 == NULL ? name1 : name2); 35 | return line; 36 | } 37 | 38 | printf("No diff."); 39 | return 0; 40 | } 41 | 42 | int main() { 43 | diff("a.txt", "b.txt"); 44 | } 45 | -------------------------------------------------------------------------------- /ch07/7-6-diff/makefile: -------------------------------------------------------------------------------- 1 | run: 2 | 3 | gcc diff.c 4 | ./a.out 5 | rm a.out -------------------------------------------------------------------------------- /key-note/init-arr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int global[2]; 4 | int global2[2] = {1}; 5 | 6 | int main() { 7 | int local[2]; 8 | int local2[2] = {1}; 9 | printf("global[0]: %d\n", global[0]); 10 | printf("global2: {%d, %d}\n", global2[0], global2[1]); 11 | printf("local[0]: %d\n", local[0]); 12 | printf("local2: {%d, %d}\n", local2[0], local2[1]); 13 | } 14 | -------------------------------------------------------------------------------- /key-note/init-global.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char a[] = "a char list"; 5 | char *p = "a string const"; 6 | char *list[] = {a, p}; 7 | 8 | int main(){} 9 | -------------------------------------------------------------------------------- /key-note/key-note.md: -------------------------------------------------------------------------------- 1 | ### 待整理 2 | 3 | - gcc 的使用 4 | - 寄存器变量(p71) 5 | - #define function() 的优势 (为确保正确的优先级,所有得参数都要用括号括起来,很烦人啊) 6 | - #undefine 已定义的宏 7 | - 附录A:参考手册 8 | - 内部声明 & 外部声明(p168) 9 | 10 | --- 11 | 12 | ### 隐式转换 13 | 14 | ``` 15 | int main() { 16 | int i = 0x7fffffff; // 假定在 32 位机上运行 17 | long long j = i + 1; 18 | long long k = i + (long long) 1; 19 | printf("%lld, %lld\n", j, k); // 输出 "-2147483648, 2147483648" 20 | } 21 | ``` 22 | 23 | 计算 `i + 1` 时,加号两边类型相同,不需要进行类型转换,直到将相加的值赋值给 j 时,发现等号两边类型不同,才进行类型转换。 24 | 25 | 26 | ### const 27 | 28 | ``` 29 | #include 30 | #include 31 | 32 | int main(){ 33 | char s1[] = "a"; 34 | char s2[] = "d"; 35 | printf("%d\n", strcmp(s1, s2)); // -3 36 | printf("%d\n", strcmp("a", "d")); // -1 37 | } 38 | ``` 39 | 40 | 疑问:为什么输出结果不一样?注意 `strcmp(const char *, const char *)` 的声明要求参数是 const。 41 | 42 | ``` 43 | char* const a 44 | char const *p 45 | ``` 46 | 47 | ### 初始化 48 | 49 | 在不进行显示初始化的情况下: 50 | 51 | 1. 外部变量和静态变量被初始化为 0。 52 | 2. 自动变量和寄存器变量的初值没有定义(即为无用信息,可能为任意值)。 53 | 54 | 初始化时: 55 | 56 | 1. 外部变量和静态变量的初始化表达式必须为常量表达式([为什么?](http://blog.csdn.net/rosetta/article/details/6603370))。 57 | 2. 自动变量和寄存器变量可以不是常量表达式。 58 | 3. 如果初始化表达式的个数比数组元素个数少,则不管该数组是外部变量、静态变量还是自动变量,剩余没有初始化表达式的元素都被初始化为 0。 59 | 60 | 61 | #### 数组初始化 62 | 63 | file: init-arr.c 64 | 65 | ``` 66 | #include 67 | 68 | int global[2]; 69 | int global2[2] = {1}; 70 | 71 | int main() { 72 | int local[2]; 73 | int local2[2] = {1}; 74 | printf("global[0]: %d\n", global[0]); 75 | printf("global2: {%d, %d}\n", global2[0], global2[1]); 76 | printf("local[0]: %d\n", local[0]); 77 | printf("local2: {%d, %d}\n", local2[0], local2[1]); 78 | } 79 | ``` 80 | 81 | 运行结果: 82 | 83 | ``` 84 | global[0]: 0 85 | global2: {1, 0} 86 | local[0]: 32767 87 | local2: {1, 0} 88 | ``` 89 | 90 | 91 | #### 字符串数组全局变量初始化 92 | 93 | file: init-global.c 94 | 95 | ``` 96 | #include 97 | 98 | char a[] = "a char list"; 99 | char *p = "a string const"; 100 | char *list[] = {a, p}; 101 | 102 | int main(){} 103 | ``` 104 | 105 | 编译结果: 106 | 107 | ``` 108 | init-global.c:5: error: initializer element is not constant 109 | init-global.c:5: error: (near initialization for ‘list[1]’) 110 | ``` 111 | 112 | 疑问:为什么会报上面的错误? 113 | 114 | 115 | ### 函数和变量的作用域 116 | 117 | file: scope/scope.c 118 | 119 | ``` 120 | #include 121 | 122 | static int fv = 1; // 文件内可访问变量 123 | int gv = 1; 124 | int gv2 = 1; 125 | 126 | static void foo() { // 文件内可访问函数 127 | printf("foo()\n"); 128 | } 129 | 130 | void bar() { 131 | printf("bar()\n"); 132 | } 133 | 134 | void bar2() { 135 | printf("bar2()\n"); 136 | } 137 | ``` 138 | 139 | file: scope/scope.h 140 | 141 | ``` 142 | #ifndef _SCOPE_H_ 143 | #define _SCOPE_H_ 144 | 145 | int gv; 146 | void bar(); 147 | 148 | #endif 149 | ``` 150 | 151 | file: scope/main.c 152 | 153 | ``` 154 | #include 155 | #include "scope.h" 156 | 157 | // int gv2 = 2; 158 | // 错误!重复定义全局变量 159 | // ld: 1 duplicate symbol for architecture x86_64 160 | 161 | extern int gv2; 162 | // int gv2; 163 | // 头文件中未声明,需先声明,再使用 164 | // 疑问:为什么加不加 extern 都可以? 165 | 166 | int main() { 167 | // int gv2 = 2; 168 | // 局部变量覆盖全局变量 169 | printf("gv: %d\n", gv); 170 | printf("gv2: %d\n", gv2); // 头文件中声明,可直接使用 171 | bar(); 172 | bar2(); // 疑问:为什么不在头文件中声明也能访问? 173 | } 174 | 175 | ``` 176 | 177 | 178 | ### 多维数组作为参数传递给函数 179 | 180 | ``` 181 | void foo(char arr[][]) {...} // 错误!type of formal parameter 1 is incomplete 182 | 183 | void foo(char **arr) {...} // 错误!passing argument 1 of ‘foo’ from incompatible pointer type 184 | 185 | void foo(char arr[][100]) // 正确:arr 指向第一行(arr[0]) 186 | // 程序需要知道行大小(100 * sizeof char) 187 | // 不管是几维数组,只有第一维可以省略传递数组大小 188 | // 不然怎么知道 arr + 1 指向哪里呢:) 189 | 190 | void foo(char (*arr)[100]) // 正确:但鉴于其可读性和可维护性较差,推荐上面的写法 191 | ``` 192 | 193 | 194 | ### 字符串和数组 195 | 196 | 1. 声明 197 | 198 | ``` 199 | char v[4] = {'a', 'b', 'c', '\0'}; // 长度为4的字符数组 200 | char a[] = "abc"; // 同上 201 | char *s = "def"; // 指向字符串 "def" 第一个字符的指针 202 | ``` 203 | 204 | 2. 赋值 205 | 206 | ``` 207 | a = "newabc" // 错误!数组名不能进行赋值操作 208 | a++ // 错误!同上 209 | s = "newdef" // 指针 s 指向新字符串 "newdef" 第一个字符 210 | s++ // 指针 s 指向其下一个字符,即 'e' 211 | ``` 212 | 213 | 3. 作为参数传递给函数 214 | 215 | ``` 216 | #include 217 | 218 | void foo(char s[]) { 219 | printf("%c\n", *++s); 220 | } 221 | 222 | int main() { 223 | char a[] = {'a', 'b', 'c', '\0'}; 224 | foo(a); // 数组名作为参数传递给一个函数时 225 | // 实际上传递的是该数组第一个元素的地址副本 226 | // 于是可以对该副本进行赋值操作 227 | printf("%c\n", *++a); // 错误!数组名不能进行赋值操作 228 | } 229 | ``` 230 | 231 | 4. 修改字符元素 232 | 233 | ``` 234 | #include 235 | 236 | void bar(char *s) { 237 | s[0] = 'z'; 238 | printf("%s\n", s); 239 | } 240 | 241 | int main() { 242 | char *s = "abc"; 243 | s[0] = 'y'; // 错误!字符串不能被修改 244 | bar(s); // 错误!虽然传递给 bar 的是一个地址副本 245 | // 但其指向的仍然是字符串 246 | } 247 | ``` 248 | 249 | 所以,书上类似 `reverse(char s[])` 之类的函数实现,只能处理字符数组,而不能处理字符串常量。 250 | 251 | 252 | ### 有效的指针运算 253 | 254 | - 同类指针之间的赋值 255 | - 指针同整数之间的加减法 256 | - 指向相同数组中元素的两个指针间的减法或比较运算 257 | - 将指针赋值为 0 或与 0 的比较运算 258 | 259 | ``` 260 | // 求两个指针的中间值 261 | int main(){ 262 | char s[] = "abcde"; 263 | char *l = s; 264 | char *h = &s[4]; 265 | char *m = l + (h - l) / 2; 266 | // char *m = (l + h) / 2; 错误:指针之间不能相加 267 | // error: invalid operands to binary expression ('char *' and 'char *') 268 | printf("%c\n", *m); 269 | } 270 | ``` 271 | 272 | 273 | ### 计算数组的长度 274 | 275 | ``` 276 | size_t length = sizeof arr / sizeof arr[0] 277 | ``` 278 | 279 | 条件编译语句 `#if` 中不能使用 `sizeof`, 因为预处理器不对类型名进行分析。但预处理器并不计算 `#define` 语句中的表达式,因此在 `#dfine` 中使用`sizeof` 是合法的。 280 | 281 | 282 | ### 命令行参数中的通配符 283 | 284 | Unix 系统中,shell 脚本会自动对通配符(*)进行扩展,替换为当前目录下所有的文件和一级子目录列表。 285 | 286 | 例如下面计算后缀表达式的程序: 287 | 288 | ``` 289 | $ calculate 2 3 4 + * // 错误! 290 | 291 | $ calculate 2 3 4 + "*" // 正确:单双引号均可阻止通配符扩展 292 | ``` 293 | 294 | 295 | ### 函数参数的计算顺序 296 | 297 | 函数调用时,传入的参数求值顺序不定,因此当传入参数的求值顺序有要求,须在函数调用前求值完毕。 298 | 299 | ``` 300 | #include 301 | 302 | void foo(int a, int b, int c) { 303 | printf("%d, %d, %d\n", a, b, c); 304 | } 305 | 306 | int main() { 307 | int i = 0; 308 | foo(i++, i++, i++); // 可能输出 "2, 1, 0" 309 | } 310 | ``` -------------------------------------------------------------------------------- /key-note/scope/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "scope.h" 3 | 4 | // int gv2 = 2; 5 | // 错误!重复定义全局变量 6 | // ld: 1 duplicate symbol for architecture x86_64 7 | 8 | extern int gv2; 9 | // int gv2; 10 | // 头文件中未声明,需先声明,再使用 11 | // 疑问:为什么加不加 extern 都可以? 12 | 13 | int main() { 14 | // int gv2 = 2; 15 | // 局部变量覆盖全局变量 16 | printf("gv: %d\n", gv); 17 | printf("gv2: %d\n", gv2); // 头文件中声明,可直接使用 18 | bar(); 19 | bar2(); // 疑问:为什么不在头文件中声明也能访问? 20 | } 21 | -------------------------------------------------------------------------------- /key-note/scope/scope.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int fv = 1; // 文件内可访问变量 4 | int gv = 1; 5 | int gv2 = 1; 6 | 7 | static void foo() { // 文件内可访问函数 8 | printf("foo()\n"); 9 | } 10 | 11 | void bar() { 12 | printf("bar()\n"); 13 | } 14 | 15 | void bar2() { 16 | printf("bar2()\n"); 17 | } 18 | -------------------------------------------------------------------------------- /key-note/scope/scope.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCOPE_H_ 2 | #define _SCOPE_H_ 3 | 4 | int gv; 5 | void bar(); 6 | 7 | #endif 8 | --------------------------------------------------------------------------------