c程序设计语言笔记2

来源:互联网 发布:java字符串转date类型 编辑:程序博客网 时间:2024/06/11 18:32

练习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 0int 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;elseinhex = 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 versionreturn b;}





原创粉丝点击