K&R学习笔记 第三章

来源:互联网 发布:玉米数据库 编辑:程序博客网 时间:2024/05/16 13:56
这一章讲控制流,基本就是if-else、while、do-while、switch-case之类的。基本的东西大家都懂。需要强调的是在默认状态下,if-else语句中的else是与之前最近的if匹配的,所以如果这不是你的本意,那么最好加上大括号括起来。其实我几乎不会犯这个错误,因为我写程序时,习惯于即便if后面只有一条语句,我也会打上括号(这个习惯好像是看C++primer上养成的)。

书中给出了一个shell排序算法的程序

void shellsort(int V[], int n){int gap, i, j, temp;for (gap = n/2; gap > 0; gap /= 2)for (i = gap; i < n; i++)for (j = i-gap; j>=0 && V[j]>V[j+gap]; j -= gap) {temp = V[j];V[j] = V[j+gap];V[j+gap] = temp;}}

恕我愚钝,我至今还没有完全弄明白它是怎么搞的。一般人的shell排序算法写不了这么简洁。

这个程序也让我感想颇多,大牛有时候是不一定会考虑小白们的感受的,就好比有时候数学书上的一句“显然……”,就可能难倒一大片学生。不光是中国人喜欢简洁、漂亮的东西(比如同济的《高等数学》,其实那本书写的很不错),国外的人也一样。但是国外的入门书籍一般都会煞费苦心的萝莉啰嗦的讲很多东西,国内的很多书可没有这个耐心。

书里面有个习题很有意思,就是将数字转化为对应的字符串:

void itoa(int n, char s[]){int i, sign;if ((sign = n) < 0) /* record sign */n = -n; /* make n positive */i = 0;do { /* generate digits in reverse order */s[i++] = n % 10 + '0'; /* get next digit */} while ((n /= 10) > 0); /* delete it */if (sign < 0)s[i++] = '-';s[i] = '\0';reverse(s);}

但是在习题中,告诉你这个程序是不能转化最小的负数的:即-2^(n-1),这是因为通过程序,可以看出,这段代码先提取正负号,然后把剩下的数字转化为对应的字符。但是当遇到最小的负数时,因为n位能表达的最大的数字是2^(n-1)-1(有一位用作符号位了),所以不能简单地采用对于负数,先求出他的相反数,然后利用这个相反数化成字符串,最后在前面补上负号来实现。对于这种特殊的情况,可以采用对于每次求模运算时计算绝对值,最后补上负号来绕过这个问题:

#define abs(x) ((x)<0 ? -(x):(x))void reverse(char s[]){int c, i , j;for(i = 0, j = strlen(s)-1;i < j;i++,j--){c = s[i];s[i] = s[j];s[j] = c;}}void itoa(int n, char s[]){int i ,sign;sign = n;i = 0;do{s[i++] = abs(n % 10) + '0';}while((n /= 10) != 0);if(sign < 0)s[i++] = '-';s[i] = '\0';reverse(s);}

这个例子也提醒我们,写程序时,有时候还是需要注意体层和一些边界值情况,否则有可能出错的。