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, ¤t, 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);
}