C语言字面常量的内存映像

1,389 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

经常遇到字面常量,比如直接出现的各种进制的数字,字符或字符串等。

那它到底是怎么在内存存储的呢?

存储在内存只读区

实际上只存在基本数据类型的字面常量。 由于字面常量只能引用,不能修改,所以语言实现一般,把它保存在程序的符号表里,而不一般的数据区中。

符号表是“只读”的,其实它是一种访问保护机制 ,但不能理解为只读存储器。 除了字符串外,你无法取一个字面常量的地址。

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语言程序整体内存映射如下:

image.png

基本情况,就是如上面所说所画。

常量字符串存在静态区

但一个情况,需要注意,也是上面提到过的:常量字符串都存放在静态存储区,返回的是常量字符串的首地址,除了常量字符串,其它的常量都存在程序只读区,只有字符串常量存在在静态存储区。

这一个也可以用代码进行验证:

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是栈上的局部变量,编译报警告了,打印出来也是空,说明空间的确已经释放了

通过这样可知,字面常量除了字符串外,都是存储在只读区的,但是字符串常量具体了两个存储区的特性

第一就是只读,不能被修改,否则,程序直接崩溃

第二就是全局的,程序运行期间,其不放被释放

文章到此