1:在内存中的实际形式
字符常量 实际上是一个整型数,
而字符串常量 实质上的类型是 :const char 类型的数组(属于C风格的字符串)
2:定义的方式
旧式的定义方法:宏定义,#define (符号常量名)(常量)
推荐的定义方式:Const
两者的区别:
Define:除了字符串常量以外,其它的字面值常量都不占用内存空间
一、常量:(不可以定义结构型常量)
常量包括字面常量,符号常量,契约型常量,枚举常量这几种类型。
二、字面常量包括:整形常量,字符型常量,字符串常量。注意:不存在数组常量,结构体常量等结构型的字面常量。但是存在结构型的符号常量
三、符号常量:(可以定义结构型常量)
用#define和const定义的常量!
这两种常量之间的区别:
1、#define定义的常量,除了字符串字面常量外都不占内存,所以无法取常量的地址,仅仅是宏替换而已
eg:
#define NAME “pang dong” //本质是字符串字面常量,会占用“静态存储区”
#define MAX 256 // 本质是整形的字面常量,不会分配内存
2、 const定义的常量要分情况考虑:
你可以去一个const符号常量的地址:
对于基本数据类型的const常量,编译器会重新在内存中创建一个他的一个拷贝,(真正的基本数据类型的const常量会被编译器放到符号表中而不分配内存空间)你通过其地址访问到的就是这个拷贝而不是原始的符号常量;
而对于构造类型的const常量,实际上他是编译时不允许修改的常量,是占内存空间的,因此如果你能绕过编译器的静态类型安全检查机制,就可以在运行时修改其内存单元。从理论上讲,只要握有一个对象(针对C++中的结构类型常量)的指针,你就可以设法绕过编译器修改它的内存。
3:字符串常量的深入理解
在C语言中
字符串常量保存在字符数组或字符指针中
在C++ 中,字符串常量 还 可以保存在String 对象中
三者的区别:
(1) 保存在数组中:实质为 复制
(2) 字符指针:实质为 将一指针指向一个 Const char* 类型的内存
(3) String对象:实质也是 复制,但String 对象提供了对字符串更强的操作
????
String str = “hello world!”; 赋值以后,“hello world” 这一字符串常量是否还占用内存,它的生命周期到啥时结束??
解答:
"abc"是常量吗?答案是有时是,有时不是。
不是常量的情况:"abc"作为字符数组初始值的时候就不是,如
char str[] = "abc";
因为定义的是一个字符数组,所以就相当于定义了一些空间来存放"abc",而又因为
字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为
char str[3] = {'a','b','c'};
又根据上面的总结1,所以char str[] = "abc";的最终结果是
char str[4] = {'a','b','c','/0'};
做一下扩展,如果char str[] = "abc";是在函数内部写的话,那么这里
的"abc/0"因为不是常量,所以应该被放在栈上。
是常量的情况: 把"abc"赋给一个字符指针变量时,如
char* ptr = "abc";
因为定义的是一个普通指针,并没有定义空间来存放"abc",所以编译器得帮我们
找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器
最合适的选择。所以尽管ptr的类型不是const char*,并且ptr[0] = 'x';也能编译
通过,但是执行ptr[0] = 'x';就会发生运行时异常,因为这个语句试图去修改程序
常量区中的东西。
记得哪本书中曾经说过char* ptr = "abc";这种写法原来在c++标准中是不允许的,
但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许,
但是建议的写法应该是const char* ptr = "abc";这样如果后面写ptr[0] = 'x'的
话编译器就不会让它编译通过,也就避免了上面说的运行时异常。
又扩展一下,如果char* ptr = "abc";写在函数体内,那么虽然这里的"abc/0"被
放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的,
只不过是它所指向的东西被放在常量区罢了。