🔥博客主页: 小羊失眠啦
🔖系列专栏: C语言、Linux
🌥️每日语录:生活便是寻求新的知识。
❤️感谢大家点赞👍收藏⭐评论✍️
一、什么是const
常类型,使用类型修饰符const说明的类型,常类型的变量或者对象的值是不能被更新的。
const含义:只要一个变量前用const来修饰,就意味着该变量里的数据只能被访问,而不能被修改,也就是意味着“只读”(readonly)
二、const的优点
-
定义常量:
const int n=100;
-
类型检查:
const常量与#define宏定义常量区别:
-
const定义变量类型只有整数或者枚举,并且常量表达初始化才为常量表达式
-
预编译指令只是对值进行简单的替换,不能进行类型检查,相比之下,被const修饰的变量有自己的类型,编译器可以通过安全检查
-
其余情况下const常量只是一个被const限定的变量,不能与常量混肴
-
-
可以保护被修饰的东西,防止意外修改,增强程序的健壮性
-
可以避免不必要的内存分配,编译器通常不为被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修饰函数的参数也是分为三种情况
-
防止修改指针指向的内容
void StringCopy(char *strDestination, const char *strSource);
其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图通过解引用的方式改动 strSource 的内容,编译器将指出错误。
-
防止修改指针指向的地址
void swap ( int * const p1 , int * const p2 )
指针p1和指针p2指向的地址都不能修改。
五、修饰函数的返回值
如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
例如函数
const char * GetString(void)
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();