• C语言数组在内存中是怎样表示的?


    最近群里有位同学问“C语言中数组在内存中是怎样表示的”,今天我们就来聊一聊这个话题。

    开局一张图:

    如上图所示,这是经典的Linux进程内存布局,通常我们使用的数据存在这样几个地方:

    • 栈区,Stack

    • 全局区,Global

    • 堆区,Heap

    接下来,我们分别看一下C语言中的数组在这几个区域是怎样表示的(注意:这里的机器是x86 64位)。

    1、数组与栈区

    先来看一段极其简单的代码:

    我们定义了一个局部变量arr作为int类型的数组,然后分别将100-600写到了数组中。那么,数组arr在内存中是怎样表示的呢?

    首先,我们编译一下:

    注意,-fno-stack-protector选项是为了禁止堆栈保护,让汇编更容易懂些,关于堆栈保护这个话题可以参考这篇文章《黑客攻防:缓冲区溢出攻击与堆栈保护》。

    好啦,一切准备就绪,可以庖丁解牛啦,使用的刀就是gdb,代码面前了无秘密,gdb面前程序的运行时(run time)了无秘密。

    用gdb来调试刚刚编译出来的程序,这里看一下arr_on_stack函数的汇编指令:

    我们在之前的文章多次提到过,每个函数在运行起来后都有属于自己的栈帧,栈帧组成栈区,此时arr_on_stack这个函数的栈区在哪里呢?答案就在寄存器rbp中。

    我们来看一下rbp寄存器指向了哪里?

     啊哈,原来栈帧在0x7ffffffee2a0这个地方,那么我们的数组arr在哪里呢?别着急,这条指令会告诉我们答案:

     这行指令的含义是说把100(0x64)放到rbp寄存器减去0x20的地方,显然,这就是数组的开头,让我们来计算一下rbp寄存器减去0x20:

    因此,我们预测arr应该在0x7ffffffee280这个位置上。

    接下来,我们用gdb验证一下:

     哈哈,怎么样,是不是和我们猜想的一样,数组arr的确就放在了0x7ffffffee280这个位置,是这样存储的:

     这就是C语言中所谓的数组了,无非就是从0x7ffffffee280 到 0x7ffffffee298这一段内存嘛,数组在栈区就是这么表示的!

    2、数组与全局区

    同样看一段代码:

     同样使用# gcc -g -fno-stack-protector a.c编译,然后用gdb加断点在int b = global_array[0]这行代码,看下全局变量global_array的内存位置:

    gdb告诉我们数组global_array存放在内存0x601050这个地址上。

    注意,0x601050这个地址和刚才看到的0x7ffffffee280这个地址相去甚远,这是为什么呢?

    再看一下开局那张图:

    全局区几乎在最底部,栈区在最顶部,所以相差很远。

    接下来,让我们看看0x601050这个内存区域中到底保存了些啥?

    我们使用命令x/6wd 0x601050,这个命令告诉gdb从0x601050这个位置开始以32bit为单位用10进制依次打印6次,让我们来看看打印的是什么?

     哈哈,怎么样,是不是正是全局变量global_array中存放的内容:

     这就是C语言中所谓的数组了,无非就是从 0x601050到 0x601068这一段内存嘛,数组在全局区就是这么表示的!

    3、数组与堆区

    再来段代码:

     使用gdb加断点在int a = arr[0];这行代码,然后打印数组arr的地址:

    注意,0x602010这个地址和刚才的全局数组global_array的地址0x601050比较接近,因为堆区和全局区挨得比较近,可以再回过头看一下开局那张图。

    然后,我们同样使用x命令查看这个区域的内存内容:

     依然不出我们所料,这个区域保存的正是数组的值。

    这就是C语言中所谓的数组了,无非就是从 0x602010到 0x602028这一段内存嘛,数组在堆区就是这么表示的!

    现在你应该明白了吧,C语言中所谓的数组是怎么表示的?很简单,其实也没啥表示,无非就是内存中一段连续的空间,仅此而已。

    希望这篇文章对大家理解C语言中的数组有所帮助。

    【学习技术群769843038】

    【网盘免费资料包,需要的自行领取】:

    嵌入式物联网 22个STM32项目、大赛作品,【华清远见发放资料包】http://makerschool.mikecrm.com/f4wjYBB

    【下方分享一些免费教程资料,大家感兴趣的可以看一下】:

    C语言编程基础 

    提升C编程能力

    指针

    C语言控制led灯

    C语言实现面向对象编程

    C语言与数据结构的经典实战案例

    Linux C语言高级开发

    必备Linux命令和C语言基础

    嵌入式操作系统uC/OS

  • 相关阅读:
    浏览器上的快捷键
    centos7 宝塔php7安装mongodb扩展
    redis集群搭建教程及遇到的问题处理
    java.time.Year使用详解
    C++并发与多线程(4) | 传递临时对象作为线程参数的一些问题Ⅰ
    【Dubbo3高级特性】「框架与服务」RPC全链路调用追踪参数传递(OpenTracing)
    Linux——操作进程状态
    一场网络攻击,可以“击垮”一个国家?【2022戴尔科技峰会预告】
    Python学习 - 异常处理
    AJAX——HttpRequest对象、get/post请求
  • 原文地址:https://blog.csdn.net/an520_/article/details/126504907