写这篇文章之前,犹豫了很久要不要写一写关于数组和集合的应用问题,对难点进行分析。但随后想到目前对数组和集合只是简单应用,而遇到的问题也只是基础知识不牢固,对其余的知识带入不强导致的,仔细分析、认真钻研,总能找到解决办法,而且并没有太合适的例子可以进行分析,所以这个问题还是暂且搁置。
仔细回想下这一周以来在C#学习中的经历,觉得可以对问题查找和程序功能实现时出现的问题做个简单的思考总结。一方面是感觉身边存在对简单问题查找存在困难的现象主要是对代码实现功能分辨度不够,另一方面是自己在编写代码时,得到的运行结果并没有实现自己想要的功能,仔细检查时发现是对问题考虑不全,也有存在实现功能的描述不完善,进行编码时只考虑描述功能如何实现,并未考虑用户实际情况不同带来的影响。
那么,如果是代码选择不正确导致的问题,编译没有导致错误,程序运行却没有达到想要的效果。针对这一类问题,只能通过运行的错误表现情况,对照源代码,将实现功能的这一部分代码从上到下进行运算(此时应通过自己对语句分析进行运算),从而判断问题产生的原因。如果对于这一问题较难判断,应当加强基础知识的积累,对所学知识首先做到全部记忆,再融会贯通,在适合的位置选择最适合的代码,这样才有足够解决分析问题的本钱。下面列举几个小例子:
实现在控制台输出:
请补足下面这个成语:
为虎作()
想要实现这个功能十分简单,但是,也会有一部分人这样写:
Console.Write("请补足下面这个成语:"); Console.WriteLine("为虎作()"); Console.ReadLine();
现在看到这个代码的确是一眼能看出第一行没有换行,是只使用了Console.Write();语句,而没有使用换行语句,也没有使用换行的转义符。但是在实际情况中,的确是存在面对这一现象很难找到原因的情况,对此还是应该加强代码的理解和积累。并且,将这一问题加深,比如实现输入错误后,提示错误并清屏等待用户重新输入,或者使用更长的文本和换行转义符穿插使用等更复杂的情况,是否还能一眼判断出问题发生的原因呢,这时就只能对实现功能的那一部分代码进行逐一排除了。
下面再举一个例子,问题发生就不是在语句上面:
在控制台实现对数组中的整数判读是否为质数,如果是质数,那么将其输出:(省略前面的代码,只写出实现功能这一块)
for(i = 0;i < nums.Length; i++) { int z = 0; for(j = 1;j < nums[i]; j++) { if(nums[i] % j == 0) { z++; } } if(z==2) Console.Write(nums[i]+"\t"); } Console.ReadLine();
运行程序后,发现控制台中并没有质数,如果多次尝试,可能会有1出现,但是1并不是质数。那么问题是发生在哪里呢?根据前面的方法,先检查语句,发现并没有可以影响输出结果语句错误。那么再次分析,因为影响计算结果的输出,除开输出语句,也需要考虑到代码实现和运算方法有没有可能错误,针对这一份代码,考虑到计算方法对代码逐条进行分析。首先第一个for将数组中的数逐一取出,再利用第二个for循环将这个数从1到这个数本身判断能否被整除,观察代码,发现对于for循环的判定,当j<nums[i]语句在实现过程中,并不能满足j自增到这个数本身时运行循环体,所以每次计算并没有运算数据被自身整除的情况。想要实现这段代码,应该将j<nums[i]改为j<=nums[i]。
由此可见,小小一个符号就能导致程序功能的失效,正确判断数据的计算方式也是关键之一。
另外,还有一种问题就不是那么直白了,当然,为了方便,例子还是上面那个,所以看到这一段代码,还是能够直接发现问题的:
int z = 0; for(i = 0;i < nums.Length; i++) { for(j = 1;j <= nums[i]; j++) { if(nums[i] % j == 0) { z++; } if(z==2) Console.Write(nums[i]+"\t"); } } Console.ReadLine();
对比上面,可以很轻松看出对z的赋值不能放在第一个for循环外面,否则每次循环对z计数,z的值是始终增加,没有得到验证的目的。那么再来看看第二个if判断是否应该放在第二个for循环外面,通过分析可以发现,第二个if判断的位置并不影响程序功能实现。其实这个例子并不是很好,在此我想表达的是在循环中,if判断位置的正确放置对程序功能实现的影响,一般遇到这种情况,最好的办法是画流程图,判断循环和循环、循环和判断的位置关系,是否应该包含,还是并列等。
还有一个容易发生的错误,就是关于变量作用域范围的使用,仍然使用一个例子说明:
int i; if(true) { int z = 10; i = z; } Console.Write(i); Console.ReadLine();
受限于自身的知识储备情况,实在不能举出更好的例子(可能遇到过,但是没有记录,以后会改进,并总结发布的)。当然,对于这段代码,在VS中很容易能找到错误,不能使用未赋值的变量i。那么令i=0,再循环,最后会输出0还是10呢?运行代码后发现控制台出现的数值为10。定义一个变量后,这个变量的内存空间就已经生成了,往后的运算只是更改储存的值,并没有更改内存空间的位置。而在上面的情况中,输出i的语句并不会判断变量作用域中的情况,因为i的定义实在if作用于之外,就算if判断后只有i=10;这一条语句从而省略大括号,变量作用域的影响依旧存在。当然,在实际使用中像这种简单的代码很容易避免出错,但是难免出现更复杂的情况,只是提醒自己需要注意。
最后,不得不提起用户输入的问题。目前只是在控制台实现程序功能,而数学计算是比较常见的。由于目前只是接触了数据、预算、循环、数组和集合这些基本知识,面对需要将用户输入的数字完成各种运算后,输出运算结果的情况,就无法避免要求用户进行输入,再对输入进行取值。控制台输入Console.ReadLine();语句获取的为字符串格式的数据,想要转换为数字类型,至少需要用户输入小数形式的数据。但是用户毕竟有自己的主观思想,计算机并不能限定用户的输入具体是什么内容,如果输入一串英文,那么计算机就会造成运行错误。如果数字仅限于几个,那个可以使用input=="限定数字"的方式来实现条件控制,使程序在不崩溃的情况下运行。但是,要求用户的输入往往是不确定的值,这时就需要自己增加提示信息了,以满足程序的人性化设计。
但就目前接触的情况而言,很难找到一个案例考虑了再各步骤运算都进行友好提示的情况,那么,遇到这种情况,就需要编程的人来完善项目的不足。例如提示输入数字、提示输入的数字超过范围,需要重新输入!、提示集合中没有这一个数,请重新输入进行删除!等等。程序最终是为人类服务,虽然目前并没有人为我提及这些东西,但是就个人而言,提示信息就像是对程序员而言的代码注释一样,也是关键的不可或缺的一部分,是完善作品必须考虑的内容。
总而言之,面对程序的编写,要从多方面考虑代码的实现和实现之后的效果,代入数据进行多次调试,代入多种类型、多种范围的数据确定程序运行能否达到最优化。