代码改变世界

Functions and Program Structure_3

2017-02-09 18:07  星星之火✨🔥  阅读(153)  评论(0)    收藏  举报

1、运用printd 函数的设计思想编写一个递归版本的itoa 函数。即通过递归调用把整数转换为字符串。

#include <math.h>

// itoa: convert n to characters in s; recursive
void itoa(int n, char s[])
{
	static int i;
	
	if(n/10)
		itoa(n/10, s);
	else
	{
		i = 0;
		if(n < 0)
			s[i++] = '-';
	}
	s[i++] = abs(n) % 10 + '0';
	s[i] = '\0';
}

itoa 需要用到两个参数,一个是待转换为字符串的整数n,一个是用来保存结果的字符数组s。如果整数除法n/10 的结果不为零,itoa 就以整数n/10 为参数调用自身。如果n/10 在某次递归调用中结果为零,我们就得到了整数n 的最高(左)位数字。我们用一个static 变量i 作为字符数组的索引。如果n 是一个负数,我们就在字符数组的第一个位置放上一个符号并对变量i 进行递增。因为这个itoa 函数时递归性的,所以它将按照从左到右的顺序计算出整数n 的每一位数字。

需要注意的是:每次递归调用将用一个"\0" 字符来结束字符数组s,但下一次递归调用(除最后一次外)将覆盖掉这个"\0" 字符。

2、编写一个递归版本的reverse(s) 函数,将字符串s 倒置。

#include <string.h>

// reverse: reverse string s in place

void reverse(char s[])
{
	void reverser(char s[], int i, int len);
	
	reverser(s, 0, strlen(s));	
}

// reverser: reverse string s in place; recursive
void reverser(char s[], int i, int len)
{
	int c, j;
	
	j = len - (i+1);
	if(i < j)
	{
		c = s[i];
		s[i] = s[j];
		s[j] = c;
		reverser(s, ++i, len);
	}
}

无论何种实现方式,都应当保持相同的reverse 函数的用户接口。因此,reverse(s) 函数的新版本仍然将只有一个参数:字符串s;reverse 函数先计算出字符串的长度,然后调用函数reverser 原地倒置字符串s;字符串内的字符由外向内依次交换,这一交换过程一直持续到i、j 指向同一个字符(i == j)或者索引i 所指向的字符出现在索引j 所指向的字符的右侧(i > j)为止。

该问题并不适合用递归方法来解决。有些问题特别适合用递归技术来解决,比如二叉树的遍历。但也有些问题用非递归技术解决更好,该问题就是一个很明显的例子。

3、定义宏swap(t, x, y) ,以交换t 类型的两个参数。

 

#define swap(t, x, y) {
			t _z;\
			_z = y;\
			y = x;\
			x = _z;
		}

 

我们利用花括号定义了一个新的程序块。程序块允许我们在它的开头部分对该语句内使用的局部变量做出声明。为了交换两个参数的值,我们声明了一个类型为t 的局部变量_z。上面这个swap 宏只有在两个参数名都不是_z 的前提下才能工作。如果两个参数名之一是_z,如swap(int, _z, x),那么这个宏在展开时就会成为{int _z; _z = x; x = _z; _z = _z} 从而导致两个参数的值无法交换。所以,我们写的这个swap 宏是以_z 不会被用作变量名为假设前提的。