C 程序设计语言——第三章练习题

C 程序设计语言——第三章练习题

3.1 Our binary search makes two tests inside the loop, when one would suffice (at the price of more tests outside.) Write a version with only one test inside the loop and measure the difference in run-time.

分析:一个二分查找值的函数,本书中的程序如下:

int binsearch(int x, int v[], int n)
{
	int low, high, mid;
	low = 0;
	high = n - 1;
	while(low <= high)
	{
		mid = (low + high) / 2;
		if (x < v[mid])
			high = mid - 1;
		else if (x > v[mid])
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}

题目需要更改函数,循环内部只有一个测试条件,并比较两种方法的运行时间。

#include<stdio.h>
#include<time.h>
#include<string.h>
#define LEN 100
int *i_gets(int *v, int n);
int Print(int *v);
int input(void);
int binsearch1(int x, int *v, int n);
int binsearch2(int x, int *v, int n);
int main(void)
{
	int v[LEN];
	int x;
	int size;
	clock_t start, finish;
	double total;
	int find;
	printf("Please enter integers (no more than %d), nonumeric to stop "  
	"input:\n",LEN);
	i_gets(v, LEN);
	printf("\nThe input numbers:\n");
	size = Print(v);
	printf("Please enter the number you want to search: ");
	x = input();
	printf("Binary search with two methods:\n");
	start = clock();
	find = binsearch1(x, v, size);
	finish = clock();
	total = (double) (finish - start) / CLOCKS_PER_SEC;
	printf("Method 1 takes %f seconds\n",total);
	start = clock();
	find = binsearch2(x, v, size);
	finish = clock();
	total = (double) (finish - start) / CLOCKS_PER_SEC;
	printf("Method 2 takes %f seconds\n",total);
	if(find != -1)
		printf("Find %d.\n",x);
	else
		printf("Can't find %d.\n",x);
	return 0;
}
int *i_gets(int *v, int len)
{
	int i = 0;
	int t;
	while(i < len)
	{
		if(scanf("%d", &t) == 1 && getchar() == '\n')
			v[i++] = t;
		else
			break;
	}
	while(getchar() != '\n')
		continue;
	return v;
}
int Print(int *v)
{
	int i;
	for(i = 0; v[i] != '\0'; i++)
		printf("%d%c",v[i], (i + 1) % 5 == 0 ? '\n' : ' ');
	if(i % 5 != 0)
		putchar('\n');
	return i;
}
int input(void)
{
	int n, status;
	int ok = 1;
	while(ok)
	{
		status = scanf("%d",&n);
		if (status != 1 || getchar() != '\n')
		{
			printf("Enter again: ");
			while(getchar() != '\n')
				continue;
		}
		else
			return n;
	}
}
int binsearch1(int x, int *v, int len)
{
	int low, high, mid;
	low = 0;
	high = len - 1;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (x < v[mid])
			high = mid - 1;
		else if (x > v[mid])
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}
int binsearch2(int x, int *v, int len)
{
	int low, high, mid;
	low = 0;
	high = len - 1;
	mid = (low + high) / 2;
	while (low <= high && v[mid] != x)
	{
		if (x < v[mid])
			high = mid - 1;
		else
			low = mid + 1;
		mid = (low + high) / 2;
	}
	return (v[mid] == x) ? mid : -1;
}

测试结果:

Please enter integers (no more than 100), nonumeric to stop input:
32
14
5
6

2
3
6
5
7
8
9
4
3
f

The input numbers:
32 14 5 6 2
3 6 5 7 8
9 4 3 
Please enter the number you want to search: 0
Binary search with two methods:
Method 1 takes 0.000002 seconds
Method 2 takes 0.000001 seconds
Can't find 0.

3.2 Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s. Use a switch. Write a function for the other direction as well, converting escape sequences into the real characters.

#include<stdio.h>
#include<string.h>
#define LEN 40
void escape(char *s, char *t);
void unescape(char *s, char *t);
int main(void)
{
	char s[LEN], t[LEN], u[LEN];
	printf("Please enter a string:\n");
	fgets(t, LEN, stdin);
	escape(s, t);
	printf("\nString displays visible escape sequence:\n");
	puts(s);
	printf("\nString converts escape sequences into the real characters:\n");
	unescape(u, s);
	puts(u);
	return 0;
}
void escape(char *s, char *t)
{
	int i, j;
	for(i = 0, j = 0; t[i] != '\0'; i++)
		switch(t[i])
		{
			case '\n': s[j++] = '\\'; s[j++] = 'n'; break;
			case '\t': s[j++] = '\\'; s[j++] = 't'; break;
			default: s[j++] = t[i];
		}
	s[j] = '\0';
}
void unescape(char *s, char *t)
{
	int i, j;
	for(i = 0, j = 0; t[i] != '\0'; i++)
		switch(t[i])
		{
			case '\\': 
				switch (t[++i])
				{
					case 'n': s[j++] = '\n'; break;
					case 't': s[j++] = '\t'; break;
					default: s[j++] = '\\'; s[j++] = t[i]; break;
				}
				break;
			default: s[j++] = t[i]; break;
		}
	s[j] = '\0';
}

3.3 Write a function expand(s1,s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc…xyz in s2. Allow for letters of either case and digits, and be prepared to handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or trailing - is taken literally.

分析:

  1. 将字符串扩展后的长度可能增加,增加多少不确定,如果一开始分配的两个字符串的长度一样,那么扩展后 s2 的长度可能超过,因此考虑对题中的函数做修改,将扩展后的字符串作为返回值,该字符串不事先定义,而是在函数内识别出需要扩展的未后定义。
  2. 识别的分两种:字母和数字,数字只识别单个数字,范围 0 ~ 9。
  3. 注意一个字符前后都有 - 时要区分两种情况考虑:
    a-b-c 和 -a-z
    注意第一种不能变成abbc,解决方法是填充时只填充中间未显示的值。
#include<stdio.h>
#include<string.h>
#include<ctype.h>
char *s_gets(char *s, int n);
char *expand(char *s1, char *s2);
int check(char c);
#define LEN 100
int main(void)
{
	char s1[LEN], s2[LEN];
	char *t = s2;
	printf("Please enter a string (no more than %d characters:\n",LEN-1);
	s_gets(s1, LEN);
	printf("Original string: %s\n",s1);
    t = expand(s1, s2);
	printf("Expanded string: %s\n", t);
	return 0;
}
char *s_gets(char *s, int n)
{
	char *ret, *find;
	ret = fgets(s, n, stdin);
	if(ret)
	{
		find = strchr(s, '\n');
		if(find)
			*find = '\0';
		else
			while(getchar() != '\n')
				continue;
	}
	return ret;
}
int check(char c)
{
	int n;
	if(isdigit(c))
	n = 0;
	else if(c >= 'a' && c <= 'z')
	n = 1;
	else if(c >= 'A' && c <= 'Z')
	n = 2;
	else
	n = -1;
	return n;
}
char *expand(char *s1, char *s2)
{
	char *t = s2;
	int i = 0, k = 0;
	int c1, c2, j;
	if(s1[i] != '\0')
		t[k++] = s1[i++];
	while(s1[i] != '\0')
	{
		if(s1[i] == '-' && s1[i+1] != '\0')
		{
			c1 = check(s1[i-1]);
			c2 = check(s1[i+1]);
			if(c1 == c2 && c1 != -1 && c2 != -1 && s1[i-1] < s1[i+1])
			{
				for(j = s1[i-1] + 1; j < s1[i+1]; j++)
					t[k++] = j;
				t[k++] = s1[i+1];
				i += 2;
			}
			else
				t[k++] = s1[i++];
		}
		else
			t[k++] = s1[i++];
	}
	t[k] = '\0';
	return t;
}

结果:

Please enter a string (no more than 99 characters:
s-f-ab-c-d-5-8-2-
Original string: s-f-ab-c-d-5-8-2-
Expanded string: s-f-abcd-5678-2-

3.4 In a two’s complement number representation, our version of itoa does not handle the largest negative number, that is, the value of n equal to -(2wordsize-1). Explain why not. Modify it to print that value correctly, regardless of the machine on which it runs.

书中的程序如下:

/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
  1. 该程序输入最大的负数时,得到的结果是错的,原因如下:
    (该部分知识点见:深入理解计算机系统英文版第二版p121)
    以本系统 int 为4字节为例,int 的范围为 -2^31 ~ 2^31 - 1,因此,当 n 为 -2^31 时,-n 本应该是 231,但该值超出了范围,将该值减去模(232),得到其值为 -2^31。
  2. 修改程序:
if((sign = n) < 0)
n = (unsigned) (-n);

改过后,当 n 为 -2^31 时,就变成 2^31,而不超过范围。

3.5 Write the function itob(n,s,b) that converts the integer n into a base b character representation in the string s. In particular, itob(n,s,16) formats s as a hexadecimal integer in s.

#include<stdio.h>
#include<string.h>
#include<limits.h>
#define LEN 34
void itob(int n, char *s, int b);
int input(int min, int max);
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int main(void)
{
	int n, b;
	char s[LEN];
	printf("Please enter a interger: ");
	n = input(INT_MIN, INT_MAX);
	printf("Please enter the base ( 2 ~ 36): ");
	b = input(2, 36);
	itob(n, s, b);
	printf("%d base %d is %s.\n", n, b, s);
	return 0;
}
int input(int min, int max)
{
	int status;
	long n;
	int ok = 1;
	while(ok == 1)
	{
		status = scanf("%ld",&n);
		//判断语句中getcha() != '\n' 必须放最后
		if(status != 1 || n < min || n > max || getchar() != '\n' )
		{
			printf("Enter again (between %d to %d): ",min, max);
			while(getchar() != '\n')
				continue;
			continue;
		}
		else
			return (int)n;
	}
}
void swap(char *s1, char *s2)
{
	char t;
	t = *s1; *s1 = *s2; *s2 = t;
}
void reverse(char *s)
{
	int len, i, j;
	len = strlen(s);
	for(i = 0, j = len-1; i < j; i++, j--)
		swap(&s[i], &s[j]);
}
void itob(int n, char *s, int b)
{
	int sign, i;
	if ((sign = n) < 0)
		n = (unsigned) (-n);
	i = 0;
	do
	{
		s[i++] = digits[n % b]; //直接将转化的数字与字符对应,无需再转化
	} while((n /= b) > 0);
	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

3.6 Write a version of itoa that accepts three arguments instead of two. The third argument is a minimum field width; the converted number must be padded with blanks on the left if necessary to make it wide enough.

#include<stdio.h>
#include<string.h>
#include<limits.h>
#define LEN 47
void itoa(int n, char *s, int w);
int input(int min, int max);
int main(void)
{
	int n, w;
	char s[LEN];
	printf("Please enter a integet (%d ~ %d): ",INT_MIN, INT_MAX);
	n = input(INT_MIN, INT_MAX);
	printf("Please enter the minimum width (0 ~ 40): ");
	w = input(0, 40);
	itoa(n, s, w);
	printf("%d corresopnding to %s.\n",n, s);
	return 0;
}
int input(int min, int max)
{
	int status;
	long n;
	int ok = 1;
	while(ok == 1)
	{
		status = scanf("%ld",&n);
		//判断语句中getcha() != '\n' 必须放最后
		if(status != 1 || n < min || n > max || getchar() != '\n' )
		{
			printf("Enter again (between %d to %d): ",min, max);
			while(getchar() != '\n')
				continue;
			continue;
		}
		else
			return (int)n;
	}
}
void swap(char *s1, char *s2)
{
	int t;
	t = *s1; *s1 = *s2; *s2 = t;
}
void reverse(char *s)
{
	int len, i, j;
	len = strlen(s);
	for (i = 0, j = len-1; i < j; i++, j--)
		swap(&s[i], &s[j]);
}
void itoa(int n, char *s, int w)
{
	int sign, i;
	if ((sign = n) < 0)
		n = (unsigned) (-n);
	i = 0;
	do
	{
		s[i++] = n % 10 + '0';
	} while ((n /= 10) > 0);
	if (sign < 0)
		s[i++] = '-';
	while (i < w)
		s[i++] = ' ';
	s[i] = '\0';
	reverse(s);
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值