K&R学习笔记 第三章

这一章讲控制流,基本就是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);
}

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

你可能感兴趣的:(K&R,学习笔记)