之初学习C,是在VC下面的(其实第一个hello world都是在turbo C下面敲出来的,蓝色屏幕,hello world,别提当时多激动了)。
学到后面,见识过各路高手批评我的代码风格很乱,后面才慢慢改,原谅我的无知,看的第一本教材是用的老谭的PDF版本的(高中毕业,在家没事干,窝在家里对着老掉牙的turbo C 敲代码,只是觉得很好玩,觉得这东西很神奇,我居然可以让电脑按照我的想法做事情,原来这就是编程。。。)
大概过了一个月的样子才换成VC,后面又嫌弃VC换成了code::blocks
问题来鸟。。。慢慢对自己代码风格有要求的时候,在VC下学会了一个当时看似很酷的skill。
[objc] view plaincopyprint?
while(!scanf("%d",&varible))
{
printf("sorry, your entered data is error!\please enter again!\n");
}
多漂亮的类型检查!
高中暑假的时候就只知道scanf,scanf。然后由scanf引起的各种bug,痛苦不堪啊。。。那种纠结是凌晨3点的痛。。。。。
当时只是知道函数返回值的概念,和现在的ZM差不多,但是很少利用这个返回值,我现在想尽力传递给ZM的思想就是领悟返回值的意义并学会利用返回值写出更好的代码,简直可以说逻辑漂亮的代码。可能我最近对你要求有点高吧。。。不过我希望ZM尽快的入门,少走我走过的弯路,当我告诉你一些细节的问题的时候,那些经验可能都是我熬了很久才学会的。短时间内,你可能会觉得难,这是正常的,但是你要知道,越是困难,经历过之后,你的收获也就越大。就好比打羽毛球一样,和高手打球进步速度是飞一般的。和水平相近或者更低的人,怎么都不能进步。我随不是高手,但是想把自己的经验告诉你,你也好少走点弯路,时间不多了,大二了。
废话少说,说scanf。
[objc] view plaincopyprint?
int scanf(const charchar *format, ...);
scanf的declaration 。你可能现在不知道指针和变长参数,没关系,不用管它,利用自己可以利用的信息,可以看懂返回值的类型是int。那么说,scanf是有返回值的。具体返回值的意义是什么呢?
要学着去man *** 。 你学C比我的起点高,教材也好,解决问题的渠道也比我当时多。当时我遇到问题了就一个人苦逼的郁闷。。。是到了大一开学军训的时候才把CPP看到中间的,想来当时很开心,不管走到哪儿都拿着手机看CPP,路上,开会,下课。有时间就看CPP。读一本好的书就像和大师交流一样。
你现在是在linux下学习C语言,可以说比很多人的起点都高。非常纯净的C环境,编译器是最标准的GCC。当然我知道,已经给你很大的挑战,所以没要你学terminal下用vim写C,而不是用code::blocks,不过你愿意的话,也可以学,也不是很难,其实我已经悄悄的教过你一点terminal的东西了。很多东西都是我花了很多时间才知道的,比方linux,我几乎用了一个暑假来入门,看了《鸟哥的linux私房菜》,我才知道怎么使用linux。而你是直接用的,我也反思,一下子都告诉你,接受不了也正常,所以当我问的急切的事情,别生气。。。我只是想你早点秒掉C。
好吧。。。不扯淡了
man scanf,你想要的他都会告诉你
RETURN VALUE
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.
scanf的返回值是正确读入的数据变量的个数。如果没有正确读入一个数据,返回0,出错返回EOF。
Question is coming. BUG is coming.
[objc] view plaincopyprint?
#include "stdio.h"
int main()
{
int ret = 0;
int var1 = 0;
while(!(ret = scanf("%d",&var3)))
{
printf("scanf error!\nplease enter again!\n");
}
printf("returned value : %d\n",ret);
return 0;
}
简单到死的测试代码。GCC bug了!
我故意输入一个字符例如'a' 然而,程序死在whlie循环里面了。一直输入下面这个报错提示
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
我当时就呆了!自己写了这么就的类型检查,居然bug了。。。完全没有意识到啊,gdb调试,发现根本就没有重新scanf读入,每次到scanf直接跳过了。第一感觉以为是编译器优化掉了,之前keil有类似的经历,相当之坑爹。。。关闭优化,发现还是一样的bug。。。不淡定了,各种google 百度。得到结论,是编译器的问题。其实还有个问题,但是我这里没有VC了,所以不方便在VC上测试,就是这篇blog最初给出的scanf类型检查方法其实也有个问题。可能有点不好理解,不过我觉得有必要跟说了。因为你已经接触了scanf,scanf那点事还是早知道好。。。
首先貌似我要给你介绍缓冲区这个概念。。。
缓冲区叫buffer。我们的标准输入都是从键盘或者其他输入设备输入的,然后把输入信息储存在缓冲区。如果你不能很具体的想象缓冲区是什么。你就想成是个盒子。。。然后这个盒子里面会暂时的存放数据,注意是暂时的哦。不然也不会叫“缓冲”区。。。
我们把输入信息输入到缓冲区,只有刷新缓冲区的时候,标准输入储存在缓冲区的信息才会显示在屏幕上面。如果不知道刷新是什么。你就想,刷新就是那个盒子(缓冲区)里面的东西全部都倒出来给你看。
背景知识over
正题,scanf在读入的时候,scanf("%d",&number);这个时候你不仅仅输入了一个int 类型数据,你输入了数据,你发现没有,你还敲击了键盘上面的一个键!which one? Enter!回车键!发现没有,我们每次输入数据都要确认输入,而确认输入就是通过回车,对不?这个时候键盘就会输入一个额外的信息!回车符号'\n'
这个时候你的缓冲区就存在两个数据 number 和' \n'! 当下一次scanf("%d",&number)的时候,程序就不会等待你输入数据写到number的地址里面去了。他会直接读取缓冲区的第一个数据,因为之前的number已经被读取了,此时缓冲区就只剩下‘\n’于是,‘\n’被读入number的地址,scanf发生错误(应该读入整形数据),于是scanf返回 0!
[objc] view plaincopyprint?
while(!scanf("%d",&varible))
学到后面,见识过各路高手批评我的代码风格很乱,后面才慢慢改,原谅我的无知,看的第一本教材是用的老谭的PDF版本的(高中毕业,在家没事干,窝在家里对着老掉牙的turbo C 敲代码,只是觉得很好玩,觉得这东西很神奇,我居然可以让电脑按照我的想法做事情,原来这就是编程。。。)
大概过了一个月的样子才换成VC,后面又嫌弃VC换成了code::blocks
问题来鸟。。。慢慢对自己代码风格有要求的时候,在VC下学会了一个当时看似很酷的skill。
[objc] view plaincopyprint?
while(!scanf("%d",&varible))
{
printf("sorry, your entered data is error!\please enter again!\n");
}
多漂亮的类型检查!
高中暑假的时候就只知道scanf,scanf。然后由scanf引起的各种bug,痛苦不堪啊。。。那种纠结是凌晨3点的痛。。。。。
当时只是知道函数返回值的概念,和现在的ZM差不多,但是很少利用这个返回值,我现在想尽力传递给ZM的思想就是领悟返回值的意义并学会利用返回值写出更好的代码,简直可以说逻辑漂亮的代码。可能我最近对你要求有点高吧。。。不过我希望ZM尽快的入门,少走我走过的弯路,当我告诉你一些细节的问题的时候,那些经验可能都是我熬了很久才学会的。短时间内,你可能会觉得难,这是正常的,但是你要知道,越是困难,经历过之后,你的收获也就越大。就好比打羽毛球一样,和高手打球进步速度是飞一般的。和水平相近或者更低的人,怎么都不能进步。我随不是高手,但是想把自己的经验告诉你,你也好少走点弯路,时间不多了,大二了。
废话少说,说scanf。
[objc] view plaincopyprint?
int scanf(const charchar *format, ...);
scanf的declaration 。你可能现在不知道指针和变长参数,没关系,不用管它,利用自己可以利用的信息,可以看懂返回值的类型是int。那么说,scanf是有返回值的。具体返回值的意义是什么呢?
要学着去man *** 。 你学C比我的起点高,教材也好,解决问题的渠道也比我当时多。当时我遇到问题了就一个人苦逼的郁闷。。。是到了大一开学军训的时候才把CPP看到中间的,想来当时很开心,不管走到哪儿都拿着手机看CPP,路上,开会,下课。有时间就看CPP。读一本好的书就像和大师交流一样。
你现在是在linux下学习C语言,可以说比很多人的起点都高。非常纯净的C环境,编译器是最标准的GCC。当然我知道,已经给你很大的挑战,所以没要你学terminal下用vim写C,而不是用code::blocks,不过你愿意的话,也可以学,也不是很难,其实我已经悄悄的教过你一点terminal的东西了。很多东西都是我花了很多时间才知道的,比方linux,我几乎用了一个暑假来入门,看了《鸟哥的linux私房菜》,我才知道怎么使用linux。而你是直接用的,我也反思,一下子都告诉你,接受不了也正常,所以当我问的急切的事情,别生气。。。我只是想你早点秒掉C。
好吧。。。不扯淡了
man scanf,你想要的他都会告诉你
RETURN VALUE
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.
scanf的返回值是正确读入的数据变量的个数。如果没有正确读入一个数据,返回0,出错返回EOF。
Question is coming. BUG is coming.
[objc] view plaincopyprint?
#include "stdio.h"
int main()
{
int ret = 0;
int var1 = 0;
while(!(ret = scanf("%d",&var3)))
{
printf("scanf error!\nplease enter again!\n");
}
printf("returned value : %d\n",ret);
return 0;
}
简单到死的测试代码。GCC bug了!
我故意输入一个字符例如'a' 然而,程序死在whlie循环里面了。一直输入下面这个报错提示
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
please enter again!
scanf error!
我当时就呆了!自己写了这么就的类型检查,居然bug了。。。完全没有意识到啊,gdb调试,发现根本就没有重新scanf读入,每次到scanf直接跳过了。第一感觉以为是编译器优化掉了,之前keil有类似的经历,相当之坑爹。。。关闭优化,发现还是一样的bug。。。不淡定了,各种google 百度。得到结论,是编译器的问题。其实还有个问题,但是我这里没有VC了,所以不方便在VC上测试,就是这篇blog最初给出的scanf类型检查方法其实也有个问题。可能有点不好理解,不过我觉得有必要跟说了。因为你已经接触了scanf,scanf那点事还是早知道好。。。
首先貌似我要给你介绍缓冲区这个概念。。。
缓冲区叫buffer。我们的标准输入都是从键盘或者其他输入设备输入的,然后把输入信息储存在缓冲区。如果你不能很具体的想象缓冲区是什么。你就想成是个盒子。。。然后这个盒子里面会暂时的存放数据,注意是暂时的哦。不然也不会叫“缓冲”区。。。
我们把输入信息输入到缓冲区,只有刷新缓冲区的时候,标准输入储存在缓冲区的信息才会显示在屏幕上面。如果不知道刷新是什么。你就想,刷新就是那个盒子(缓冲区)里面的东西全部都倒出来给你看。
背景知识over
正题,scanf在读入的时候,scanf("%d",&number);这个时候你不仅仅输入了一个int 类型数据,你输入了数据,你发现没有,你还敲击了键盘上面的一个键!which one? Enter!回车键!发现没有,我们每次输入数据都要确认输入,而确认输入就是通过回车,对不?这个时候键盘就会输入一个额外的信息!回车符号'\n'
这个时候你的缓冲区就存在两个数据 number 和' \n'! 当下一次scanf("%d",&number)的时候,程序就不会等待你输入数据写到number的地址里面去了。他会直接读取缓冲区的第一个数据,因为之前的number已经被读取了,此时缓冲区就只剩下‘\n’于是,‘\n’被读入number的地址,scanf发生错误(应该读入整形数据),于是scanf返回 0!
[objc] view plaincopyprint?
while(!scanf("%d",&varible))