鱼C论坛

 找回密码
 立即注册
查看: 3062|回复: 3

[技术交流] 《C语言入门经典》一道课后题引出的编程思考

[复制链接]
发表于 2014-3-18 12:45:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
[ 本帖最后由 199 于 2014-3-18 12:56 编辑 ]

这几天在看《C语言入门经典》(Ivor Horton 第四版),大学四年中有两年半是扎扎实实的去玩了。玩够了大三下帮老师做项目,我就是打杂的,但是自己画了个51单片机的电路,以后想玩自己可以花钱请人打板。大四上考研,光荣战死。现在我像大一新生一样,每天要看C语言,C++,因为我毕业设计选了一个全校最牛,要求极其严格的老师。老人家教龄30多年,那个年代走过来的,要是我敢混, 非被这个老师一个键盘拍死。再加上以前玩得很有心得,这几天买了个超级不错的键盘,开始我正式的复习+预习程序学习之路,其实这个程序设计范围太大了,咱们就聊一道课后题,然后由这道课后题想到的,咱们慢慢说。

首先,这道题目是第六章习题6.2题目,我把要求大致复述一下:编写一个程序,输入一系列单词,单次之间以逗号分隔,然后提取这些单词,并将他们分行输出,删除头尾的空格。例如输入:
John,Jack,jill
输出将是:
John
Jack
Jill

题目分析:最怕出版商打印空格这些东西,你知道排版的时候很多空格就给搞丢了。所以,这个程序就不考虑空格了,直接考虑逗号‘,’的解决,说真的开始这个题目还真的要我耗费了一下脑筋。两种解法,第一种复杂些,抛砖引玉,这个就是砖,第二种解法就是玉。

解法1:写一个字符串数组,用于接收用户的输入;设计一个整形数组,用于统计字符串数组中逗号的序号(模块1)。然后以这些序号为基础,分为三类输出:把第一个逗号前的字符串输出(模块2-1);把第一个逗号和最后一个逗号之间的单词输出(模块2-2);把最后一个逗号以后的字符串输出(模块2-3)。 这些就是这个解法的思路了。直接上源代码和心得:

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

void main()
{
        char data[20];                                                                    //模块1
        int point[20];
        printf("Input your words less than 20 letters in total:\n");
        gets(data);
        int j=0;
        for (int i=0;i<20;i++)
        {
                if(data[i]==',')
                        point[j++]=i;            
        }
/*
         for(int k=0;k<20;k++)
         {
                if(point[k] <0 || point[k] >20) point[k] = 0;
                 else
                         printf("%d ,",point[k]);  
         }
*/
        for(int m=0;m<point[0];m++) printf("%c",data[m]);         //模块2-1
        printf("\n");
        int s=0;
        
        while(point[s])                                                                     //模块2-2
        {
                for(int n=point[s]+1;n<point[s+1];n++)
                {
                        printf("%c",data[n]);
                }     
                printf("\n");
                s++;
        }


        for(int last =0;last <20;last++)                                                       //  模块2-3
        {
                if(point[last+1]==0 && point[last]>point[last-1])
        {
                for(int lastlast =point[last];lastlast<20;lastlast++)
                {
                        if (isalpha(data[lastlast]))
                                printf("%c",data[lastlast]);
                }
                printf("\n");
        }
        }
}



心得:(1)看不见的编程过程:除了你人生的第一个Hello World,很少有程序会只要求你只写一两行的代码了,那么对于我们来讲,不得不面对的问题是程序的调试,关于程序的调试,《C语言入门经典》中提到,编写了一个小功能的时候你就编译一下,不要写完了所有再一下子编译,那样会增加程序的死亡率。第一种解法中注释掉的第一处区域,其实是打印point数组,即逗号的位置,这个不是解法1的核心,但是确是该解法思路的基础,如果数组不对,下面你可以设置好自动关机,清理下垃圾,抽根烟,拿个快递了;所以这一步骤里面,我把point数组打印,尔后还给point中没有使用的空间赋值,这些都是打印了数组后方便下面的进行做的工作。(2)具体的调试过程:VC++6.0中提供了调试工具,以前老师就教我单步执行,查看寄存器,汇编代码等等。太复杂了,从来不用,就用printf来调试(只是当年那个老师的研究生助教交给我的)。这里面也有诸多技巧,即与你自己的想法有关,因为程序是你写的,你自己就会琢磨哪里用printf,哪里不需要用,需要输出什么等问题,一句话:自己做,自然会。(3)高聚合低耦合:C是非常适合模块化的语言,如果遇到合适的程序,那么完全可以看到C程序是由一个一个函数组成的;每个函数就完成一个单一的功能,不要一个函数完成很多功能,这个可以保证你的函数写好了,可以被其它人调用,比如下次要用,你直接拷贝过来就行了;(4)关于完美:很多人在做一件事情的时候,大多会想到自己利用时间把这件事情做到完美,很多同学也以完美主义者自居,我觉得如果你每次都做到了,你是大牛,如果你做不到,甚至什么都没做,那么就是浮躁。解决一个问题的时候,首先考虑的应该是如何把这个问题解决,解决了问题以后才考虑完美这个词,那时候你需要的是思考和改进。说真的,解决问题的最难的一点往往是问题的解决,即使你有思路,实现这个思路大多也是不易的。至于完美,在什么都没做的时候说就有点扯淡了。前几天看我同学大鹏的QQ签名:做完事情,要胜于完美收工。他已经工作了,实打实做的是项目,不是几十行代码的玩具,这就是经验。同样提出这种思想的还有《数学之美》那本书里面提到的艾利克·布莱尔(大牛,宾夕法尼亚大学马库斯实验室里待过),即简单之美,简单有效,我的思路略有不同,即直接暴力有效就行了。这个程序还能写得更好吗?能,我现在一个想法就可以给它来个大改,例如函数的使用,例如低耦合,但是有必要吗?没有,我要的是独立解决这个问题的过程,不看答案较劲脑汁把问题解决了。解决问题再付出的话就是写点东西留给自己看,也给大家一些思路,那些细枝末节的事情不要兼顾。


解法2:依旧是写一个字符串数组,接收用户的输入,然后打印该字符串数组,要是判断为字母,则打印该字母本身,如果是‘,’,则打印'\n',如果遇到空格等,不要操作,这样就完成了。


#include<stdio.h>
#include <ctype.h>
void main()
{
        char test[20];
        printf("Input your number:\n");
       gets(test);

        for(int i=0;i<20;i++)
        {
                if(isalpha(test[i]) )
               {
                      printf("%c",test[i]);
                 }
                else if (test[i] = ',')
                {
                        printf("\n");
                }
       else
      ;
     }
}


心得:(1)该程序的过程:吃了晚饭回来写的第二种解法,路上就在想,那个C语言不就是围着内存转吗?也就是一排一排的小房子,所以循环是少不了的。那么如何循环是一个问题,循环中干什么也是我该考虑的,我干嘛用那么多排房子存储不同的数据,直接在原始数据上循环,打印不就可以了吗?所以回来后哦很快就写好了。第一个if,判断是不是字幕,打印字母,如果你字符串里面有数字也要打印,加一个或语句,判断是不是数字if (isalpha(test[i]) || isdigit(test[i]))(你确定老美的名字有数字?美国版王二麻子?:titter:).第二个else if 判断是不是',',打印‘\n’,第三个else千万不要删掉啊,那是给空格等符号留着的,遇到这些啥也不要做,直接执行下次循环(continue?不清楚,自己试下呗)。(2)还有其他关于编程的思考,那是我这四年调皮捣蛋的经验,下次再说,下次再说。对了,学习写程序最重要的方法就是独立写,不要说我学完了集中写,能写就抓紧写,哪怕你看了一个自然段觉得有点心得需要表达。还有,千万不要背东西,这个就是一门手艺,就像游泳,骑马,不是你背了一本书就能体会的,如果算法什么的需要背下来,直接抄在txt文件里面,用的时候拿过来直接用。等你在一个语言泡久了,写程序基本上就是copy自己原来的程序了。当然,这也说明,你在做浪费时间的事情,该学习新的东西,让自己活力绽放吧。



[/i][/i][/i][/i][/i][/s][/s][/i]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-3-18 13:04:10 | 显示全部楼层
小白表示不太懂,大一,刚学习C语言入门。希望能有理解的那天哈哈!!!:big
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-18 14:24:04 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-4-21 10:38:32 | 显示全部楼层
感谢楼主分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-26 01:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表