K&R 第二章 类型、运算符与表达式

2-1 编写一个程序以确定分别由signed及unsigned限定的char、short、int与long类型变量的取值范围。采用打印标准头文件中的相应值以及直接计算两种方式实现。后一种方法的实现较困难一些,因为要确定各种浮点类型的取值范围。

#include <stdio.h>
#include <limits.h>

//第一种方法
int main()
{
  printf("Size of Char %d\n", CHAR_BIT);
  printf("Size of Char Max %d\n", CHAR_MAX);
  printf("Size of Char Min %d\n", CHAR_MIN);
  printf("Size of int min %d\n", INT_MIN);
  printf("Size of int max %d\n", INT_MAX);
  printf("Size of long min %ld\n", LONG_MIN);       /* RB */
  printf("Size of long max %ld\n", LONG_MAX);       /* RB */
  printf("Size of short min %d\n", SHRT_MIN);
  printf("Size of short max %d\n", SHRT_MAX);
  printf("Size of unsigned char %u\n", UCHAR_MAX);  /* SF */
  printf("Size of unsigned long %lu\n", ULONG_MAX); /* RB */
  printf("Size of unsigned int %u\n", UINT_MAX);    /* RB */
  printf("Size of unsigned short %u\n", USHRT_MAX); /* SF */
 
  return 0;
}

//第二种方法
int main()
{

  printf("Size of Char Max %d\n", (char)((unsigned char)~0 >> 1));
  printf("Size of Char Min %d\n", -((char) ((unsigned char)~0>>1)+1));
}

2-2  在不使用运算符&&和||的条件下编写一个与上面(P.32)for循环语句等价的循环语句。分析:分析该for语句含义(执行步骤)用关系运算符实现(等价 - C语句含义层面)

    	for(i=0;i<lim-1 && (c=getchar() !='\n' && c!=EOF;++i)
	不使用&&和||编写等价的循环语句 	
	
	enum loop{NO,YES};
	enum loop okloop=YES;
	
	i=0;
	while(okloop==YES)
	    if(i>lim-1)
	        okloop=NO;
	    else if((c=getchar())=='\n')
	         okloop=NO;
	    else if(c==EOF)
		       okloop=NO;
        else{
		   s[i]=c;
		   ++i;
		 }

2-3  编写htoi(s),把由16进制数字组成的字符串(包含可选的前缀0x或0X)转换为与之等价的整型值。字符串允许包含的数字包括:0 ~ 9、a ~ f以及A ~ F。

#define YES 1
#define NO  0
 
int htoi(char s[]){
	int hexdigit,i,inhex,n;
	
	i=0;
	if(s[i]=='0'){       //跳过前缀0X或0X 
		++i;
		if(s[i]=='X'||s[i]=='x')
		     ++i;
	}
	
	n=0;
	inhex=YES;                   //假定是个有效的十六进制数 
	
	for(;inhex==YES;++i){
		if(s[i]>='0'&&s[i]<='9')
		    hexdigit=s[i]-'0';
		else if(s[i]>='a'&&s[i]<='f')
		    hexdigit=s[i]-'a'+10;
		else if(s[i]>'A'&& s[i]<'F')
		    hexdigit=s[i]-'A'+10;
		else 
		  inhex=NO;             //不是一个有效的十六进制数   
		
	    if(inhex==YES)
	         n=16*n+hexdigit;
	}
	
	return n;
	
}

//教材内容代码

//atoi:convert s to integer
int atoi(char s[])
{
	int i,n;
	i=n=0;
	while(s[i]>='0'&&s[i]<='9'){
		 n=10*n+(s[i]-'0');
		i++;
	}
	
	return n;
}

//convert c tolower case
int lower(int c)
{
	if(c>='A'&&c<='Z')
	    return c+'a'-'A';
	else
	    return c;    
}

//删除字符串s中出现的字符c
void squeeze(char s[],int c)
{
	int i,j;
	for(i=j=0;s[i]!='\0';i++){
		if(s[i] !=c)
		    s[j++]=s[i];
	}
	
	s[j]='\0';
}

//将字符串t连接到字符串s的尾部
void strcat(char s[],char t[])
{
	int i,j;
	i=j=0;
	while(s[i]!='\0')
	      i++;
	while(t[j] !='\0')
		 s[i++]=t[j++];
		 
	s[i]='\0';
}

2-4  重新编写squeeze(s1, s2)[P.37],将字符串s1中任何与字符串s2中字符匹配的字符都删除。

void squeeze(char s1[],char s2[])
{
	int i,j,k;
	i=j=0;
	
	while(s2[j]!='\0'){
	   while(s1[i]!='\0'){
			if(s1[i]==s2[j]){
				k=i;
				 while(s1[k]!='\0'){   //删除字符,前移 
			     	s1[k]=s1[k+1];
			     	k++;
				 }
				 s1[k]='\0';
				 i--;           //防止重复值 
			}
			i++;	      
		}//s1遍历完成 
		i=0;
		j++;
	}	  
}

void squeeze_1(char s1[],char s2[])
{
	int i,j,k;
	
	for(i=k=0;s1[i]!='\0';i++){
	    for(j=0;s2[j]!='\0'&&s2[j]!=s1[i];j++)
	         ;
	    if(s2[j]=='\0')              //s2中没有与是s[i]匹配的字符 
	          s1[k++]=s1[i];      //s[i]复制到结果字符串 
	}
	s1[k]='\0';
	         
}

2-5 编写函数any(s1, s2),将字符串s2中任一字符在字符串s1中第一次出现的位置作为结果返回。如果s1中不包含s2中的字符,则返回-1。(标准库函数strpbrk具有同样的功能,但它返回的是指向该位置的指针)。

int any(char s1[],char s2[])
{
	int i,j;
	for(i=j=0;s1[i]!='\0';i++){
		for(j=0;s2[j]!='\0';j++)
		    if(s1[i]==s2[j])
			    return i;
		
	}
	
	return -1;
}

//返回x中从右边数第p位开始向右数n位的字段。假设最右边的一位是第0位
unsigned getbits(unsigned x,int p,int n) 
{
	  return	(x>>(p-n+1)) &  ~(~0<<n);
}

2-6 编写一个函数setbits(x, p, n, y),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变。

//169:1010 1001  7:0000 0111    189:101 111  01
unsigned setbits(unsigned x,int p,int n,unsigned y)
{

	return x& ~ (~(~0<< n) << (p+1-n)) |  (y & ~(~0 << n)) <<(p+1-n);
}

2-7 编写一个函数invert(x, p, n),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位求反(即,1变成0,0变成1),x的其余各位保持不变。

//0^a=a   1^a=~a; 
unsigned invert(unsigned x,int p,int n)
 {
 	 return x^  (~(~0<<n) <<(p+1-n));
 }

unsigned invert_1(unsigned x,int p,int n)
 {
 	setbits(x,p,n,~x>>(p-n+1));
 }

2-8 编写一个函数rightrot(x, n),该函数返回将x循环右移(即从最右端移出的位将从最左端移入)n(二进制)位后所得到的的值。

unsigned rightot_1(unsigned x,int n)
{
	unsigned y=x&( ~(~0<<n) );
  
   return setbits(x>>n,sizeof(unsigned)*8-1,n,y);
}

//计算出运行程序的计算机所使用的字长 
int wordlength(void)
{
	int i;
	unsigned v=(unsigned)~0;
	
	for(i=1;(v=v>>1)>0;i++)
			;

	return i;		
}

//x&1 得到x的最后一位 
unsigned rightot(unsigned x,int n)
{
	int rbit;
	while(n-- >0)
	{
		rbit=(x&1) << (wordlength()-1);
		x=x>>1;
		x=x|rbit;
	}
	return x;
} 

unsigned rightot_2(unsigned x,int n)
{
	unsigned rbits;
	
	if((n=n%wordlength()) >0)
	{
		rbits = ~(~0 << n) &x;    //得到x最右端的值 
		
		rbits = rbits << (wordlength() -n);
		x = x >> n;
		x = x | rbits;
	}
	return x;
}

2-9 在求对二的补码(Two’s complement)时,表达式x &=(x - 1)可以删除x中最右边值为1的一个二进制位(如1000中的1)。请解释这样做的道理。用这一方法重写bitcount函数(P.40 ~ P.41),以加快其执行速度。

//x声明为unsigned,保证右移后,左位补零 
int bitcount(unsigned x)
{
	int b;
	for(b=0;x!=0;x>>1)
	{
		if(x&01)
			b++;
	}
	
	return b;
}

int bitcount_1(unsigned x)
{
	int b;
	for(b=0;x!=0;x &=x-1)
		++b;
	return b;	
}

2-10 重新编写将大写字母转换为小写字母的函数lower(P.34) 并用条件表达式替换其中的if-else结构。

int lower(int c)
{
	return c>='A'&&c<='Z' ? c+'a'-'A':c;
}

 

全部评论

相关推荐

10-15 09:13
已编辑
天津大学 soc前端设计
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务