第13章--高级指针话题

1、编写一个程序,从标准输入中读取一些字符,并根据下面的分类计算各类字符所占的百分比:
控制字符/空白字符/数字/小写字母/大写字母/标点符号/不可打印字符
这些分类是根据ctype.h中的函数定义的,不能使用一系列的if语句。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int unprint(int ch)
{
	return !isprint(ch);
}

int (*test[])(int ch) = {
	iscntrl,
	isspace,
	isdigit,
	islower,
	isupper,
	ispunct,
	unprint,
};

char *print[] = {
	"cntrl",
	"space",
	"digit",
	"lower",
	"upper",
	"punct",
	"unprint",
};

float types[7] = {0, 0, 0, 0, 0, 0, 0};
float count = 0;

void main()
{
	int i;
	char ch;

	printf("Please input string: ");
	while ((ch = getchar()) != '\n') {
		count++;
		for (i = 0; i < 7; i++) {
			if (test[i](ch))
				types[i]++;
		}
	}

	if (count == 0) {
		printf("No character input\n");
	}
	else {
		for (i = 0; i < 7; i++)
			printf("%s: %2.2f %%\n", print[i], (types[i] / count) * 100);
	}
}

2、编写一个通用目的的函数,遍历一个单链表,它应该接受两个参数,一个指向链表第一个节点的指针,和一个指向回调函数的指针,回调函数应该接受单个参数,也就是指向一个链表节点的指针,对于链表中的每个节点,都应该调用一次这个回调函数。这个函数需要知道链表节点的什么信息?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

typedef struct node {
	int data;
	struct node *next;
} NODE;

void exe(NODE *current);
void handle(NODE *root, void (*callback)());

void main()
{
	NODE *head;

	handle(head, exe);
}

void handle(NODE *root, void (*callback)())
{
	while (root != NULL) {
		callback(root);
		root = root->next;
	}
}

void exe(NODE *current)
{
	current->data = 0;
}

3、转换下列代码段,使它改用转移表而不是switch语句

	Node *list;
	Node *current;
	Transaction *transaction;
	typedef enum {NEW, DELETE, FORWARD, BACKWORD,
	              SEARCH,EDIT} Trans_type;
	...
	switch(transaction->type){
	case NEW:
	    add_new_trans(list,transaction);
	    break;
	case DELETE:
	    current = delete_trans(list,transaction);
	    break;
	case FORWORD:
	    current = current->next;
	    break;
	case BACKWORD:
	    current = current->prev;
	case SEARCH:
	    current = search(list,transaction);
	    break;
	case EDIT:
	    edit(current,transaction);
	    break;
	default:
	    printf("Illegal transaction type!\n");
	    break;
	}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node {
	int data;
	struct node *next;
	struct node *prev;
} NODE;

typedef struct tran {
	int type;
} TRANSACTION;

typedef enum {
	NEW,
	DELECT,
	FORWARD,
	BACKWARD,
	SEARCK,
	EDIT
} trans_type;

void add_new_trans(NODE *list, NODE **current, TRANSACTION *transaction);
void delect_trans(NODE *list, NODE **current, TRANSACTION *transaction);
void search(NODE *list, NODE **current, TRANSACTION *transaction);
void edit(NODE *list, NODE **current, TRANSACTION *transaction);
void forward(NODE *list, NODE **current, TRANSACTION *transaction);
void backward(NODE *list, NODE **current, TRANSACTION *transaction);

void (*handle[])() = {
	add_new_trans,
	delect_trans,
	search,
	edit,
	forward,
	backward
};

void main(int argc, char **argv)
{
	NODE *list;
	NODE *current;
	TRANSACTION *transaction;

	transaction = malloc(sizeof(TRANSACTION));
	transaction->type = atoi(argv[1]);
	
	if (transaction->type >= NEW && transaction->type <= EDIT)
		handle[transaction->type](list, &current, transaction);
	else
		printf("Illegal transaction type!\n");
}

void add_new_trans(NODE *list, NODE **current, TRANSACTION *transaction)
{
	printf("add new trans\n");
}

void delect_trans(NODE *list, NODE **current, TRANSACTION *transaction)
{
	printf("delect trans\n");
}

void search(NODE *list, NODE **current, TRANSACTION *transaction)
{
	printf("search\n");
}

void edit(NODE *list, NODE **current, TRANSACTION *transaction)
{
	printf("edit\n");
}

void forward(NODE *list, NODE **current, TRANSACTION *transaction)
{
	*current = (*current)->next;
	printf("forward\n");
}
void backward(NODE *list, NODE **current, TRANSACTION *transaction)
{
	*current = (*current)->prev;
	printf("backward\n");
}

4、编写一个名叫sort的函数,它用于对一个任何类型的数组进行排序,为了使函数更为通用,他的其中一个参数必须是一个指向比较回调函数的指针,该回调函数由调用程序提供,比较函数接受两个参数,也就是两个指向需要进行比较的值的指针,如果两个值相等,返回0,如果第一个值小于第二个返回小于零的整数,否则,返回大于零的整数。
sort函数的参数将是:
1.一个指向需要排序的数组的第一个值的指针
2.数组中值的个数
3.每个数组元素的长度
4.一个指向比较回调函数的指针
sort函数没有返回值。你将不能根据实际类型声明数组参数,因为函数应该可以对不同类型的数组进行排序,如果你把数据当成一个字符数组使用,你可以用第三个参数寻找实际数组中每个元素的起始位置,也可以用它交换两个数组元素(每次一个字节)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void sort(void *array, int num, int len, int (*compare)());
int compare_char(char *value1, char *value2);
int compare_short(short *value1, short *value2);
int compare_int(int *value1, int *value2);
int compare_double(double *value1, double *value2);
void swap(char *value1, char *value2, int len);

void main()
{
	int i;
	int num;
	int array[] = {1, -3, 5, -2, 4, -6};

	num = sizeof(array) / sizeof(array[0]);
	sort(array, num, sizeof(array[0]), compare_int);

	printf("sort: ");
	for (i = 0; i < num; i++)
		printf("%d ", array[i]);
	printf("\n");
}

void sort(void *array, int num, int len, int (*compare)())
{
	int i, j;
	char *value1, *value2;

	value1 = (char *)array;
	for (i = 0; i < num - 1; i++) {
		value2 = value1 + len;
		for (j = i + 1; j < num; j++) {
			if (compare(value1, value2) > 0)
				swap(value1, value2, len);
			value2 += len;
		}
		value1 += len;
	}
}

int compare_char(char *value1, char *value2)
{
	return *value1 - *value2;
}

int compare_short(short *value1, short *value2)
{
	return *value1 - *value2;
}

int compare_int(int *value1, int *value2)
{
	return *value1 - *value2;
}

int compare_double(double *value1, double *value2)
{
	return *value1 - *value2;
}

void swap(char *value1, char *value2, int len)
{
	int i;
	char tem;
	
	for (i = 0; i < len; i++) {
		tem = value1[i];
		value1[i] = value2[i];
		value2[i] = tem;
	}
}

5、编写代码处理命令行参数是十分乏味的,所以最好有一个标准函数来完成这项工作。但是不同的程序以不同的方式处理它们的参数,所以,这个函数必须非常灵活,以便使它能用于更多的程序。在本题中,你将编写这样一个函数。你的函数通过寻找和提取参数来提供灵活性。用户所提供的回调函数将执行实际的处理工作。下面是函数的原型。注意它的第四个参数和第五个参数是回调函数的原型。
char ** do_args(int argc, char **argv, char *control, void (*do_arg)(int ch, char *value), void (*illegal_arg)(int ch));
头两个参数就是main函数的参数,main函数对它们不做修改,直接传递给do_args,第三个参数是个字符串,用于标志程序期望接受的命令行参数。最后两个参数都是函数指针,它们是由用户提供的。do_args函数按照下面这样的方式处理命令行参数:

跳过程序名参数
while 下一次参数以一个横杆开头
  对于参数横杠后面的每个字符
    处理字符
返回一个指针,指向下一个参数指针

为了“处理字符”,你首先必须观察该字符是否位于control字符串内,如果它并不位于那里,调用illegal_arg指向函数,把这个字符作为参数传递过去。如果它位于control字符串内,但它的后面并不是跟一个+号,那么就调用do_arg所指向的函数,把这个字符和一个NULL指针作为参数传递过去。
如果该字符位于control字符串内并跟一个+号,那么就应该有一个值与这个字符相联系。如果当前参数还有其他字符,它们就是我们需要的值。否则,下一个参数才是这个值。在任何一种情况下,你应该调用do_arg所指向的函数,把这个字符和指向这个值的指针传递过去。如果不存在这个值(当前参数没有其他字符,且后面不再有参数),那么你应该调用Illegal_arg函数。注意:你必须保证这个值中的字符以后不会被处理。
当所有以一个横杆开头的参数被处理完毕后,你应该返回一个指向下一个命令行参数的指针的指针(也就是一个诸如&argv[4]或argv+4的值)。如果所有的命令行参数都以一个横杆开头,你就返回一个指向“命令行参数列表中结尾的NULL指针”的指针。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **do_args(int argc, char **argv, char *control, void (*do_arg)(int ch, char *value), void (*illegat_arg)(int ch));
void do_arg(int ch, char *value);
void illegat_arg(int ch);

void main(int argc, char **argv)
{
	char **last;
	char *control = "abcdef";
	
	last = do_args(argc, argv, control, do_arg, illegat_arg);
	printf("last argv: %s\n", *last);
}

char **do_args(int argc, char **argv, char *control, void (*do_arg)(int ch, char *value), void (*illegat_arg)(int ch))
{
	int i;
	int ch;
	char *ch_p;
	char *locate;

	for (i = 1; i < argc; i++) {
		ch_p = argv[i];
		if (*ch_p == '-') {
			ch_p++;
			while ((ch = *ch_p) != '\0') {
				ch = *ch_p;
				if ((locate = strchr(control, ch)) == NULL) {
					illegat_arg(ch);
				}
				else {
					if (*(locate + 1) != '+') {
						do_arg(ch, NULL);
					}
					else {
						if (*(ch_p + 1) != '\0') {
							do_arg(ch, ch_p + 1);
							break;
						}
						else if (argv[i + 1] != NULL)
							do_arg(ch, argv[++i]);
						else
							illegat_arg(ch);
					}
				}
				ch_p++;
			}
		}
		else
			break;
	}

	return &argv[i];
}

void do_arg(int ch, char *value)
{
	printf("do arg: ch = %c, value = %s\n", ch, value);
}

void illegat_arg(int ch)
{
	printf("illegat arg: ch = %c\n", ch);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值