• 情景分析“C语言的const关键字”


    C语言中的const一直是C语言初学者心中的痛,这是因为const在不同位置有不同作用,在不同情景有不同角色。这让初学者摸不清头脑。今天,和大家一起研究一下const,让它的每个角色都“深入人心”!

    ==============================================================================================

    情景一:最简单的const用法

    #include<stdio.h>
    int main()
    {
    int const a;
    a=5;
    printf("a=%d\n",a);
    return 0;
    }

    如果编译这个c文件,就会报错:

    1071.c: In function ‘main’:
    1071.c:5: error: assignment of read-only variable ‘a’

    显而易见,这是const在搞鬼,因为声明了const的变量是不能修改的!

    如果将源代码修改为如下这样,就没有问题了!

    #include<stdio.h>
    int main()
    {
    int const a=5;
    printf("a=%d\n",a);
    return 0;
    }

    总结:const声明的变量必须要进行初始化赋值,如果错过这个机会,以后再想给const的变量赋值,可就没门了!切记~

    PS:int const和const int是一回事,“颠倒写”都是可以的。以后遇到了别犯晕,呵呵。但是,还是要留个心眼,当const和指针搀和到一起时,这个“颠倒写”的规律可未必成立。

    ==============================================================================================

    情景二:发明const为了什么?

    在const诞生之前,开发者一直使用#define VAR 100来定义一些有特殊用途的类常量,不过这样定义是存在一些劣势的。因此const应运而生,之后开发者可以使用const int VAR=100;来定义类常量了。

    至于为什么#define有其劣势,还要读者自己去google下。:)

    ==============================================================================================

    情景三:const和指针的配合是噩梦!

    你能分辨得清这些声明么:

    const int *A;
    int const *A;
    int *const A;
    const int *const A;

    如果有点犯晕的话,那就先给出它们的讲解,然后继续看后面的情景分析吧。

    const int *A; //修饰指向的对象,A可变,A指向的对象不可变
    int const *A;   //修饰指向的对象,A可变,A指向的对象不可变
    int *const A;   //修饰指针A, A不可变,A指向的对象可变
    const int *const A; //指针A和A指向的对象都不可变

    ==============================================================================================

    情景四:const int *A

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    const int *A=&num;
    printf("result=%d\n",*A);
    return 0;
    }

    编译执行结果为:

    [rocrocket@wupengchong const_test]$ cc test1.c
    [rocrocket@wupengchong const_test]$ ./a.out
    result=12

    接下来,我们动动手脚,在代码中加入了(*A)++;这条语句:

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    const int *A=&num;
    (*A)++;
    printf("result=%d\n",*A);
    return 0;
    }

    编译这个c文件:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    test1.c: In function ‘main’:
    test1.c:6: error: increment of read-only location ‘*A’
    可以看到,报错了,报错的内容表示”*A”是只读的,不能修改。

    我们再修改一下源代码为下面这样:

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int tmp=100;
    const int *A=&num;
    A=&tmp;
    printf("result=%d\n",*A);
    return 0;
    }

    编译执行结果为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    [rocrocket@wupengchong const_test]$ ./a.out
    result=100

    好了,如果你仔细看了这几个小得不能再小的程序,你自己都可以给出结论了!

    结论:如果声明了const int *A,那么A值是可以修改的,而*A是不可以修改的。更通俗的说,A指针可以随便指向一个整型,但只要被A盯上了的整型变量在使用*A引用时就不能修改了。

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int tmp=100;
    const int *A=&num;
    A=&tmp;
    tmp=3;
    printf("result=%d\n",*A);
    return 0;
    }

    编译执行的结果为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    [rocrocket@wupengchong const_test]$ ./a.out
    result=3

    结论2:即使A指向了tmp,我虽然不能修改*A,但是我仍然是可以用tmp来修改这个值的,完全不管*A的存在。呵呵

    ==============================================================================================

    情景五:int *const A

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int *const A=&num;
    printf("result=%d\n",*A);
    return 0;
    }

    编译执行结果为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    [rocrocket@wupengchong const_test]$ ./a.out
    result=12

    我们稍微修改下源代码:

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int tmp=100;
    int *const A=&num;
    A=&tmp;
    printf("result=%d\n",*A);
    return 0;
    }

    编译时报错了:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    test1.c: In function ‘main’:
    test1.c:7: error: assignment of read-only variable ‘A’
    [rocrocket@wupengchong const_test]$ cat test1.c

    可见A本身的值已经不能再变了。

    继续修改源代码如下:

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int *const A=&num;
    (*A)=100;
    printf("result=%d\n",*A);
    return 0;
    }

    编译执行结果为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    [rocrocket@wupengchong const_test]$ ./a.out
    result=100

    可以看出,(*A)是可以改变的。

    结论又可以轻易推出了:int *const A;   //const修饰指针A, A不可变,A指向的对象可变

    ==============================================================================================

    情景六:const int *const A; //指针A和A指向的对象都不可变

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int const *const A=&num;
    (*A)=100;
    printf("result=%d\n",*A);
    return 0;
    }

    编译会报错:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    test1.c: In function ‘main’:
    test1.c:6: error: assignment of read-only location ‘*A’

    改下源代码:

    [rocrocket@wupengchong const_test]$ cat test1.c

    #include<stdio.h>
    int main()
    {
    int num=12;
    int tmp=100;
    int const *const A=&num;
    A=&tmp;
    printf("result=%d\n",*A);
    return 0;
    }

    编译仍然会报错:

    [rocrocket@wupengchong const_test]$ !cc
    cc test1.c
    test1.c: In function ‘main’:
    test1.c:7: error: assignment of read-only variable ‘A’

    呵呵,结论很明显了,const int *const A; //指针A和A指向的对象都不可变

    当然const int *const A;和int const *const A=&num;是等价的!

    情景七:如果const用在函数形参里呢?是不是又要复杂很多?

    答案是NO!一点也不复杂。

    来看看这个函数投:int addnum(const int num, int a, int b);

    这个函数声明中的第一个形参是const int num,这就表明如果我调用了这个函数,那么第一个实参被传到addnum函数里之后,就不能再做修改了!呵呵 就这么简单。

    给个例子吧,让大家能更一目了然:

    [rocrocket@wupengchong const_test]$ cat test2.c

    #include<stdio.h>
    int addto(const int num, int a, int b)
    {
    if(num==1){
    return a+b;
    }else{
    return 0;
    }
    }
     
    int main(){
    int num=100;
    int a=12,b=22;
    int res;
    num=1;
    res=addto(num,a,b);
    printf("res=%d\n",res);
    return 0;
    }

    编译执行结果为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test2.c
    [rocrocket@wupengchong const_test]$ ./a.out
    res=34

    如果我修改一下,编译就会出错:

    [rocrocket@wupengchong const_test]$ cat test2.c

    #include<stdio.h>
    int addto(const int num, int a, int b)
    {
    if(num==1){
    num=3;
    return a+b;
    }else{
    return 0;
    }
    }
     
    int main(){
    int num=100;
    int a=12,b=22;
    int res;
    num=1;
    res=addto(num,a,b);
    printf("res=%d\n",res);
    return 0;
    }

    编译报错为:

    [rocrocket@wupengchong const_test]$ !cc
    cc test2.c
    test2.c: In function ‘addto’:
    test2.c:5: error: assignment of read-only location ‘num’

    可见在函数里形参被声明为const的变量也是不能修改的哦!呵呵~

    const其实不难,把本文的几个小例子看懂就OK了!

    除了传递要求为const的参数以外,自己声明对象没有什么必须要加,但是对于一个逻辑上不应该被修改,应该为常量的对象,没有声明为const,就必须由程序员自己来维护,来记住这个变量不应该被修改,即使你不小心修改导致程序整体混乱了,编译器也不会报错
    另,const和普通变量的声明存在于头文件时有区别,总之这些都是与你具体写程序的规划有关系,const这个玩意只是方便程序设计和程序编写,能够使程序更加的清晰,如果说我就是不爱用,就是喜欢一路变量用到底,那也没什么不行

  • 相关阅读:
    美国和日本不是盟友吗,为什么拒绝出售F-22战斗机给日本?
    刚刚大学毕业,是选择创业还是选择公司上班?
    现今的社会一定要结婚吗?
    事必躬亲果真是无能的表现?
    课外辅导机构,就让疫情灭了吧!
    这些年,我读书越来越少了!
    Python操作日志、加密、发送邮件、线程、生产者消费者
    Python模块操作之re、MySQL、Excel
    Python面向对象、迭代器、range和切片的区分
    Python模块、文件读写、异常
  • 原文地址:https://www.cnblogs.com/jqyp/p/2382531.html
Copyright © 2020-2023  润新知