普通const只读变量
编译器不为普通的const只读变量分配存储空间,而是将它们保存在符号表中。不像#define一样在预编译过程中给出立即数,在预编译阶段进行替换,const修饰的只读变量在编译的时候确定其值。
const int a = 10; //一般变量
const int arr[5] = {1,2,3,4,5}
修饰指针
例子
const int *p; //p可变,p指向的对象不可变
int const *p; //p可变,p指向的对象不可变
int *const p; //p不可变,p指向的对象可变
const int *const p; //指针p和指针p指向的对象都不可变
记忆方法
先忽略类型名(编译器解析的时候也先忽略类型名),看const离哪个近,离谁近就修饰谁,修饰谁谁就不可变
- const
int*p;
const 修饰 *p,p是指针,*p是指针指向的对象,不可变 intconst *p;
const 修饰 *p,p是指针,*p是指针指向的对象,不可变int*const p;
const修改p,p 是指针,p不可变,p指向的对象可变- const
int* const p
前一个const修饰*p,后一个const修饰p,都不可变
修饰函数的参数
const修饰符也可以修饰函数的参数,当不希望这个参数值在函数体内被意外修改时使用。
void Fun(const int *p);
告诉编译器,*p在函数体中不能改变,从而防止了使用者的一些无意的错误修改。
在C语言中,有很多库函数的形参被定义为const *类型
size_t strlen ( const char * str );
int strcmp ( const char * str1, const char * str2 );
char * strcat ( char * destination, const char * source );
char * strcpy ( char * destination, const char * source );
int printf ( const char * format, ... );
自定义的函数const限制
加const限制符表明,调用该函数不会修改传进来的对象的值。不但可以防止由于程序员误操作引起的字符串修改,还可以给用户一个提示,函数不会修改你提供的字符串。
#include <stdio.h>
//查找字符串中某个相同的字符
void my_fun(const char *str, char ch, int *num)
{
int ch_sum = 0;
while (*str != '\0')
{
if (*str++ == ch)
{
ch_sum ++;
}
}
*num = ch_sum;
}
int main()
{
const char *str = "adbacccsdddde";
char ch = 'd';
int n = 0;
my_fun(str, ch, &n);
printf("character d num is = %d\n", n);
return 0;
}
修饰函数的返回值
const修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
const int Fun(void);
const和非const的转换
在编写函数的过程中,经常会遇到编译器的warning,提示某个函数的入参是一个const char*类型,但是传入的指针却没带const。此时怎么办呢?
警告给出的场景
const char *str1 = "this is const string and can not be modified" //str1为指向字符串常量的指针
void my_fun(char *str2);
void my_fun(char *str2)
{
... //处理str_data指向的字符串,此时,
... //str_data指向的字符串可被修改,因为函数入参没有带const限制
}
int main()
{
my_fun(str1);
}
- 在上述情况下,编译器会发出警告,因为通过str不能修改数据,而赋值后通过str2能够修改数据了,意义发生了转变,所以编译不提倡这种行为,会给出错误或警告。在VS2017下给出的警告如下:
void my_fun(char *str, char ch, int *num);
int main()
{
const char *str = "adbacccsdddde";
char ch = 'd';
int n = 0;
my_fun(str, ch, &n);
printf("character d num is = %d\n", n);
return 0;
}
warning C4090: “函数”: 不同的“const”限定符
const和非const char* 指向数据的降级与升级
- 不能将const char *类型的数据赋给char *类型的变量。
- 编译器允许将char 类型的数据赋值给const char类型的变量。 例子:
void my_fun(const char *str, char ch, int *num)
{
...
}
int main()
{
char *str = "adbacccsdddde"; //这里将之前的const 关键字去掉后,编译器未warning,程序正常运行
char ch = 'd';
int n = 0;
my_fun(str, ch, &n);
printf("character d num is = %d\n", n);
return 0;
}
如何理解
- char * 指向的数据有 “读”/==“写”==权限
- const char*指向的数据只有 “读” 权限
- 降低数据的权限不会带来风险,反之提升则有可能发生危险
const 和 数值宏常量
为了安全,建议在定义一些宏常数的时候用const代替,编译器会给const修饰的只读变量做类型校验,减少错误的可能。但一定要注意,const修饰的不是常量而是readonly的变量,const修饰的只读变量不能用来做为定义数组的维数,也不能放在case关键字后面。
#define MAX_NUM 100
int data[MAX_NUM] = {0}; //可以编译
const int Max_Num = 100;
int data[Max_Num] ={0} //错误,因为const定义的只读变量不能定义数组的维数