第4章 函数和程序结构
函数要有高效性和易用性
4.1 函数的基本内容
查看strindex()的实现,该功能和strstr()类似, 都是查找子串的位置
int strindex(char s[], char t[]) { int idx, i, j; for (idx = 0; s[idx] != '\0'; idx++) { for (i = idx, j = 0; t[j] != '\0' && s[i] == t[j]; i++, j++); if (t[j] == '\0' && j > 0) return idx; } return -1; }
理解上述代码:
1. 如果s短,s[i]是否会越界?不会,因为第二层循环中,s[i]=='\0'时,循环肯定会结束
2. if判断中,j>0 什么作用?我认为当 t[] = '\0'时,起到检查作用
4_1 练习编写strrindex(s, t), 它将返回字符串t在s中最右边出现的位置,如果s中不包含t,就返回-1
int strindex(char s[], char t[]) { int i, k, pos = -1; for (i = 0; s[i] != '\0'; i++) { for (k = 0; t[k] != '\0' && s[i + k] == t[k]; k++); // 查找t 是否在 s 中 if (t[k] == '\0' && k > 0) pos = i; // i += k-1; // 加上这一行,可以跳过 刚才遍历的 substr } return pos; }
4.2 返回非整型值的函数
练习 4_2 对atof函数进行扩充,使它可以处理形如123.45e-6的科学表示法
#include <stdio.h> #include <ctype.h> double atof(char *s) { double val, power; int i, sign; for (i = 0; isspace(s[i]); i++); //跳过空白符 sign = ('-' == s[i]) ? -1 : 1; if ('-' == s[i] || '+' == s[i]) i++; for (val = 0.0; isdigit(s[i]); i++) { val = val * 10 + s[i] - '0'; } if (s[i] == '.') i++; for (power = 1.0;isdigit(s[i]); i++){ val = val * 10 + s[i] - '0'; power *= 10.0; } val = val * sign / power; if (s[i] == 'e' || s[i] == 'E') { // 处理指数部分 sign = ('-' == s[++i]) ? 0 : 1; if ('-' == s[i] || '+' == s[i]) i++; int exp = 0; for (; isdigit(s[i]); i++) exp = exp * 10 + s[i] - '0'; while (exp-- > 0) { if (sign) val *= 10; else val /= 10; // 不乘0.1 是为了减少误差 } } return val; }
4.3 外部变量
应避免外部变量和局部变量的名子一样
这一节 介绍了 处理逆波兰表达式的代码,代码中使用getop()函数处理 字符串
int getch(void); void ungetch(int); int getop(char s[]) { int i, c; while ((s[0] = c = getch()) == ' ' || c == '\t'); s[1] = '\0'; if (!isdigit(c) && c != '.') return c; i = 0; if (isdigit(c)) while (isdigit(s[++i] = c = getch())); if (c == '.') while (isdigit(s[++i] = c = getch())); s[i] = '\0'; if (c != EOF) ungetch(c); return '0'; } #define BUFSIZE 100 char buf[BUFSIZE]; int bufp = 0; // next free position in buf int getch(void) { return (bufp > 0) ? buf[--bufp] : getchar(); } void ungetch(int c) { if (bufp >= BUFSIZE) printf("ungetch: too many characters\n"); else buf[bufp++] = c; }
思考:1.这个getch() 中使用的buf 只用 2个字节是不是就足够了? 2. 这个getop() 使用的s[] 最大可以装下 INT_MIN的位数, 就可以?
4.9 初始化
对于外部变量和静态变量,初始化表达式必须是常量表达式,且只初始化一次
4.10 递归
我看书中的printd() 不能处理INT_MIN, 自己的修改如下;然后对比 练习 4-12发现了 劣处
#include <stdio.h> #include <stdlib.h> #include <limits.h> void print_d(int num) { if (num == 0) return; if (num < 0) putchar('-'); print_d(abs(num / 10)); putchar(abs(num % 10) + '0'); } void main() { int num = INT_MIN; print_d(num); while(scanf("%d", &num)>= 0) { print_d(num); putchar('\n'); } }
练习 4-12 使用printd 的思想重写 递归半版本的 itoa()函数
#include <stdio.h> #include <stdlib.h> #include <limits.h> //#define abs(x) ((x) < 0 ? (-x) : (x)) void itoa(int n, char *s) { static int i; // 默认初值就是0 if (n / 10) { itoa(n / 10, s); } else { // 说明 n 已经个位数 i = 0; if (n < 0) s[i++] = '-'; } s[i++] = abs(n % 10) + '0'; // 使用宏 ABS(x) 会出错;并且 abs(n)%10 也是 -8 s[i] = 0; } void main() { char s[20]; int n = INT_MIN;
itoa(n, s); printf("n=%d, s=%s\n", n, s); while (scanf("%d", &n) >= 0) { itoa(n, s); printf("s=%s\n", s); } }

浙公网安备 33010602011771号