《C程序设计语言》(《The C Programming Language》)第二版第二章练习题

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

#include <stdio.h>
#include <limits.h>   //包含标准值的头文件
#include <math.h>     //包含pow()函数的头文件,即求幂函数
int main(void)
{
	printf("该系统的整型数据限制如下:\n");

	//使用标准头文件
	printf("int类型的最大值:%d\n", INT_MAX);
	printf("int类型的最小值:%d\n", INT_MIN);
	printf("unsigned int类型的最大值:%u\n\n", UINT_MAX);

	
	printf("short类型的最大值:%hd\n", SHRT_MAX);
	printf("short类型的最小值:%hd\n", SHRT_MIN);
	printf("unsigned short类型的最大值:%hu\n\n", USHRT_MAX);

	printf("long类型的最大值:%ld\n", LONG_MAX);
	printf("long类型的最小值:%ld\n", LONG_MIN);
	printf("unsigned long类型的最大值:%lu\n\n", ULONG_MAX);

	
	printf("char类型的最大值:%d\n", CHAR_MAX);
	printf("char类型的最小值:%d\n", CHAR_MIN);
	printf("signed char类型的最大值:%d\n", SCHAR_MAX);
	printf("signed char类型的最小值:%d\n", SCHAR_MIN);
	printf("unsigned char类型的最大值:%d\n\n", UCHAR_MAX);

	//直接计算
	
	printf("int类型占用 %d 字节,每字节为 %d位,因此int类型占用位数为 %d 位\n", 
	sizeof(int), CHAR_BIT, CHAR_BIT * sizeof(int));
	int int_max = pow(2, CHAR_BIT * sizeof(int) - 1) - 1;
	int int_min = pow(2, CHAR_BIT * sizeof(int) - 1);
	printf("int类型的取值范围为:%d\n", int_max);
    printf("int类型的取值范围为:%d\n\n", int_min);

    printf("short类型占用 %d 字节,每字节为 %d位,因此int类型占用位数为 %d 位\n", 
    sizeof(short), CHAR_BIT, CHAR_BIT * sizeof(short));
	short short_max = pow(2, CHAR_BIT * sizeof(short) - 1) - 1;
	short short_min = pow(2, CHAR_BIT * sizeof(short) - 1);
	printf("short类型的取值范围为:%d\n", short_max);
    printf("short类型的取值范围为:%d\n\n", short_min);


    printf("long类型占用 %d 字节,每字节为 %d位,因此int类型占用位数为 %d 位\n", 
    sizeof(long), CHAR_BIT, CHAR_BIT * sizeof(long));
	long long_max = pow(2, CHAR_BIT * sizeof(long) - 1) - 1;
	long long_min = pow(2, CHAR_BIT * sizeof(long) - 1);
	printf("long类型的取值范围为:%d\n", long_max);
    printf("long类型的取值范围为:%d\n\n", long_min);

    printf("char类型占用 %d 字节,每字节为 %d位,因此int类型占用位数为 %d 位\n", 
    sizeof(char), CHAR_BIT, CHAR_BIT * sizeof(char));
	char char_max = pow(2, CHAR_BIT * sizeof(char) - 1) - 1;
	char char_min = pow(2, CHAR_BIT * sizeof(char) - 1);
	printf("char类型的取值范围为:%d\n", char_max);
    printf("char类型的取值范围为:%d\n\n", char_min);

	return 0;
}

2-2:
在不使用运算符&&或||的条件下编写一个与上面的for循环语句等价的循环语句

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int len;
 
	while ((len = getline(line, MAXLINE)) > 0)
	{
		printf("%s", line);
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1; ++i)
	{
		c = getchar();
		if(c == EOF)
		{
			s[i] = '\0'; 
			return i;
		}
		else if(c == '\n')
		{
			s[i] = '\n';
			s[++i] = '\0';
			return i;
		}
		s[i] = c;
	}
 
	s[i] = '\0';
	return i;
}

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

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
int htoi(char s[]);
 
int main()
{
	char line[MAXLINE];
	int len, i;
	int result = 0x0;//声明一个十六进制变量
 
	while ((len = getline(line, MAXLINE)) > 0)
	{
		result = htoi(line);
		if(result == -1)
			printf("请按标准格式输入,前缀为0x或0X,字符串中的数字为0 ~ 9或a ~ f或A ~ F\n");
		else
			printf("十进制:%d,八进制:%o,十六进制:%x\n", result, result, result);
		printf("继续输入\n");
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1; ++i)
	{
		c = getchar();
		if(c == EOF)
		{
			s[i] = '\0'; 
			return i;
		}
		if(c == '\n')
		{
			s[i] = '\n';
			s[++i] = '\0';
			return i;
		}
		s[i] = c;
	}
 
	s[i] = '\0';
	return i;
}

int htoi(char s[])
{
	int x = 0x0;//声明一个十六进制变量
	int i;

	if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X'))
		return -1;
	else
	{
		for(i = 2; s[i] != '\n' && s[i] != '\0'; i++)
		{
			if(s[i] >= '0' && s[i] <= '9')
				x = 16 * x + (s[i] - '0');
			else if(s[i] >= 'a' && s[i] <= 'f')
				x = 16 * x + (s[i] - 'a' + 10);
			else if(s[i] >= 'A' && s[i] <= 'F')
				x = 16 * x + (s[i] - 'A' + 10);
			else
				return -1;
		}
		return x;
	}
}

2-4:
squeeze(s1, s2),将字符串s1中任何与s2中字符匹配的字符都删除

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
void squeeze(char s1[], char s2[]);
 
int main()
{
	char line1[MAXLINE];
	char line2[MAXLINE];
 
	printf("请输入两条字符串\n");
	while (getline(line1, MAXLINE) > 0 && getline(line2, MAXLINE) > 0)
	{
		squeeze(line1, line2);
		printf("继续输入\n");
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1; ++i)
	{
		c = getchar();
		if(c == EOF)
		{
			s[i] = '\0'; 
			return i;
		}
		if(c == '\n')
		{
			s[i] = '\n';
			s[++i] = '\0';
			return i;
		}
		s[i] = c;
	}
 
	s[i] = '\0';
	return i;
}

void squeeze(char s1[], char s2[])
{
	int i, j, k;
	int mask;
	printf("字符串s1:%s", s1);
	printf("字符串s2:%s", s2);

	for(i = k = 0; s1[i] != '\n' && s1[i] != '\0'; i++)//保留换行符和空字符
	{
		mask = 1;
		for(j = 0; s2[j] != '\n' && s2[j] != '\0'; j++)
		{
			if(s1[i] == s2[j] && s1[i] != ' ')//保留空格
				mask = 0;
		}
		if(mask)
		{
			s1[k++] = s1[i];
		}
	}
	s1[k] = '\0';

	printf("删除掉与s2中字符匹配字符后的s1:%s\n", s1);
}

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

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
int any(char s1[], char s2[]);
 
int main()
{
	char line1[MAXLINE];
	char line2[MAXLINE];
	int result;
 
	printf("请输入两条字符串\n");
	while (getline(line1, MAXLINE) > 0 && getline(line2, MAXLINE) > 0)
	{
		result = any(line1, line2);
		if(result == -1)
			printf("未在s1中找到s2对应字符\n");
		else
			printf("其在s1字符串中第一次出现的实际位置为第 %d 位\n", result);
		printf("继续输入\n");
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1; ++i)
	{
		c = getchar();
		if(c == EOF)
		{
			s[i] = '\0'; 
			return i;
		}
		if(c == '\n')
		{
			s[i] = '\n';
			s[++i] = '\0';
			return i;
		}
		s[i] = c;
	}
 
	s[i] = '\0';
	return i;
}

int any(char s1[], char s2[])
{
	int i, j;
	printf("字符串s1:%s", s1);
	printf("字符串s2:%s", s2);

	for(i = 0; s1[i] != '\n' && s1[i] != '\0'; i++)//忽略换行符和空字符
	{
		for(j = 0; s2[j] != '\n' && s2[j] != '\0'; j++)
		{
			if(s1[i] == s2[j] && s1[i] != ' ')//忽略空格
			{
				printf("发现字符 %c,", s2[j]);
				return i + 1;//返回的是字符在字符串的实际位置,而不是数组位置
			}
		}
	}
	return - 1;
}

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

#include <stdio.h>
#define SIZE 17

int setbits(int x, int p, int n, int y);
void show(char s[], int n);//打印二进制形式的函数

int main(void)
{
	char line[SIZE];
	int x = 107;
	int p = 5;
	int n = 3;
	int y = 60;
	int result = 0;
	
	printf("x的十进制形式为 %d,", x);
	show(line, x);
	printf("y的十进制形式为 %d,", y);
	show(line, y);

	result = setbits(x, p, n, y);
    
	printf("将%d中从第%d位开始的%d个(二进制)位设置为%d中最右边%d位的值"
		"所得结果为:%d\n", x, p, n, y, n, result);
	
	show(line, result);
	return 0;
}

void show(char s[], int n)
{
	int i;
	for(i = SIZE - 2; i >= 0; i--, n >>= 1)//从数组的倒数第二个元素开始赋值
		s[i] = (n & 01) + '0';
	
	s[SIZE - 1] = '\0';
	
	printf("其二进制形式为:");
	
	for(i = 0; i < SIZE; i++)
	{
		putchar(s[i]);
		if(i % 4 == 3)
			putchar(' ');
	}
	putchar('\n');
}

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

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

#include <stdio.h>
#define SIZE 17

int invert(int x, int p, int n);
void show(char s[], int n);//打印二进制形式的函数

int main(void)
{
	char line[SIZE];
	int x = 309;
	int p = 5;
	int n = 3;
	int result = 0;
	
	printf("x的十进制形式为 %d,", x);
	show(line, x);

	result = invert(x, p, n);
    
	printf("将%d中从第%d位开始的%d个(二进制)位求反"
		"所得结果为:%d\n", x, p, n, result);
	
	show(line, result);
	return 0;
}

void show(char s[], int n)
{
	int i;
	for(i = SIZE - 2; i >= 0; i--, n >>= 1)//从数组的倒数第二个元素开始赋值
		s[i] = (n & 01) + '0';
	
	s[SIZE - 1] = '\0';
	
	printf("其二进制形式为:");
	
	for(i = 0; i < SIZE; i++)
	{
		putchar(s[i]);
		if(i % 4 == 3)
			putchar(' ');
	}
	putchar('\n');
}

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

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

#include <stdio.h>
#include <limits.h>
#define SIZE ((CHAR_BIT * sizeof(int)) + 1)

unsigned int rightrot(unsigned int x, int n);
void show(char s[], int n);//打印二进制形式的函数

int main(void)
{
	char line[SIZE];
	unsigned int x = 309;
	int n = 8;
	unsigned int result = 0;
	
	printf("x的十进制形式为 %u,", x);
	show(line, x);

	result = rightrot(x, n);
    
	printf("将%d循环右移%d位后所得结果为:%u\n", x, n, result);
	
	show(line, result);
	return 0;
}

void show(char s[], int n)
{
	int i;
	for(i = SIZE - 2; i >= 0; i--, n >>= 1)//从数组的倒数第二个元素开始赋值
		s[i] = (n & 01) + '0';
	
	s[SIZE - 1] = '\0';
	
	printf("其二进制形式为:");
	
	for(i = 0; i < SIZE; i++)
	{
		putchar(s[i]);
		if(i % 4 == 3)
			putchar(' ');
	}
	putchar('\n');
}

unsigned int rightrot(unsigned int x, int n)
{
	int i;
	for(i = 1; i <= n; i++)
	{
		x = ((x & 01) << (SIZE - 2)) | (x >> 1);
		//首先判断x的第0位的值,将该值移至最高位,最后与x右移一位所得值进行按位或运算
	}
	return x;
}

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

/*首先解释一下题目中的问题:
假设x = 11,其二进制形式为0000 1011
x - 1 = 10,其二进制形式为0000 1010
x &= (x - 1)等效于x = x & (x - 1),所得结果的二进制形式为0000 1010,删除
一个为1的位
同样假设x = 10, x - 1 = 9,其二进制形式为0000 1001
x &= (x - 1),所得结果二进制形式为0000 1000,再删除一个为1的位
以此类推……
也就是说从第0位开始,寻找第一个1出现的位置,(x - 1)的作用是将该位变为0,
将其后的所有位变为1,那么x &= (x - 1)的结果就是将该位以及后面的所有位都
变为0,该位之前的所有位不变,达到删除最右边值为1的一个二进制位的作用
*/
#include <stdio.h>
#include <limits.h>
#define SIZE ((CHAR_BIT * sizeof(int)) + 1)

int bitcount(unsigned int x);
void show(char s[], int n);//打印二进制形式的函数

int main(void)
{
	char line[SIZE];
	unsigned int x = 309;
	int result = 0;
	
	printf("x的十进制形式为 %u,", x);
	show(line, x);

	result = bitcount(x);
    
	printf("x中共有%d个位为1\n", result);
	return 0;
}

void show(char s[], int n)
{
	int i;
	for(i = SIZE - 2; i >= 0; i--, n >>= 1)//从数组的倒数第二个元素开始赋值
		s[i] = (n & 01) + '0';
	
	s[SIZE - 1] = '\0';
	
	printf("其二进制形式为:");
	
	for(i = 0; i < SIZE; i++)
	{
		putchar(s[i]);
		if(i % 4 == 3)
			putchar(' ');
	}
	putchar('\n');
}

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

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

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
void lower(char s1[], char s2[]);
 
int main()
{
	char line1[MAXLINE];
	char line2[MAXLINE];
	int result;
 
	printf("请输入待转换的字符串\n");
	while (getline(line1, MAXLINE) > 0)
	{
		lower(line1, line2);
		printf("将字符串中小写转化为大写后结果为:\n");
		printf("%s", line2);
		printf("继续输入");
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1; ++i)
	{
		c = getchar();
		if(c == EOF)
		{
			s[i] = '\0'; 
			return i;
		}
		if(c == '\n')
		{
			s[i] = '\n';
			s[++i] = '\0';
			return i;
		}
		s[i] = c;
	}
 
	s[i] = '\0';
	return i;
}

void lower(char s1[], char s2[])
{
	for(int i = 0; s1[i] != '\0'; i++)
		s2[i] = (s1[i] >= 'A' && s1[i] <= 'Z')? (s1[i] - 'A' + 'a') : s1[i];
	s2[i] = '\0';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值