C和指针_编程练习_第9章_第16题

/*
        这个程序与前面一个练习程序相似, 但它更为通用.
        它按照一个指定的格式字符串对一个数字字符串进行格式化, 类似于许多BASIC 编译器所提供的"print using" 语句.
        函数的原型应该如下:
        int format( char *format_str, char const *digit_str );

        digit_str 中的数字根据一开始在format_str 中找到的字符从右到左逐个复制到format_str 中. 
        注意被修改后的format_str 就是这个程序处理的结果.
        当你完成时, 确定format_str 依然是以字符NUL 结尾的.
        根据格式化过程中是否出现错误, 函数返回真或假.
        
        格式字符串可以包含下列字符:
        #       在两个字符串中都是从右向左进行操作. 格式字符串中每一个# 字符都被数字字符串中的下一个数字取代. 如果数字字符串用完, 格式字符串中所有剩余的# 字符由空白符代替(但存在例外, 请参见下面对小数点的讨论)

        ,       如果逗号左边至少有一位数字, 那么它就不作修改. 否则它就由空白符代替.

        .       小数点始终作为小数点存在. 如果小数点左边没有一位数字, 那么小数点左边的那个位置以及右边直到有效数字为止的位置都用0 填充.

        下面的例子说明了这个函数的一些调用结果. 符号* 用于表示空白.
        格式字符串:             数字字符串:             结果格式字符串:
        #####                   12345                   12345
        #####                   123                     **123
        ##,###                  1234                    *1,234
        ##,###                  123                     ***123
        ##,###                  1234567                 34,567
        #,###,###.##            123456789               1,234,567.89
        #,###,###.##            1234567                 ***12,345.67
        #,###,###.##            123                     ********1.23
        #,###,###.##            1                       ********0.01
        #####.#####             1                       ****0.00001

        为了简化这个项目, 你可以假定格式字符串所提供的格式总是正确的. 最左边至少有一个# 符号, 小数点和逗号的右边至少也有一个# 符号. 而且逗号绝对不会出现在小数点的右边.
        你需要检查的错误只有:

        a. 数字字符串中的数字多于格式字符串中的# 符号.
        b. 数字字符串为空.

        发生这两种错误时, 函数返回假, 否则返回真. 如果数字字符串为空, 格式字符串在返回时应未作修改.
        你如你使用指针而不是下标来解决问题, 你会学到更多东西.

        提示:
        开始时让两个指针分别指向格式字符串和数字字符串的末尾, 然后从右向左进行处理.
        对于作为参数传递给函数的指针, 你必须保留它的值, 这样你就可以判断是否达到了这些字符串的左端.
*/

typedef enum { false, true } bool;

#include <stdio.h>

bool Is_Format( char *formatStr, char const *digitStr )
{
        /*
         * formatCnt: 记录格式字符串中字符# 个数
         * digitCnt: 记录数字字符串中数字个数
         */
        unsigned int formatCnt, digitCnt;
        char *const formatStrMark = formatStr;
        char const *const digitStrMark = digitStr;

        if( digitStr == NULL )
        {
                return false;
        }

        /* formatStr 指向格式字符串末尾的NUL 字符 */
        for( ; *formatStr != '\0'; ++formatStr )
        {
                ;
        }

        /*
         * 假定数字字符串格式总是正确的(全部都是数字)
         * digitStr 指向数字字符串末尾的NUL 字符
         * digitCnt 记录了数字字符串中数字个数
         */
        for( digitCnt = 0; *digitStr != '\0'; ++digitStr )
        {
                ++digitCnt;
        }

        /*
         * tmp: 临时指针
         * Is_PointAppeared: 布尔值
         */
        char *tmp;
        bool Is_PointAppeared;

        /* 从右向左遍历格式字符串和数字字符串, 直到遍历到格式字符串的起始位置 */
        for( --formatStr, --digitStr, formatCnt = 0; formatStr != formatStrMark - 1; --formatStr )
        {
                switch( *formatStr )
                {
                        case '#':
                                /*
                                 * 格式字符串当前字符为'#' 时, 如果数字字符串还没走到最左端, 复制对应位数字到格式字符串的当前字符位, 随后两个指针都前移一位
                                 * 如果此时数字字符串走到了最左端, 说明该位格式字符串要进行填充, 应该填充'0' 还是空格呢?
                                 * 此时就要检测格式字符串当前位左边是否存在小数点'.', 如果有小数点, 则填充 '0', 如果没有小数点, 则填充空格,
                                 *
                                 * 格式字符串的当前位不管是填充还是复制的, 最后formatCnt 都应该自增1
                                 */
                                if( digitStr != digitStrMark - 1 )
                                {
                                        *formatStr = *digitStr--;
                                }
                                else
                                {
                                        for( tmp = formatStr, Is_PointAppeared = false; tmp != formatStrMark - 1; --tmp )
                                        {
                                                if( *tmp == '.' )
                                                {
                                                        Is_PointAppeared = true;
                                                        break;
                                                }
                                        }

                                        Is_PointAppeared ? (*formatStr = '0'): (*formatStr = ' ');
                                }
                                ++formatCnt;
                                break;

                        case ',':
                                /* 格式字符串当前字符为逗号时, 如果数字字符串走到了最左端, 逗号改空格, 如果没有走到最左端, 逗号保留 */
                                if( digitStr == digitStrMark -1 )
                                {
                                        *formatStr = ' ';
                                }
                                break;

                        case '.':
                                /*
                                 * 小数点出现后, 小数点肯定会保留, 需要关注的是小数点左边有没有一位数字
                                 * 如果没有, 则小数点左边那个位置要用'0' 来填充
                                 *
                                 * 小数点左边没有数字时, 程序还要检测小数点左边是否是字符# 
                                 * 原因是当格式字符串中, 当前小数点左边还是小数点时, 我认为它依然是符合规范的, 应该原封不东地把两个小数点都保留
                                 *
                                 * 题目中已经说明格式字符串最左边一定有一个字符#, 所以当前字符为小数点时, 可以把formatStr大胆地前移一位并解引用, 而不用担心越界问题
                                 * 填充0 后, formatStr 前移一位
                                 */
                                if( digitStr == digitStrMark -1 )
                                {
                                        if( *( formatStr - 1 ) == '#' )
                                        {
                                                *--formatStr = '0';
                                                ++formatCnt;
                                        }
                                }
                                break;

                        default:
                                /* 如果格式字符串格式正确, 不干了, 直接返回false */
                                return false;
                }
        }

        /* 如果格式字符串中的字符# 个数不小于数字字符串中的数字个数, 函数返回真, 否则返回假 */
        return  formatCnt >= digitCnt ? true: false;
}


int main( void )
{
        char *digitStr;

        char formatStr_1[] = "#####";
        digitStr = "12345";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_1, digitStr );
        Is_Format( formatStr_1, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_1 ): printf( "结果字符串: %-20sfalse\n", formatStr_1 );

        char formatStr_2[] = "#####";
        digitStr = "123";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_2, digitStr );
        Is_Format( formatStr_2, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_2 ): printf( "结果字符串: %-20sfalse\n", formatStr_2 );

        char formatStr_3[] = "##,###";
        digitStr = "1234";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_3, digitStr );
        Is_Format( formatStr_3, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_3 ): printf( "结果字符串: %-20sfalse\n", formatStr_3 );

        char formatStr_4[] = "##,###";
        digitStr = "123";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_4, digitStr );
        Is_Format( formatStr_4, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_4 ): printf( "结果字符串: %-20sfalse\n", formatStr_4 );

        char formatStr_5[] = "##,###";
        digitStr = "1234567";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_5, digitStr );
        Is_Format( formatStr_5, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_5 ): printf( "结果字符串: %-20sfalse\n", formatStr_5 );

        char formatStr_6[] = "#,###,###.##";
        digitStr = "123456789";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_6, digitStr );
        Is_Format( formatStr_6, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_6 ): printf( "结果字符串: %-20sfalse\n", formatStr_6 );

        char formatStr_7[] = "#,###,###.##";
        digitStr = "1234567";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_7, digitStr );
        Is_Format( formatStr_7, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_7 ): printf( "结果字符串: %-20sfalse\n", formatStr_7 );

        char formatStr_8[] = "#,###,###.##";
        digitStr = "123";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_8, digitStr );
        Is_Format( formatStr_8, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_8 ): printf( "结果字符串: %-20sfalse\n", formatStr_8 );

        char formatStr_9[] = "#,###,###.##";
        digitStr = "1";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_9, digitStr );
        Is_Format( formatStr_9, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_9 ): printf( "结果字符串: %-20sfalse\n", formatStr_9 );

        char formatStr_10[] = "#####.#####";
        digitStr = "1";
        printf( "格式字符串: %-20s 数字字符串: %-20s ", formatStr_10, digitStr );
        Is_Format( formatStr_10, digitStr ) ? printf( "结果字符串: %-20strue\n", formatStr_10 ): printf( "结果字符串: %-20sfalse\n", formatStr_10 );

        return 0;
}

程序运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值