C和指针 第13章 高级指针话题 13.10 编程练习

1. 编写一个程序,从标准输入读取一些字符,并根据下面的分类计算各类字符所占的百分比。
    控制字符
    空白字符
    数字
    小写字母
    大写字母
    不可打印字符
这些字符的分类是根据ctype.h中的函数定义的。不能使用一系列的if语句。 
解析:
这个问题是在第9章给出的,但那里没有对if语句施加限制。这个限制的意图是促进你考虑其他实现方法。函数is_not_print的结果是isprint函数返回值的负值,它避免了主循环处理特殊情况的需要,每个函数保存了函数指针、标签以及每种类型的计数值。
/* 
** 计算从标准输入的几类字符的百分比。 
*/ 
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> 
/*
** 定义一个函数,判断一个字符是否为可打印字符。这可以消除下面代码中这种类型的特殊情况。 
*/
int is_not_print( int ch ){
    return !isprint( ch );

/*
** 用于区别每种类型的分类函数的跳转表。 
*/
static int(*test_func[])( int ) = {
    iscntrl,
    isspace,
    isdigit,
    islower,
    isupper,
    ispunct,
    is_not_print
};

#define N_CATEGORIES (sizeof(test_func) / sizeof(test_func[0]))

/*
** 每种字符类型的名字。 
*/
const char *label[] = {
    "control",
    "whitespace",
    "digit",
    "lower case",
    "upper case",
    "punctuation",
    "non_printable"
};

/*
** 目前见到的每种类型的字符数以及字符的总量。 
*/
int count[N_CATEGORIES]; 
int total;

int main( void ){
    int ch;
    int category;
    
    /*
    ** 读取和处理每个字符。 
    */
    while( (ch = getchar()) != EOF ){
        total += 1;
        
        /*
        ** 为这个字符调用每个测试函数。如果结果为真,增加对应计数器的值。 
        */
        for( category = 0; category < N_CATEGORIES; category += 1 ){
            if( test_func[category]( ch ) ){
                count[category] += 1;
            }
        } 
    }
    
    /*
    ** 打印结果。 
    */ 
    if( total == 0 ){
        printf( "No characters in the input!\n" );
    } else{
        for( category = 0; category < N_CATEGORIES; category += 1 ){
            printf( "%3.0f%% %s characters\n", count[category] * 100.0 / total, label[category] );
        }
    }
    
    return EXIT_SUCCESS;
}
输出:

2. 编写一个通用目的函数,用于遍历一个单链表。它应该接受两个参数:一个指向链表第一个节点的指针和一个指向一个回调函数的指针。回调函数应该接受单个参数,也就是指向一个链表节点的指针。对于链表中的每个节点,都应该调用一次这个回调函数。这个函数需要知道链表节点的什么信息?
解析:
需要知道这个节点是否为空,不为空则打印列表信息。
#include <stdio.h>
#include <stdlib.h>

#define ELEMENT_TYPE int
typedef struct NODE{
    ELEMENT_TYPE value;
    struct NODE *link;
} Node;
 
void print( void const *node );
void traverse( Node *first, void (*pf)( void const * ) );
int main( void ){
    Node third;
    Node second;
    Node first;
    
    third = (Node){ 3, NULL };
    second = (Node){ 2, &third }; 
    first = (Node){ 1, &second };
    printf( "traverse the single linked list:\n" );
    traverse( &first, print );
    
    return EXIT_SUCCESS;
}

void print( void const *node ){
    printf( "%d ", ((Node*)node)->value );
}

void traverse( Node *first, void (*pf)( void const * ) ){
    while( first ){
        pf( first );
        first = first->link;
    } 
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值