练习2-1 编写一个程序以确定分别有signed及unsigned限定的char、short、int、long类型变量的取值范围。
(1) 采用打印标准头文件中的相应值实现
#include <stdio.h>
#include <limits.h>
/*
* ANSI C标准规定:各种类型的取值范围必须在头文件<limits.h>中定义。
* int、short、long类型在不同的硬件上有不同的长度。
*/
main()
{
printf("signed-----------\n");
printf("signed char: %d ~ %d\n", SCHAR_MIN, SCHAR_MAX);
printf("singed int: %d ~ %d\n", INT_MIN, INT_MAX);
printf("singed short: %d ~ %d\n", SHRT_MIN, SHRT_MAX);
printf("singed long: %d ~ %d\n", LONG_MIN, LONG_MAX);
printf("unsigned------------\n");
/* %u:输入输出unsigned(无符号)类型的数值 */
printf("unsigned char max: %u\n", UCHAR_MAX);
printf("unsinged int max: %u\n", UINT_MAX);
printf("unsinged short max: %u\n", USHRT_MAX);
printf("unsinged long max: %u\n", ULONG_MAX);
}
(2)直接计算
#include <stdio.h>
main()
{
printf("signed char: %d ~ %d\n",
-(char)((unsigned char) ~0 >> 1),
(char)((unsigned char) ~0 >> 1));
printf("signed int: %d ~ %d\n",
-(int)((unsigned int) ~0 >> 1),
(int)((unsigned int) ~0 >> 1));
printf("signed char: %d ~ %d\n",
-(short)((unsigned short) ~0 >> 1),
(short)((unsigned short) ~0 >> 1));
printf("signed char: %d ~ %d\n",
-(long)((unsigned long) ~0 >> 1),
(long)((unsigned long) ~0 >> 1));
printf("unsigned char max: %u\n",
(unsigned char) ~0);
printf("unsigned int max: %u\n",
(unsigned int) ~0);
printf("unsigned short max: %u\n",
(unsigned short) ~0);
printf("unsigned long max: %lu\n",
(unsigned long) ~0);
}
练习2-2 在不使用运算符&&或||的条件下编写一个与下面for循环语句等价的语句
for(i=0; i<lim-1 && (c=getchar()) != '\n' && c!= EOF; ++i)
s[i] = c;
#include <stdio.h>
/* 使用枚举变量 */
main()
{
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;
}
}
}
/* for循环
main()
{
for(i=0; i<lim-1; ++i)
if((c=getchar()) != EOF)
if(c != '\n')
s[i] = c;
}
*/
练习2-3 编写函数htoi(s),把由十六进制数字组成的字符串(包含可选的前缀0x或0X)转换为与之等价的整型值。字符串允许包含的数字包括:0-9、a-f、A-F
#include <stdio.h>
#include <math.h>
int htoi(char s[]);
main()
{
int c, i;
char n[100];
i = 0;
while((c=getchar()) != EOF && c != '\n'){
n[i] = c;
++i;
}
printf("count: %d\n", htoi(n));
}
int htoi(char s[])
{
int i;
enum flag {N, Y};
int hexdigit;
int count;
i = count = 0;
enum flag ff = Y;
if(s[i] == '0'){ /* 去'0x'或'0X' */
++i;
if(s[i]=='x' || s[i]=='X')
++i;
}
for( ; ff==Y ; ++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
ff = N;
if(ff == Y)
count = 16 * count + hexdigit;
}
return count;
}
练习2-4 编写函数squeeze(s1, s2), 将s1中任何与s2中字符匹配的字符都删除
void squeeze(char s1[], char s2[])
{
int i, j, k;
for(i=k=0 ; s1[i]!='\0' ; i++){
for(j=0; s2[j]!='\0' && s1[i]!=s2[j] ; j++)
;
if(s1[i] != s2[j]){
s1[k++] = s1[i];
}
}
s1[k] = '\0';
printf("cankao:%s\n", s1);
}
练习2-5 编写函数any(s1, s2), 将字符串s2中的任一字符在字符串s1中第一次出现的位置作为结果返回。若s1中不包含s2中的字符,则返回-1
int any(char s1[], char s2[])
{
int i, j;
for(i=0; s2[i]!='\0'; ++i)
for(j=0; s1[j]!='\0'; ++j)
if(s1[j] == s2[i])
return j;
}
2-6 编写一个函数setbits(x, p, n, y),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
return x & ~(~(~0<<n) << (p-n+1)) |
(y & ~(~0<<n)) << (p-n+1));
}
练习2-7 编写一个函数invert(x, p, n),该函数返回对x执行下列操作后的结果值:将z中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变
unsigned invert(unsigned x, int p, int n)
{
return x ^ (~(~0 << n) << (p+1-n));
}
练习2-8 编写一个函数rightrot(x, n), 该函数返回将x循环右移(即从最右端移出的位将从最左端再移入)n位(二进制)后所得到的值
unsigned rightrot(unsigned x, int n)
{
int wordlength(void); /* 求运行程序的计算机的字长 */
int rbit;
while(n-- > 0){
rbit = x << (wordlength() - 1); /* 将最右移到最左 */
x = x >> 1;
x = x | rbit;
}
return x;
}
int wordlength(void)
{
int i;
unsigned v = (unsigned) ~0;
for(i=0; (v>>=1)>0; ++i)
;
return i;
}
练习2-9 在求对二的补码时,表达式 x &= (x-1)可以删除x中最右边为1的一个二进制位。请解释这样做的道理。用这一方法重写bitcount函数,以加快其执行速度。
//不懂这个和求对二的补码有什么关系
int bitcount(unsigned x)
{
int b;
for(b=0; x!=0; x&=x-1)
++b;
return b;
}
练习2-10 重新编写将大写字母转换成小写字母的函数lower,并用条件表达式代替其中的if-else结构
int lower(int c)
{
return c>='A' && c<='Z' ? c+'a'-'A' : c;
}