K&R 第三章 流控制

3-1 在上面有关折半查找的例子中,while循环语句内共执行了两次测试,其实只要一次就足够(代价是将更多的测试在循环外执行)。重写该函数,使得在循环内部只执行一次测试。比较两个版本函数的运行时间。

int binsearch(int x,int v[],int n)
{
	int low,high,mid;
	
	low=0;
	high=n-1;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(x<v[mid])
			high=mid+1;
		else if(x>v[mid])
			low=mid+1;
		else
			return mid;	
	}
	return -1;
}
int binsearch_1(int x,int v[],int n)
{
	int low,high,mid;
	
	low=0;
	high=n-1;
	mid=(low+high)/2;
	while(low<=high && x !=v[mid])
	{
		if(x<v[mid])
			high=mid-1;
		else
			low=mid+1;
		mid=(low+high)/2;
	}
	
	if(x==v[mid])
		return mid;
	else
		return -1;	
	
}

3-2 编写一个函数escape(s, t),将字符串t复制到字符串s中,并在复制过程中将换行符、制表符等不可见字符分别换成\n、\t等相应的可见的转义字符序列。要求使用switch语句。再编写一个具有相反功能的函数,在复制过程中将转义字符序列转换为实际字符。

void escape(char s[], char t[])
{
    unsigned i, j;

    j   = 0;
    for (i = 0; t[i] != '\0'; ++i) {
        switch (t[i]) {
            case '\n':
                s[j++]  = '\\';
                s[j++]  = 'n';
                break;
            case '\t':
                s[j++]  = '\\';
                s[j++]  = 't';
                break;
            default:
                s[j++]  = t[i];
                break;
        }
    }
    s[j]    = '\0';
}

void unescape(char s[],char t[])
{
	int i,j;
	for(i=j=0;t[i] != '\0';i++)
	{
		if(t[i]!='\\')
			s[j++]=t[i];
		else
			switch(t[++i])
			{
				case 'n':
					s[j++]='\n';
					break;
				case 't':
					s[j++]='\t';
					break;
				default:
					s[j++]='\\';
					s[j++]=t[i];
					break;
			}	
	}
	s[j]='\0';
}

书中一些案例

//将字符串转换为对应数值的atoi
#include <ctype.h>
int atoi(char s[])
{
	int i,n,sign;
	
	for(i=0;isspace(s[i]);i++) //skip white space
			;
	sign=(s[i]== '-')?-1:1;
	if(s[i]=='+' || s[i]=='-')
			i++;
	for(n=0;isdigit(s[i]);i++)
		n=10*n+(s[i]-'0');
	
	return sign * n;	
			
}

//字符串的转置 
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;
	if((sign=n)<0)
		 n=-n;
	i=0;
	do{
		s[i++]=n%10+'0';
	}while( (n /=10) >0);
	if(sign<0)
		s[i++]='-';
	s[i]='\0';
	reverse(s);
}


//希尔排序
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;
			}
			
}


//删除字符串尾部的空格符、制表符和换行符
int trim(char s[]) 
{
	int n;
	for(n=strlen(s)-1;n>=0;n--)
		if(s[n] !=' '&&s[n] !='\t'&&s[n]!='\n')
			break;
	s[n+1]='\0';
	return n;
}

3-3 编写函数expand(s1, s2),将字符串s1中类似于a-z一类的速记符号在字符串s2中扩展为等价的完整列表abc…xyz。该函数可以处理大小写字母和数字,并可以处理a-b-c、a-z0-9与-a-z等类似的情况。作为前导和尾随的-字符原样排印。

void expand(char s1[],char s2[])
{
	char c;
	int i,j;
	i=j=0;
	while((c = s1[i++]) !='\0')
		if(s1[i]=='-'&&s1[i+1] >=c)
		{
			i++;
			while(c < s1[i])
				s2[j++]=c++;
		}
		else
			s2[j++]=c;
	s2[j] = '\0';
}

    3-4 在数的对二补码表示中,我们编写的itoa函数不能处理最大的负数,即n等于-(2^字长-1)的情况。请解释原因。修改该函   数,使它在任何机器上运行时都能打印出正确的值。

      -(2^字长-1)无法通过 n=-n转化为正数,对二的补码所能表示的最大正数只能是(2^字长-1)-1

#define abs(x)	 ((x)<0 ? -(x):(x))
void itoa_1(int n,char s[])
{
	int i,j,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);
}

    3-5 编写函数itob(n, s, b),将整数n转换为以b为底的数,并将转换结果以字符的形式保存到字符串s中。例如,itob(n, s, 16)
    把整数n格式化成十六进制整数保存在s中。

void itob(int n,char s[],int b)
{
	int i,j,sign;
	sign=n;
	i=0;
	if(b<=0)
		{
			s[i++]='0';
			s[i]='\0';
			return;
		}
	do
	{	
		j=abs(n%b);
		s[i++]=(j<=9)? j+'0':j+'a'-10;
	}while((n/=b)!=0);
	if(sign<0)
		s[i++]='-';
	s[i]='\0';
	reverse(s);
}

    3-6 修改itoa函数,使得该函数可以接收三个参数。其中,第三个参数为最小字段宽度。为了保证转换后所得的结果至少具有第三个参数指定的最小宽度,在必要时应在所得结果的左边填充一定的空格。

void itoa_2(int n, char s[],int w)
{
	int i,j,sign;
	sign=n;
	i=0;
	do{
		s[i++]=abs(n%10)+'0';
	}while( (n/=10)!=0);
	
	if(sign<0)
		s[i++]='-';
	while(i<w)
		s[i++]=' ';
	s[i]='\0';
	reverse(s);
}

 

全部评论

相关推荐

不愿透露姓名的神秘牛友
11-26 16:06
已编辑
快手电商 后端 23k-35k
点赞 评论 收藏
分享
伟大的烤冷面被普调:暨大✌🏻就是强
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务