• CPrimerPlus第11章第10题


    题目:

    编写一个程序,读取输入,直到读入了10个字符串或遇到EOF,由二者中最先被满足的那个终止读取过程。这个程序可以为用户提供一个有5个选项的菜单:输出初始字符串列表、按ASCII顺序输出字符串、按长度递增顺序输出字符串、按字符串中第一个单词的长度输出字符串和退出。菜单可以循环,直到用户输入退出请求。当然,程序要能真正完成菜单中的各项功能。


    1.先完成第一个部分,读入字符串。

    打算使用指针数组来储存字符串们,先定义并初始化指针字符串(指针需要初始化,指针数组也是,担心成为野指针,所以刚开始全部指向NULL,发现后来就用不了,所以还是用malloc分配一下内存给指针吧)。

        char *str[10];
        for(i=0; i<10; i++)
            str[i] = (char *)malloc(200 * sizeof(char));

    按要求读入字符串们,遇到EOF或者读入了10个字符串就停止读入。结果不行,因为函数gets(ptr)如果发现了EOF就返回NULL,不会把EOF读入并让指针ptr指向的(比方说我吩咐了gets()去读EOF符号,他碰到了EOF符号并没有读入,而是跑回来跟我说,臣妾做不到啊~)。

        while(j<10  &&  (*str[j]!=EOF))
        {
            gets(str[j]);
            j++;
        }

    所以修改while()中的判断条件,且修改后的while()条件中已经包含了gets()函数,每次判断时已经执行了一遍,所以下面循环中的gets()要删除,只留下j++就好了。

        while( (j<10) && (gets(str[j]) != NULL))//(*str[j]!=EOF)这个作为判断是不行滴
            j++;

    2.设计好主函数的思路,分析逻辑,编写主函数部分。主要就是用if和else的组合给选择分类,要注意选择超出选项范围的情况。代码如下

    while (scanf("%c",&choice) == 1)
        {
            if(choice < 'a' || choice > 'e')
                printf("choice must be between 'a' and 'e'
    ");
            if(choice == 'e')
                exit(1);
            else
            {
                if(choice == 'a')
                    print_orig(str);
                if(choice == 'b')
                    print_as_ascii(str);
                if(choice == 'c')
                    print_as_strlen(str);
                if(choice == 'd')
                    print_as_1strlen(str);
            }
            getchar();    //清除enter键确认输入时带来的换行字符
            puts("make your choice(a, b, c, d, e):");
            print_table();
        }
        puts("fail reading the choice, good bye!");
    
        return 0;
    }

    3.分别编写各个子函数

    3.0 打印表头,这个简单,就是printf函数即可

    /*******************************打印表头***************************/
    void print_table(void)    
    {
        printf("a) print original text              b) print lines in order of ASCII
    ");
        printf("c) print lines in order of strlen   d) print lines in order of first word's len
    ");
        printf("e) exit
    ");
    }

    3.1 打印原来的字符串们,由于刚开始就考虑使用指针数组,因此挨个指针进行打印就可以了(循环puts(str[i]几次即可))

    /**************************打印原字符串们**************************/
    void print_orig(char *str[])
    {
        int i;
        for(i=0; i<lines; i++)
            puts(str[i]);
    }

    3.2 按照字符串ascii码大小来打印字符串们,需要对字符串们进行排序,本章讲解了选择排序的算法,在这里正好使用上,我之前的博客也提到了。代码如下,注意注释中的注意。不过经过排序后指针变换了指向的位置,所以执行完选择排序后再想打印出原字符串们,就不能用指针了。我能想到的办法就是再用一组指针,指向这些字符串们,变一组指针,不变另一组指针,打印原字符串们时就用不变的指针数组,选择排序时就用变得指针数组(时间原因自己没有弄了)。

    /*********************按ascii码打印字符串们*************************/
    void print_as_ascii(char *str[])
    {
        int i,j;
        char * p_temp;
        for(i=0; i<lines; i++)
        {
            for(j=i+1; j<lines; j++)
            {
                if(ascii_num(str[i]) > ascii_num(str[j]))    //参考答案是用strcmp()函数来比较字符串的ascii码值大小的,我自己不嫌麻烦又写了个函数(其实是没想到,呜呜~~)
                {
                    p_temp = str[i];    //比的是ascii_num(str[i])和ascii_num(str[j]),调换的是str[i]和str[j],这里有映射关系!!映射问题困扰了我半天
                    str[i] = str[j];
                    str[j] = p_temp;
                }
            }
        }
        print_orig(str);
    }

    3.3 按照字符串长度来输出字符串们,和上面的套路其实都一样了,只是比较时使用strlen()函数即可。代码如下

    /**********************按字符串长度打印字符串们*********************/
    void print_as_strlen(char *str[])
    {
        int i,j;
        char * p_temp;
        for(i=0; i<lines; i++)
        {    
            for(j=i+1; j<lines; j++)
            {
                if(strlen(str[i]) > strlen(str[j]))
                {
                    p_temp = str[i];
                    str[i] = str[j];
                    str[j] = p_temp;
                }
            }
        }
        print_orig(str);
    }

    3.4 按照字符串中第一个单词的长度来排序并输出字符串们,同上的套路,只是比较时比较首单词的长度而已。我没有仔细考虑具体情况,简单写了个函数(开头的就是空格的话就算0),当然考虑清楚写的缜密些最好了,只是这里我想自己毕竟出于练习的目的,不必花太多时间(其实也写了两三天了,呜呜~,心里烦他了~呜呜~)。

    /********************按字符串中首个单词长度打印*********************/
    void print_as_1strlen(char *str[])
    {
        int i,j;
        char *p_temp;
        for(i=0; i<lines; i++)
        {
            for(j=i+1; j<lines; j++)
            {
                if(first_len(str[i]) > first_len(str[j]))
                {
                    p_temp = str[i];
                    str[i] = str[j];
                    str[j] = p_temp;
                }
            }
        }
        print_orig(str);
    }

    3.5 在3.2和3.4中自己有写两个简单的小程序,分别计算ascii码值和首单词长度,代码如下(随便写的,不缜密)

    int ascii_num(char * p)    //计算一个字符串的ascii码值
    {
        int i,asciinum = 0;
        for(i=0; *(p+i)!=''; i++)
            asciinum+=*(p+i);
        return asciinum;
    }
    
    int first_len(char *p)    //计算一个字符串中首单词的长度
    {
        int i;
        for(i=0; *(p+i)!=' '; i++);
        return i;
    }

    4.总结

    参考答案中使用了二维数组和指针数组,把输入读入二维数组的指针,再用指针数组分别指向各个字符串,算是备份好了原文件,然后折腾指针也不怕损坏原文件的顺序什么的吧。这一点值得学习。参考答案中的选择排序在实现时基本与我的差不多;主函数中没有用if—else组合,而是用的switch—case组合;调用了库函数strcmp(),isalpha(),不浪费资源啊。

    经过调试算是能完成任务了吧,但是问题还是有滴,所以我想还是在程序开头位置作好说明,毕竟如果再回头看时能方便回忆和理清思路,尤其是程序稍微有点复杂时(这是我自己编的比较长的程序了,可见自己有多水了。不过路漫漫其修远兮,自己慢慢努力慢慢完善自己吧,加油^_^)。

     
  • 相关阅读:
    关闭Windows的CTRL+ALT+DEL 和 ALT+TAB组合键的方法
    VC中常用文件操作(一)
    VC 创建NT服务程序
    几个操作文件的API函数
    VC中常用文件操作(二) ——INI文件操作
    初学OpenCV之图像坐标读取函数cvGet2D()
    OpenCV学习之图像读取与显示
    SLT容器之vector简单实现C++运行时多态
    C/C++文件——数据写入、读取
    OpenCV学习之视频读取与帧的提取、显示及保存
  • 原文地址:https://www.cnblogs.com/TomLily/p/6010531.html
Copyright © 2020-2023  润新知