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';
}