c程序设计语言笔记2

时间:2022-12-28 20:35:45

练习2-1:

  编写一个程序以确定分别由signed及unsigned限定的char、short、int及long类型变量的取值范围。采用打印标准头文件中的相应值以及直接计算两种方式实现:

  采用打印标准头文件中的相应值:

#include <stdio.h>
 #include <limits.h>
 //determine ranges of types
 int main()
 {
 printf("采用打印标准头文件limits.h中的相应值:\n");
 //signed types
 printf("signed char min = %d\n", SCHAR_MIN);
 printf("signed char max = %d\n", SCHAR_MAX);
 printf("signed short min = %d\n", SHRT_MIN);
 printf("signed short max = %d\n", SHRT_MAX);
 printf("signed int min = %d\n", INT_MIN);
 printf("signed int max = %d\n", INT_MAX);
 printf("signed long min = %ld\n", LONG_MIN);
 printf("signed long max = %ld\n", LONG_MAX);
 //unsigned types
 printf("unsigned char max = %u\n", UCHAR_MAX);
 printf("unsigned short max = %u\n", USHRT_MAX);
 printf("unsigned int max = %u\n", UINT_MAX);
 printf("unsigned long max = %lu\n", ULONG_MAX);
 system("pause");
 return 0;
 }

这种实现方法没什么好讨论的,只要知道相应的头文件和变量名就可以了。

直接计算:

#include <stdio.h>
 //determine ranges of types
 int main()
 {
 printf("采用直接计算的方式:\n");
 //signed types
 printf("signed char min = %d\n", -(char)((unsigned char)~0>>1)-1);
 printf("signed char max = %d\n", (char)((unsigned char)~0>>1));
 printf("signed short min = %d\n", -(short)((unsigned short)~0>>1)-1);
 printf("signed short max = %d\n", (short)((unsigned short)~0>>1));
 printf("signed int min = %d\n", -(int)((unsigned int)~0>>1)-1);
 printf("signed int max = %d\n", (int)((unsigned int)~0>>1));
 printf("signed long min = %ld\n", -(long)((unsigned long)~0>>1)-1);
 printf("signed long max = %ld\n", (long)((unsigned long)~0>>1));
 //unsigned types
 printf("unsigned char max = %u\n", (unsigned char)~0);
 printf("unsigned short max = %u\n", (unsigned short)~0);
 printf("unsigned int max = %u\n", (unsigned int)~0);
 printf("unsigned long max = %lu\n", (unsigned long)~0);
 system("pause");
 return 0;
 }

小结:

  利用按位运算符进行计算。表达式:(char)((unsigned char)~0>>1)

  先把数字0的各个二进制位全部转换为1:取反,~0

  然后,将结果值转换为unsigned char类型:(unsigned char)~0

  再把这个unsigned char类型值右移一位以清除符号位:(unsigned char)~0 >> 1

  最后,把它转换为char类型:(char)((unsigned char)~0>>1)

  这一系列操作的最终结果就得到了signed类型字符的最大值。

  而其signed类型字符的最小值加负号后还需减去1才是最小值。(K&R书的中文习题解答此处并没有减去1)

练习2-2

在不使用&&或||的条件下编写一个与下面的for循环语句等价的循环语句

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),把由十六进制数字组成的字符串(包含可选的前缀0x或0X)转换为与之等价的整数值。

#include <stdio.h>

#define YES 1
#define NO 0

int hoti(char s[]);


main()
{
	int c,i;
	char s[10];
	i = 0;
	while ((c = getchar()) != '\n' )
		s[i++] = c;
	printf("the number is %d\n", hoti(s));
	getch();
	

}
/* convert hexdecimal strings to intrger */

int hoti(char s[])
{
	int hexdigit, i, inhex, n;
	i = 0;
	if(s[i] == '0'){
		if(s[++i] == 'x' || s[i] == 'X')
			i++;
	}
	n = 0;
	inhex = YES;
	while(inhex == YES){
		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 = n * 16 + hexdigit;
		i++;
	}
	return n;

}
在网上看到一段大牛写的利用移位实现本题要求功能的代码,看不太懂先贴在下面。据说移位是c语言的精华所在,善于利用移位可以解决很多问题。只是我目前还没有这样的体会,可能是见识的太少了。

=============使用移位的思想================
BOOL   HexToDec(   LPCTSTR   shex,int&   idec   )  
     {  
      int   i,mid;  
      int   len   =   lstrlen(   shex   );      
      if(   len>8   )     return   FALSE;     
      mid   =   0;   idec   =   0;  
      for(   i=0;i<len;i++   )  
      {  
          if(   shex[i]>='0'&&shex[i]<='9'   )   mid   =   shex[i]-'0';  
          else   if(   shex[i]>='a'&&shex[i]<='f'   )   mid   =   shex[i]   -'a'   +10;  
          else   if(   shex[i]>='A'&&shex[i]<='F'   )   mid   =   shex[i]   -'A'   +10;  
          else   return   FALSE;      
          mid   <<=   ((len-i-1)<<2); //最精妙的地方,需要好好琢磨。 
          idec   |=   mid;      
      }      
      return   TRUE;  
   } 
练习2-6

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

#include <stdio.h>
#include <stdlib.h>

unsigned setbits(unsigned ,int,int,unsigned);

main()
{
	unsigned x = 0331;
	unsigned y = 0251;
	int p = 5,n = 4;
	printf("The convert number 0f %o is %o.",x,setbits(x,p,n,y));
	system("pause");
}

/*setbits:set n nits of x at position p with bits of y */
unsigned setbits(unsigned x,int p, int n, unsigned y)
{
	return x & ~(~(~0 << n) << (p + 1 - n)) | (y & ~(~0 << n)) << (p + 1 - n);
}
看到一个递归实现2进制输出的小程序如下:

void digui(int x)
{
     int j;
     j=x%2;
     x=x/2;
     if(x>0)
     digui(x);
     printf("%d",j);
}

按位运算符的运用:

C语言中提供了6个位操作符。这些运算符只能作用于整型操作数,即只能作用于带符号或无符号的char、short、int与long类型:

&  |  ^   >>  <<   ~

1.按位与的运用:&

  提取特定位、清零其余位:
  例如:mask中要保留的位上为1,其他位为0,a=a0&mask

      判断int的奇偶(效率比%2高得多):
  例如:(a&1)==0则为偶数,反之为奇数。(原理:因为奇数二进制末位总为1,偶数总为0。原数与00…001进行按位与运算,就得到了a二进制末位的值。)

2.按位异或运用:^

  特定位取反
  例如:mask中要取反的位为1,其余为0,a=a0^mask

     不用中间变量交换两数的值
  例如:要交换a、b的值只需:a=a^b;b=a^b;a=a^b;即可。
  (原理:上式即a=(a^b)^(a^b)^b,b=a^b^b。由于一个数与它本身进行“按位异或”运算得到0,任何一个数与0进行“按位异或”运算得到它本身,故上式即是:a=[b的原值],b=[a的原值]。这样就达到了交换a、b的目的。)

练习2-7 

将x中从p位开始的n个位求反,x的其余各位保持不变。

事实上,只要用对应位为1,其余位为0 的屏蔽码与x进行异或操作即可实现。与1异或取反,与0异或不变。

练习2-8

编写函数rightrot实现循环右移。

/* rightrot: rotate x to the right by n positions */
unsigned rightrot(unsigned x,int n)
{
	int wordlength(void);
	int rbit;					/* rightmost bit */
	
	while (n-- > 0){
		rbit = (x & 1) << (wordlength() - 1);
		x = x >> 1;
		x = x | rbit;
		}
	return x;
}

函数wordlength()的作用是计算运行程序的计算机所用的字长

int wordlength(void)
{	
	int i;
	unsigned v = (unsigned) ~0;
	for(i = 0;(v = v >> 1) > 0; i++);
	return i;
}
K&R的书中文习题解答中给出的另外一种无循环的版本如下:

unsigned rightrot(unsigned x, int n)
{
	int wordlength(void);
	unsigned rbits;
	
	if ((n = n % wordlength()) > 0){
		rbits = ~(~0 << n) & x;
		rbits = rbits << (wordlength() - n);
		x = x>> n;
		x = x | rbits;
	}
	return x;
}

练习 2-9 

利用x &= (x - 1)可以删除x中的最右边为1 的一个二进制位,重写bitcount函数,计算x中1的个数。

/* bitcount: count 1 bits in x -fast version */
int bitcount(unsigned x)
{
	int b;
	for (b = 0; x != 0; x &= x - 1)  //for(b = 0;x != 0;x >>= 1)
		b++;                      //if(x & 01) b++;  old version
	return b;
}