『C语言进阶』const详解-LMLPHP
🔥博客主页 小羊失眠啦
🔖系列专栏 C语言Linux
🌥️每日语录生活便是寻求新的知识。
❤️感谢大家点赞👍收藏⭐评论✍️


『C语言进阶』const详解-LMLPHP

一、什么是const

常类型,使用类型修饰符const说明的类型,常类型的变量或者对象的值是不能被更新的。

const含义:只要一个变量前用const来修饰,就意味着该变量里的数据只能被访问,而不能被修改,也就是意味着“只读”(readonly)


二、const的优点

  1. 定义常量:

    const int n=100;
    
  2. 类型检查:

    const常量与#define宏定义常量区别:

    • const定义变量类型只有整数或者枚举,并且常量表达初始化才为常量表达式

    • 预编译指令只是对进行简单的替换,不能进行类型检查,相比之下,被const修饰的变量有自己的类型,编译器可以通过安全检查

    • 其余情况下const常量只是一个被const限定的变量,不能与常量混肴

  3. 可以保护被修饰的东西,防止意外修改,增强程序的健壮性

  4. 可以避免不必要的内存分配,编译器通常不为被const修饰的变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。


三、const的用法:

3.1 修饰全局变量

此时全局变量只能使用不可修改,直接修改(编译报错)与修改地址(程序异常)都不行

#include <stdio.h>
//const修饰全局变量
//此时全局变量只能使用不可修改,直接修改(编译报错)与修改地址(程序异常)也不行
const int a = 100;
void test()
{
    printf("a = %d\n", a);//直接使用
    //a = 200;//直接修改,编译报错,显示a是只读的
    //printf("a = %d\n", a);
    //int *p = &a;
    //*p = 300;//通过地址修改,程序异常,有些编译器可能只会显示警告,并不会报错,且程序能正常运行,但是不会显示任何结果
    //printf("a = %d\n", a);
}
 
int main()
{
	test();
	return 0;
}

全局变量的作用域是整个文件,我们应该尽量避免使用全局变量,因为一旦有一个函数改变了全局变量的值,它也会影响到其他引用这个变量的函数,导致除了bug后很难发现,如果一定要用全局变量,我们应该尽量的使用const修饰符进行修饰,这样防止不必要的人为修改。

3.2 修饰局部变量

不可直接修改变量的值(编译报错),但是可以通过地址进行修改

const int n = 5;
int const n = 5;

这两种写法是一样的,都是表示变量n的值不能被改变了,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了。

#include<stdio.h>
//const修饰普通局部变量
//不可直接修改(编译报错),但是可以通过地址进行修改
void test()
{
    const int b = 100;
    printf("b = %d\n", b);
    //b = 200;//直接修改,编译报错
    //printf("b = %d\n", b);
    int *p = &b;
    *p = 300;//通过地址进行修改
    printf("b = %d\n", b);
}
int main()
{
	test();
    return 0;
}

接下来看看const用于修饰常量静态字符串,例如:

const char* str = "fdsafdsa";

如果没有const的修饰,我们可能会在后面有意无意的写str[4]=’x’类似这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了const,这个错误就能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译期被发现。

3.3 修饰指针变量的类型(即常量指针)

const修饰指针变量的类型,可直接修改变量值,不可修改指针指向的地址里的内容(编译报错),可以修改指针的指向

常量指针是指针指向的内容是常量,可以有以下两种定义方式:

const int * n;
int const * n;

可以发现,无论是在int前还是在int后,const一直位于*之前

#include<stdio.h>
void test()
{
    int c = 100;
    const int *p = &c;
    printf("c = %d\n",c);
    c = 111;//可以直接修改变量的值
    printf("c = %d\n",c);
    //*p = 200;//不可修改指针指向的地址里的内容,编译报错
    //printf("c = %d\n",c);
    int d =300;
    p = &d;//可以修改指针的指向
    printf("*p = %d\n",*p);
}
int main()
{
	test();
    return 0;
}

3.4 修饰指针变量(即指针常量)

可以直接修改变量的值,可以修改指针指向地址的内容,但是不能修改指针的指向(编译报错)

指针常量是指指针本身是个常量,不能在指向其他的地址,写法如下:

int *const n;
#include<stdio.h>
void test()
{
    int c = 200;
    int  * const p = &c;//const修饰指针,即指针常量
    printf("*p = %d\n",*p);
    c = 300;
    printf("c = %d\n",c);//直接修改值
    printf("*p = %d\n",*p);
    *p = 400;//修改指针指向地址里的内容
    printf("*p = %d\n",*p);
    int d =500;
    //p = &d;//不能修改指针的指向,编译报错
    //printf("*p = %d\n",*p);
}
int main()
{
	test();
	return 0 ;
}

区分常量指针和指针常量的关键就在于*的位置,以*为分界线,如果const在*的左边,则为常量指针,如果const在*的右边则为指针常量。

如果我们将*读作‘指针’,将const读作‘常量’的话,内容正好符合:

int const * n;
     常量+指针-->常量指针
int *const n;
   指针+常量  -->常量指针

3.5 指向常量的常指针

是以上两种的结合,指针指向的位置不能改变并且也不能通过这个指针改变变量的值,但是依然可以通过其他的普通指针改变变量的值

const int* const p;
#include<stdio.h>
void test()
{
    int c = 200;
    const int * const p = &c;//即修饰指针变量类型又修饰指针变量
    printf("*p = %d\n",*p);
    c = 300;//可以直接修改值
    printf("c = %d\n",c);
    printf("*p = %d\n",*p);
    //*p = 400;//不能修改指针指向地址里的内容,编译报错
    //printf("*p = %d\n",*p);
    //int d =500;
    //p = &d;//不能修改指针指向,编译报错
    //printf("*p = %d\n",*p);
}
int main()
{
	test();
	return 0;
}

四、修饰函数的参数

根据常量指针与指针常量,const修饰函数的参数也是分为三种情况

  1. 防止修改指针指向的内容

    void StringCopy(char *strDestination, const char *strSource);
    

    其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图通过解引用的方式改动 strSource 的内容,编译器将指出错误。

  2. 防止修改指针指向的地址

    void swap ( int * const p1 , int * const p2 )
    

    指针p1和指针p2指向的地址都不能修改。


五、修饰函数的返回值

如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
例如函数

const char * GetString(void)

如下语句将出现编译错误:

char *str = GetString();

正确的用法是

const char *str = GetString();

『C语言进阶』const详解-LMLPHP

10-18 13:49