“输入输出函数对比及总结”和 const

一、输入输出函数对比及总结

1、输入函数有哪些
     1>  scanf函数
     2>  gets函数
     3>  fgets函数
  
     1>scanf函数特点
                 优点:可以格式化输入
                 缺点:不能接收空格
    
     2>  gets函数特点
                 优点:可以接收空格
                 缺点:会有一个警告,是不安全的,有安全隐患
                           不安全表现在,比如一个数组长度为50,如果我们输入的长度正好是50个,此时会把50个字符全部存到数组中,这样就没有空间存储字符结束符‘\0’

     3>  fgets函数
                   优点:是一个安全的字符串接收函数
         
           fgets函数是一个文件操作相关的函数,暂时使用这个函数可以从键盘上接收一个字符串,保存到数组中

       小结:在之前的blog中已经对其余2中输入函数进行过介绍,今天主要介绍fgets函数

2、fgets函数的使用
     
      fgets函数的原型是
                   char *fgets(char *s,int n,FILE *fp)
      参数数量比较多,有3个。而fgets相比于gets有一个显著的差别就是fgets会将行末的换行符算到读入的字符串里面。所以相同且正常(输入无错误,缓冲区够大)的情况下,fgets读入的字符串会比gets在末尾‘\0’前面多一行符;行长度超出缓冲区大小时只读入前n-1个字符。

3、fgets函数的一些特性
     下面我们通过例子来展现这些特性

     1>当输入的字符串长度小于数组存储长度时:
程序如下:

打印输出如下:


       从打印图可以看到,asd后面空了一行,这是为什么?

为了解决这个疑问,我们打印输出字符数组中存储的内容的ascii值看看

程序代码如下:

输出打印如下:

a、s、d的ascii值分别是97、115、100.那么怎么会有10和0那这是什么,查ascii值发现10代表'\n'也就是回车,0代表'\0'这下我们终于找到了为什么输出后面会有一空行,原来是把空缺的数组位置存放回车所以假设我们输入2个字符看看数组中会存储几个ascii的值为10?输出回空几行?
程序如下:

打印输出如下:


        总结:
                用fgets函数作为输入的时候,当输入的字符个数少于数组长度的时候,数组中除了存储输入字符还会存储一个‘\n’字符,最后存储'\0'字符。

       2>当输入的字符串长度等于数组存储长度时:
程序代码如下:

打印输出如下:

小结:
        当输入字符长度正好等于数组长度的时候,会发展数组中存储输入的字符和字符'\0'

       3>当输入的字符串长度大于数组存储长度时:

程序如下:

打印输出如下:

小结:
        当我们输入的字符串长度大于数组长度的时候,数组中只会存储数组长度-1个内容,而其它多余的输入字符将不会被输入。这就保证了安全

4.如果想取消输出换行,可以通过以下方式:
程序如下:

打印输出如下:

总结:
         从上面打印的图来看是没有了输出换行的现象

5.输出函数有哪些
     
      1>printf函数
      2>puts函数
      3>fputs函数

1>printf函数的特点
            优点:可以格式化输出
            缺点:不安全

2>puts函数
            优点:输出可以自动换行
            缺点:不安全

3>fputs函数
            优点:可以自动截取输入的字符串,使得我们对字符串的存取是安全的
            特点:既不能输出自动换行又不可以格式化输出

下面通过例子来对比一下:

下面是用scanf函数输入、printf函数输出的例子,我们输入字符串长度大于数组长度时:

程序如下:

打印输出如下:

总结:
         从打印可以看出,无论我们输入的字符串的长度是否已经超出数组长度,都快打印出我们输入的字符串,这表明我们输入的字符串已经占用了别的存储空间,发生了越界行为,这是不安全的。

下面用gets函数为输入、puts函数为输出的情况,当输入字符串长度大于数组长度时:
程序如下:

打印输出如下:

总结:
         从这个打印输出可以知道,同样输入字符串的长度是多长就可以输出多长,这也占用了别的存储空间,会发生越界,是有危险的;另一点证明了puts函数是可以自动换行的。

下面我们讨论一下fgets函数、和fputs函数这两个函数哪一个函数决定安全性?
程序如下:

打印输出如下:

总结:
         从程序我们可以看出程序中是用的scanf函数输入、fputs函数输出,但是当我们输入的字符串长度大于我们输出的长度时依然可以输出,这可以说明真正决定安全性的是函数fgets函数,下面我们验证一下

程序如下:

打印输出如下:

总结:
         从上图打印可以验证我们上面的推测,fgets函数才是真正的决定输入输出安全性的函数


二、const关键字介绍及作用

1、什么是const
       const是一个类型修饰符,使用const修饰变量则可以让变量的值不能改变
常量类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的

2、const有什么主要的作用
     1>可以定义const常量,具有不可变形
     2>便于进行类型检查,是编译器对处理内容有更多了解,消除了一些隐患。
     3>可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变!如果想要修改const定义过的内容,只需要:const  int  max=you want;即可
     4>可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。还是上面的例子,如果在函数体内修改了i,编译器就会报错
     5>可以节省空间,避免不必要的内存分配。例如
#define   PI   3.14159       //宏定义
const   doulbe  Pi=3.14159  //此时并未将Pi放入rom中
double  i=Pi;    //此时为Pi分配内存,以后不再分配
double  I=PI; //编译期间进行宏替换,分配内存
double  j=Pi;    //没有内存分配
double  J=PI;   //再进行宏替换,又一次分配内存
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝
     6>提高了效率。编译器通常部位普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高

3、如何使用const
    
    1>修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。
     比如:
              int  const   x=2;
        或
             const  int    x=2;
    
    2>修饰常数组(值不能够改变了)定义或说明一个常数组可采用如下格式:
     比如:
              int const  a[5]={1,2,3,4,5};
         或
              const  int  a[5]={1,2,3,4,5};

    3>修饰函数的常参数  const修饰符也可以修饰函数的传递参数,格式如下:
         void  fun(const  int  var);
                 告诉编译器var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改
   
    4>修饰函数的返回值:const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下:
        const   int   fun1();
        const   Myclass  fun2();

    5>修饰常指针
        const   int  *a;
        const 修饰指针, a可变,a指向的值不能被修改

        int   const   *a
        const 修饰指针, a可变,a指向的值不能被修改

下面我们通过实例来看看const的影响
程序如下:

打印输出如下:

说明:
         这是打印了我们定义的两个变量的值;下面我们来改变一下变量的值看看

打印如下:

总结:
         从这个打印图来看可以知道,用const定义过的变量的值是不可以修改的
程序如下:

打印如下:

总结:
         从打印图可以知道,当我们用指针来指向const类型定义的变量时,通过指针可以改变const类型定义的变量的值。值得注意的是,在xcode中是不能实现通过指针可以改变const类型定义的变量的值。这也许是编译器不同造成的差异

下面看看让指针p指向变量b是否可以成功
程序如下:

打印如下:

总结:
         从上图打印我们可以知道,指针p是可以随便指向任何一个变量

下面我们看看由const定义的指针p的情况

打印如下:

总结:
         从打印图可以知道,const类型指针指定指向地址后是不可以再改变地址,但是可以改变指向变量的值


打印如下:

总结:
         从上图可以知道:用const  int  *const  p=&b  定义的指针,既不能改变值也不能改变指针的指向


总结:
         关于const和指针变量的总结
         看const  和   *的位置:

         如果   const  在  *   的左侧      表示指针变量指向的变量的值不能变,但是指向可以改变
       
         如果   const  在  *   的右侧      表示指针变量指向的变量的值可以改变,但是指向不可以改变

         如果   const  出现在  *   的两侧,   表示指针变量的指向和值都不能改变
        










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值