本文已参与「新人创作礼」活动,一起开启掘金创作之路。
经常遇到字面常量,比如直接出现的各种进制的数字,字符或字符串等。
那它到底是怎么在内存存储的呢?
存储在内存只读区
实际上只存在基本数据类型的字面常量。 由于字面常量只能引用,不能修改,所以语言实现一般,把它保存在程序的符号表里,而不一般的数据区中。
符号表是“只读”的,其实它是一种访问保护机制 ,但不能理解为只读存储器。 除了字符串外,你无法取一个字面常量的地址。
x = 1;
char c = 'a';
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 int main()
6 {
7 char *var_a = "abc";
8 printf("var_a=%s\n", var_a);
9 *(var_a+1) = 'e';
10 printf("var_a=%s\n", var_a);
11
12 }
root@mkx:~/learn/literalConstant# gcc literalConstant2.c -o liberal2
root@mkx:~/learn/literalConstant# ./liberal2
var_a=abc
段错误 (核心已转储)
root@mkx:~/learn/literalConstant#
通过上面可知:字符串常量,是不可被修改的,这体现了其只读的特性。
这些都是字面常量,其是怎么存储的呢?
在C语言的内存存储是这样的: 1、栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完后就释放了,其操作方式类似于数据结构中的栈。栈内存分配运算内置于CPU的指令集,效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。(栈是先进后出,队列是先进先出)
2、堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。“内存泄漏”通常说的就是堆区。
3、静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。
4、常量区:常量存储在这里,不允许修改。
5、代码区:顾名思义,存放代码。
C语言程序整体内存映射如下:
基本情况,就是如上面所说所画。
常量字符串存在静态区
但一个情况,需要注意,也是上面提到过的:常量字符串都存放在静态存储区,返回的是常量字符串的首地址,除了常量字符串,其它的常量都存在程序只读区,只有字符串常量存在在静态存储区。
这一个也可以用代码进行验证:
2 #include <stdlib.h>
3 #include <string.h>
4
5 char *Func(void)
6 {
7 //str数组创建在函数堆栈上,并用字符串常量来初始化,在末尾自动添加'\0'
8 char str[] = "hello world";
9 printf("sizeof(str)=%lu\n", sizeof(str));
10 printf("strlen(str)=%lu\n", strlen(str));
11 return str;
12 }
13
14 char *Func2(void)
15 {
//就是创建在静态存储区中
16 char *p = "hello world";
17 printf("sizeof(p)=%lu\n", sizeof(p));
18 printf("strlen(p)=%lu\n", strlen(p));
19 return p;
20 }
21
22 int main()
23 {
24 char *str = Func();
25 printf("str=%s\n", str);
26 char *p = Func2();
27 printf("p=%s\n", p);
28
29 }
~
"literalConstant.c" 29L, 571C
运行情况:
root@mkx:~/learn/literalConstant# gcc literalConstant.c -o literalConstant
literalConstant.c: In function ‘Func’:
literalConstant.c:11:10: warning: function returns address of local variable [-Wreturn-local-addr]
return str;
^
root@mkx:~/learn/literalConstant# ./literalConstant
sizeof(str)=12
strlen(str)=11
str=(null)
sizeof(p)=8
strlen(p)=11
p=hello world
root@maokx:~/learn/literalConstant#
从编译可知:
p=hello world是正常打印出来了,这说明,其是全局的变量,不是局部的变量;
而str是栈上的局部变量,编译报警告了,打印出来也是空,说明空间的确已经释放了
通过这样可知,字面常量除了字符串外,都是存储在只读区的,但是字符串常量具体了两个存储区的特性
第一就是只读,不能被修改,否则,程序直接崩溃
第二就是全局的,程序运行期间,其不放被释放
文章到此