容易被忽略的输入和输出

在C语言里,我们经常用scanf作为输入语句,用printf输出。那么关于输入和输出,你到底了解多少呢?

一、关于“&”

  首先我们来看一段程序:

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int num;  
  6.   
  7.     printf("Please input num = ");  
  8.   
  9.     scanf("%d",num);  
  10.   
  11.     printf("num = %d\n",num);  
  12.       
  13.     return 0;  
  14. }  

  运行程序,当我们输入 num = 5 时,输出为多少呢?输出结果如下:

[objc]  view plain  copy
  1. Please input num = 5  
  2. 段错误  

  我们可以看到,这个时候出现了“段错误”,那么什么是段错误呢?简单来说,段错误就是内存错误。

  在我们上述程序中,有一句“scanf("%d",num)”,问题便出在这里。

  我们举一个简单的例子,假如在一所学校里,有20个人叫张三,我到了这个学校,说我要找张三,那么我能准确地找到我想找的那个张三么?当然不能。为什么呢?因为这个学校里有20个人叫张三,我只说了我要找的人叫张三,那么我要找的到底是这20个人中的哪一个呢?所以如果我想找到张三,我需要说我要找某某年级某某班的张三,给一个准确的定位,这样我才可以准确地找到他。

  那么在这里是一样的,num只是一个名字,如果我说我要输入一个数给num,系统又怎么知道我要输给的num在哪呢?所以这个时候我们要把num的地址加上去,这样才可以找到num在内存空间的地址,即只有名字是不行的,还要有地址。所以以后用scanf
时千万不要忘记加“&”。


二、关于输入字符之前加一个getchar函数

  首先参考http://blog.youkuaiyun.com/newcong0123/article/details/51853458中提到过的问题,即在输入一个数字之后,略过了字符的输入,直接输入下一个数字的问题。下面我们来解释一下为什么会有这样的情况。

  简单来说,就是scanf有一个缓冲区,我们通过scanf输入的数据先存放到缓冲区,然后再依次输出。

  下面我们利用之前的程序分析一下:

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int num1;  
  6.     int num2;  
  7.   
  8.     char ch;  
  9.   
  10.     printf("Please input num1: ");  
  11.     scanf("%d",&num1);  
  12.   
  13.     printf("Please input ch: ");  
  14.     scanf("%c",&ch);  
  15.   
  16.     printf("Please input num2: ");  
  17.     scanf("%d",&num2);  
  18.   
  19.     printf("%d %c %d\n",num1,ch,num2);  
  20.   
  21.     return 0;  
  22. }  

  当我们输入 num1 = 2 之后,2被放到了缓冲区,敲回车,这时,'\n'也被放到了缓冲区内,在分配时,便把2分给了num1,而把'\n'分给了ch,ch已经被分配了值,所以再输入时便直接略过了ch而直接输num2的值。

  所以在获得一个数据后,再获得下一个数据而不让输入时,可以用getchar。


三、三种方法输入、输出数组a[3]

1. &a[i]

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int i;  
  6.   
  7.     int a[3];  
  8.   
  9.     for (i = 0; i < 3; i++)  
  10.     {  
  11.         printf("Please input a[%d] = ",i);  
  12.   
  13.         scanf("%d",&a[i]);  
  14.     }  
  15.   
  16.     for (i = 0; i < 3; i++)  
  17.     {  
  18.         printf("a[%d] = %d\n",i,a[i]);  
  19.     }  
  20.   
  21.     return 0;  
  22. }  

运行结果:

[objc]  view plain  copy
  1. Please input a[0] = 1  
  2. Please input a[1] = 2  
  3. Please input a[2] = 3  
  4. a[0] = 1  
  5. a[1] = 2  
  6. a[2] = 3  


2. a + i

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int i;  
  6.   
  7.     int a[3];  
  8.   
  9.     for (i = 0; i < 3; i++)  
  10.     {  
  11.         printf("Please input a[%d] = ",i);  
  12.   
  13.         scanf("%d",a + i);  
  14.     }  
  15.   
  16.     for (i = 0; i < 3; i++)  
  17.     {  
  18.         printf("a[%d] = %d\n",i,*(a + i));  
  19.     }  
  20.   
  21.     return 0;  
  22. }  

运行结果:

[objc]  view plain  copy
  1. Please input a[0] = 1  
  2. Please input a[1] = 2  
  3. Please input a[2] = 3  
  4. a[0] = 1  
  5. a[1] = 2  
  6. a[2] = 3  

  在这里需要注意的是,用a++是不可以的,见如下代码:

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int i;  
  6.   
  7.     int a[3];  
  8.   
  9.     for (i = 0; i < 3; i++)  
  10.     {  
  11.         printf("Please input a[%d] = ",i);  
  12.   
  13.         scanf("%d",a++);  
  14.     }  
  15.   
  16.     for (i = 0; i < 3; i++)  
  17.     {  
  18.         printf("a[%d] = %d\n",i,a[i]);  
  19.     }  
  20.   
  21.     return 0;  
  22. }  

运行结果如下:

[objc]  view plain  copy
  1. 在函数 ‘main’ 中:  
  2. 13: 错误:自增运算中的左值无效  

  因为在这里a是数组名,即数组首元素的地址,在这里是常量,所以不能自加。


3. p++

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int i;  
  6.   
  7.     int a[3];  
  8.   
  9.     intint *p = a;  // p = &a[0]; 把a里的地址给p  
  10.   
  11.     for (i = 0; i < 3; i++)  
  12.     {  
  13.         printf("Please input a[%d] = ",i);  
  14.   
  15.         scanf("%d",p++);  
  16.     }  
  17.   
  18.     p = a;  
  19.   
  20.     for (i = 0; i < 3; i++)  
  21.     {  
  22.         printf("a[%d] = %d\n",i,*(p + i));  
  23.     }  
  24.   
  25.     return 0;  
  26. }  

运行结果:

[objc]  view plain  copy
  1. Please input a[0] = 1  
  2. Please input a[1] = 2  
  3. Please input a[2] = 3  
  4. a[0] = 1  
  5. a[1] = 2  
  6. a[2] = 3  


四、三种方法输入、输出字符数组src[100]

1. scanf

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. #define MAX 10  
  4.   
  5. int main()  
  6. {  
  7.     char src[MAX];  
  8.   
  9.     printf("Please input string : ");  
  10.   
  11.     scanf("%s",src);  
  12.   
  13.     printf("The string is %s.\n",src);  
  14.   
  15.     return 0;  
  16. }  

如果输入hello,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello  
  2. The string is hello.  

如果输入hello world,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello world  
  2. The string is hello.  

如果输入helloworld,输出结果为:
[objc]  view plain  copy
  1. Please input string : helloworld  
  2. The string is helloworld.  
  3. 段错误  

如果输入hihihihihihihihihihi,输出结果为:
[objc]  view plain  copy
  1. Please input string : hihihihihihihihihihi  
  2. The string is hihihihihihihihihihi.  
  3. 段错误  

  从上面我们运行时输入不同的字符串,输出的结果也不同,我们可以看到:

  ①当我们输入的字符串有空格时,输出时只输出空格之前的字符串。
  ②当我们输入的字符串超出了所定义的字符数组的长度,会报错,即段错误,但不影响输出结果。即无法解决越界问题。

2. gets

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. #define MAX 10  
  4.   
  5. int main()  
  6. {  
  7.     char src[MAX];  
  8.   
  9.     printf("Please input string : ");  
  10.   
  11.     gets(src);  
  12.   
  13.     printf("The string is %s.\n",src);  
  14.   
  15.     return 0;  
  16. }  

如果输入hello,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello  
  2. The string is hello.  

如果输入helloworld,输出结果为:
[objc]  view plain  copy
  1. Please input string : helloworld  
  2. The string is helloworld.  

如果输入hello world,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello world  
  2. The string is hello world.  
  3. 段错误  

如果输入hihihihihihihihihihi,输出结果为:
[objc]  view plain  copy
  1. Please input string : hihihihihihihihihihi  
  2. The string is hihihihihihihihihihi.  
  3. 段错误  

  从上述结果我们可以看出:

  ①gets输入字符串不受空格影响,仍然可以输出空格后的字符串。
  ②当我们输入的字符串超出了长度,同样会报段错误,但仍然输出相应的字符串。同样无法解决越界问题。


3. getchar()

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. #define MAX 10  
  4.   
  5. int main()  
  6. {  
  7.     char ch;  
  8.   
  9.     char src[MAX];  
  10.   
  11.     int i = 0;  
  12.   
  13.     printf("Please input string : ");  
  14.       
  15.     while ((ch = getchar()) != '\n')  
  16.     {  
  17.         src[i] = ch;  
  18.   
  19.         i++;  
  20.     }  
  21.   
  22.     src[i] = '\0';  
  23.   
  24.     printf("The string is %s.\n",src);  
  25.   
  26.     return 0;  
  27. }  

如果输入hello world,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello world  
  2. The string is hello worl  
  3. .  

  可以看出:

  ①gerchar也不受空格影响。
  ②输入的字符串超出长度时,会把输出的字符串的长度控制在我们定义的范围内,即可以解决越界问题。
  ③需要一个字符一个字符获取,所以获取的运行效率低。

控制越界,越界即报错。代码如下:

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. #define MAX 10  
  4.   
  5. int main()  
  6. {  
  7.     char ch;  
  8.   
  9.     char src[MAX];  
  10.   
  11.     int i = 0;  
  12.   
  13.     printf("Please input string : ");  
  14.       
  15.     while ((ch = getchar()) != '\n')  
  16.     {  
  17.         src[i] = ch;  
  18.   
  19.         i++;  
  20.   
  21.         if (i == 9)  
  22.         {  
  23.             printf("Too long!\n");  
  24.             break;  
  25.         }  
  26.     }  
  27.   
  28.     src[i] = '\0';  
  29.   
  30.     printf("The string is %s.\n",src);  
  31.   
  32.     return 0;  
  33. }  

如果输入helloworld,输出结果为:
[objc]  view plain  copy
  1. Please input string : helloworld  
  2. Too long!  
  3. The string is helloworl.  

如果输入hihihihihihihihihihi,输出结果为:
[objc]  view plain  copy
  1. Please input string : hihihihihihihihihihi  
  2. Too long!  
  3. The string is hihihihih.  

如果输入hello world,输出结果为:
[objc]  view plain  copy
  1. Please input string : hello world  
  2. Too long!  
  3. The string is hello wor.  


五、关于printf

  如果你认为你对printf足够了解,那么看一下下面这段程序:

[objc]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     printf("Hello world!");  
  6.   
  7.     while (1) ;  
  8.   
  9.     return 0;  
  10. }  

  运行之后的结果是什么呢?是“Hello world!”么?当然不是。当我们运行了之后,会发现什么都不打印,并且陷入死循环。可能有人要问了,为什么不打印“Hello world!”呢?这便是我要给大家介绍的printf的一个特点。

  printf是一个行缓冲函数,并且printf与scanf使用同一个缓冲区。先写到缓冲区,当满足一定的条件之后,才会将缓冲区的内容输出。而这里需要满足的一定条件如下:
  ①缓冲区满
  ②写入的字符里有'\n'
  ③手动刷新缓冲区
  ④调用scanf,需要从缓冲区读取数据
  ⑤程序退出

  针对④,printf与scanf使用同一个缓冲区,当使用scanf时,会吧printf在缓冲区的数据清出来,于是可以输出。针对⑤,在程序退出时,会把缓冲区打扫干净,同样会清缓冲区,在清缓冲区的过程中会输出。

  所以希望我们大家在使用printf时,养成加'\n'的好习惯,这样才不会出现一些本不应该出现的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值