之所以引出这个问题,是因为最近在看C语言运行时各种变量的内存分区情况,不太明确const 修饰的变量和字符串常量/数字常量等这些量是否存储在一起。
只读变量:const修饰的变量,准确来说是只读变量,其实际上是可读可写的,只不过写的实现需要借助于指针,存储在栈区域,如果是在函数内部定义的。
常量:“hello”这种的才是真正的常量,存储在静态内存中的常量存储区,由系统进行管理。
#include <stdio.h>
#include <string.h>
int main(void)
{
int n = 2;
int* pn = &n;
printf("int n address is %d\n", pn);
printf("\n");
const int i = 3;
//i是只读变量,但仍然是一个变量,存储在堆栈这种动态存储区,由编译器负责
int* p = &i;//i毕竟是一个变量,初始化后不能通过直接赋值来改变i的值,因为前面加了
//const,C语言语法上不允许再对其进行直接赋值。通过指针可以改变其值,const就是一个限定修
//饰符,不改变i仍然是一个变量的性质。
*p = 200;//通过指针修改const int i的数值
printf("const int i aggress is %d\n", p);
printf("const int i is %d\n", i);
printf("\n");
char* c = "helloworld";//这才是真正的常量,是由系统管理的,编译器管不到。
printf(" helloworld address is %d\n", c);
return 0;
}
输出结果:
int n address is 15988844
const int i aggress is 15988856 //可以看到const int i和int n是存储在一块区域中的,栈区域。
const int i is 200 //通过指针修改了const int i的数值
helloworld address is 8215608//字符串常量存储在另一个区域,也就是静态存储区中的常量存储区。由系统负责。
详情参考https://blog.csdn.net/csdn_lsd/article/details/78419203
看完上面这些,基本已经可以说服自己,原来const修饰的变!量!也是可以修改的,下面再看这句话:
const是语言特性,不能通过const修饰的名称去修改对应的内容,但是并不是不能修改。因为编译器实现的时候,并没有规定要放到只读区。举个例子:
int a = 5;
const int* b = &a;
此时不能通过b修改地址&a中的值,但是依旧可以把a重新赋值。地址&a中存放的值就改变了。
可能你会疑惑,常量指针,指针常量,一会能用指针修改const限定的值,已经晕头转向了。其实,也不用过分纠结,为什么一会指针能修改,一会又不能修改了,你可以理解为这就是C语言的语法,之所以看起来有些复杂,是因为要多定一些规则满足各种各样的需求。
//================const修饰的量仍然还是变量,不能用于定义数组=========
在定义数组时,必须明确指明数组大小,或者通过对数组元素进行初始化的方式让编译器获取数组大小,如int a[5]; char a[]={'a','b','c'},不能使用变量作为数组的大小。下面这个例子就可以说明const修饰的量,虽然我们习惯上称之为是常量,但实际上其只是只读变量,是可读可写的,写通过指针进行,之所以是这样,这就是const对变量的限制作用,记住即可。
下面看例子,说明const修饰的量仍然是一个变量而非常量,其不能用来定义数组大小。const修饰的量是只读变量,仍然是存储在动态存储区的栈中。
#include<stdio.h>
#include<string.h>
//#define MAX 3
int main(int argc,char* agrv[])
{
const int max = 3;
int a[max] = { 1, 2, 3 };
这里提示错误:数组大小应为常量值,不能定义大小为0的数组。
这个错误说明max并不是一个常量,那么max是什么?使用const修饰的只读变量,什么样的才是常量:
int a[3]={1,2,3};//数字3才是真正的常量,其是不可更改的,放在系统存储区中,编译器是无权管理的。
return 0;
}
改成下面的代码,用预定义define的方式可以引入一个真正的常量,下面的代码就是正确的。
#include<stdio.h>
#include<string.h>
#define MAX 3
int main(int argc,char* agrv[])
{
int a[MAX] = { 1, 2, 3 };//MAX表示的3这个数字,才是真正意义上的常量
return 0;
}
再次明确:const修饰的量实际上不是真正意义上的常量,是一个只读变量,存储在栈中,可以通过地址修改数值。数组大小的定义,一定要用常量,这个常量是真正意义上的常量,就是不可改变的数字,或者不知名大小,对元素进行初始化来定义数组。