【Linux C】容易被忽略的输入和输出

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

一、关于“&”

  首先我们来看一段程序:

#include <stdio.h>

int main()
{
    int num;

    printf("Please input num = ");

    scanf("%d",num);

    printf("num = %d\n",num);
    
    return 0;
}

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

Please input num = 5
段错误

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

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

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

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


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

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

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

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

#include <stdio.h>

int main()
{
    int num1;
    int num2;

    char ch;

    printf("Please input num1: ");
    scanf("%d",&num1);

    printf("Please input ch: ");
    scanf("%c",&ch);

    printf("Please input num2: ");
    scanf("%d",&num2);

    printf("%d %c %d\n",num1,ch,num2);

    return 0;
}

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

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


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

1. &a[i]

#include <stdio.h>

int main()
{
    int i;

    int a[3];

    for (i = 0; i < 3; i++)
    {
        printf("Please input a[%d] = ",i);

        scanf("%d",&a[i]);
    }

    for (i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n",i,a[i]);
    }

    return 0;
}

运行结果:

Please input a[0] = 1
Please input a[1] = 2
Please input a[2] = 3
a[0] = 1
a[1] = 2
a[2] = 3


2. a + i

#include <stdio.h>

int main()
{
    int i;

    int a[3];

    for (i = 0; i < 3; i++)
    {
        printf("Please input a[%d] = ",i);

        scanf("%d",a + i);
    }

    for (i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n",i,*(a + i));
    }

    return 0;
}

运行结果:

Please input a[0] = 1
Please input a[1] = 2
Please input a[2] = 3
a[0] = 1
a[1] = 2
a[2] = 3

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

#include <stdio.h>

int main()
{
    int i;

    int a[3];

    for (i = 0; i < 3; i++)
    {
        printf("Please input a[%d] = ",i);

        scanf("%d",a++);
    }

    for (i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n",i,a[i]);
    }

    return 0;
}

运行结果如下:

在函数 ‘main’ 中:
13: 错误:自增运算中的左值无效

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


3. p++

#include <stdio.h>

int main()
{
    int i;

    int a[3];

    int *p = a;  // p = &a[0]; 把a里的地址给p

    for (i = 0; i < 3; i++)
    {
        printf("Please input a[%d] = ",i);

        scanf("%d",p++);
    }

    p = a;

    for (i = 0; i < 3; i++)
    {
        printf("a[%d] = %d\n",i,*(p + i));
    }

    return 0;
}

运行结果:

Please input a[0] = 1
Please input a[1] = 2
Please input a[2] = 3
a[0] = 1
a[1] = 2
a[2] = 3


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

1. scanf

#include <stdio.h>

#define MAX 10

int main()
{
    char src[MAX];

    printf("Please input string : ");

    scanf("%s",src);

    printf("The string is %s.\n",src);

    return 0;
}

如果输入hello,输出结果为:
Please input string : hello
The string is hello.

如果输入hello world,输出结果为:
Please input string : hello world
The string is hello.

如果输入helloworld,输出结果为:
Please input string : helloworld
The string is helloworld.
段错误

如果输入hihihihihihihihihihi,输出结果为:
Please input string : hihihihihihihihihihi
The string is hihihihihihihihihihi.
段错误

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

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

2. gets

#include <stdio.h>

#define MAX 10

int main()
{
    char src[MAX];

    printf("Please input string : ");

    gets(src);

    printf("The string is %s.\n",src);

    return 0;
}

如果输入hello,输出结果为:
Please input string : hello
The string is hello.

如果输入helloworld,输出结果为:
Please input string : helloworld
The string is helloworld.

如果输入hello world,输出结果为:
Please input string : hello world
The string is hello world.
段错误

如果输入hihihihihihihihihihi,输出结果为:
Please input string : hihihihihihihihihihi
The string is hihihihihihihihihihi.
段错误

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

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


3. getchar()

#include <stdio.h>

#define MAX 10

int main()
{
    char ch;

    char src[MAX];

    int i = 0;

    printf("Please input string : ");
    
    while ((ch = getchar()) != '\n')
    {
        src[i] = ch;

        i++;
    }

    src[i] = '\0';

    printf("The string is %s.\n",src);

    return 0;
}

如果输入hello world,输出结果为:
Please input string : hello world
The string is hello worl
.

  可以看出:

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

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

#include <stdio.h>

#define MAX 10

int main()
{
    char ch;

    char src[MAX];

    int i = 0;

    printf("Please input string : ");
    
    while ((ch = getchar()) != '\n')
    {
        src[i] = ch;

        i++;

        if (i == 9)
        {
            printf("Too long!\n");
            break;
        }
    }

    src[i] = '\0';

    printf("The string is %s.\n",src);

    return 0;
}

如果输入helloworld,输出结果为:
Please input string : helloworld
Too long!
The string is helloworl.

如果输入hihihihihihihihihihi,输出结果为:
Please input string : hihihihihihihihihihi
Too long!
The string is hihihihih.

如果输入hello world,输出结果为:
Please input string : hello world
Too long!
The string is hello wor.


五、关于printf

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

#include <stdio.h>

int main()
{
    printf("Hello world!");

    while (1) ;

    return 0;
}

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

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

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

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


  
  以上为博主的学习笔记,如有错误,望大家指出,O(∩_∩)O谢谢观看。



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值