C语言数据的存储超详细讲解上篇

下面是“C语言数据的存储超详细讲解上篇”完整攻略。

一、内存模型

在C语言中,程序中的数据都是存储在内存中的。内存是按照字节进行划分的,每个字节都有一个唯一的地址。程序可以通过地址来访问内存中的数据。

C语言中的内存模型分为以下几个不同的部分:

栈是一种数据结构,它是一个先进后出(LIFO)的结构。栈的大小是可以动态变化的,它和函数的调用有着密切的关系。

当一个函数被调用时,它的参数、返回地址以及一些寄存器都会被压入栈中。函数执行结束后,它们也会被弹出。

在栈中,变量的分配是连续的,因此可以通过栈指针进行内存地址的计算。这也是栈的优势之一。

堆是一种动态内存分配的机制,它的大小可以在运行时动态地改变。我们通常使用mallo函数从堆上动态地分配内存。

堆中的内存分配不是连续的,也就是说,没有办法通过指针偏移来访问。

在堆中分配的内存需要手动释放,否则就会发生内存泄漏。

数据段

数据段是一个存储全局变量和静态变量的区域。它分为两个部分:

  • BSS段:用来存放未被初始化的全局变量和静态变量;
  • 数据段:用来存放已经被初始化的全局变量和静态变量。

代码段

代码段存储着程序的代码,它通常是只读的。执行程序时,代码段中的指令会被载入到CPU中,进行执行。

二、示例

下面是两个示例,它们分别演示了存储在不同内存模型中的数据的不同。代码如下:

示例1

#include <stdio.h>
#include <stdlib.h>

char* str = "Hello World"; // 全局变量,存储在数据段中

void f() {
    char* s = "Hello China"; // 局部变量,存储在栈中
    printf("%s\n", s);
}

int main() {
    char* p = malloc(sizeof(char) * 100); // 动态内存分配,存储在堆中
    strcpy(p, str);
    printf("%s\n", p);

    f();

    return 0;
}

在这个示例中,我们定义了一个全局变量,将它存储在数据段中。同时,在函数中定义了一个局部变量,将它存储在栈中。在main函数中,我们使用malloc函数从堆中动态地分配了一块内存。

运行这个程序后,我们可以看到输出了如下内容:

Hello World
Hello China

这是因为在函数调用的过程中,函数参数、返回地址等信息都被压入栈中。

示例2

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a = 10; // 栈区
    int b[10];  // 栈区
    char* p = "Hello World"; // 常量区
    char str[] = "Hello"; // 栈区

    static int c = 30; // 数据区

    int *q = (int *)malloc(sizeof(int));
    *q = 20; // 堆区

    printf("a: %p\n", &a);
    printf("b: %p\n", b);
    printf("p: %p\n", p);
    printf("str: %p\n", &str);
    printf("c: %p\n", &c);
    printf("q: %p\n", q);

    free(q);

    return 0;
}

在这个示例中,我们定义了不同类型的、存储在不同内存模型中的变量,并使用了一些函数来打印变量的地址。

运行程序后,我们可以得到如下输出:

a: 0x7fff6e79e32c
b: 0x7fff6e79e320
p: 0x106920f26
str: 0x7fff6e79e30e
c: 0x106920f20
q: 0x7facbf400b40

从输出中可以看出,不同类型的变量存储在不同的内存模型中。同时,我们也可以通过地址来判断一个变量存储在哪个内存模型中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据的存储超详细讲解上篇 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • C++中的new/delete、构造/析构函数、dynamic_cast分析

    C++ 中的 new/delete、构造/析构函数和 dynamic_cast 是面向对象编程中非常重要的概念。本攻略将为你详细讲解这三个概念的含义和用法。 new/delete 在 C++ 中,new 和 delete 是动态内存分配和释放运算符。new 运算符用于分配动态内存,delete 运算符用于释放动态内存。它们可以用于任意类型的数据。 示例说明 …

    other 2023年6月26日
    00
  • vue2与vue3中生命周期执行顺序的区别说明

    Vue2与Vue3中生命周期执行顺序的区别说明 Vue2和Vue3是两个较为流行的版本的Vue框架。两个版本的组件生命周期函数执行顺序有一些区别。本文将分析并比较Vue2和Vue3中组件生命周期函数的执行顺序,同时给出两个示例以便更好地理解。 Vue2生命周期执行顺序 beforeCreate 在Vue2中,组件实例被创建后,会立即执行beforeCreat…

    other 2023年6月27日
    00
  • Win8.1桌面图标显示不正常问题的解决方法

    Win8.1桌面图标显示异常的问题一般有两种情况:一是桌面图标变得很小或者没有了文字,二是桌面图标布局变乱了或者重叠了。下面是解决这些问题的攻略。 问题一:桌面图标变小或没有文字 步骤1:检查缩放设置 首先,我们需要检查电脑的缩放设置是否正确。在桌面上按住 Ctrl 键不放,同时滚动鼠标滚轮,调整缩放比例。如果缩放比例过小,桌面上的图标就会变得很小,无法看清…

    other 2023年6月27日
    00
  • dos是什么意思?怎么进DOS命令的方法

    以下是对你提出的问题的详细解答。 什么是DOS DOS是Disk Operating System(磁盘操作系统)的缩写。是在早期IBM PC(个人电脑)上广泛使用的操作系统。DOS提供了一组命令,通过命令行(命令提示符)来操作计算机文件和目录,以及运行应用程序。它在早期的计算机历史中发挥了巨大的作用。 进入DOS命令的方法 进入DOS命令有不同的方法,下面…

    other 2023年6月26日
    00
  • Java 深入分析链表面试实例题目

    Java 深入分析链表面试实例题目的攻略如下: 1. 理解链表结构 链表是一种非常基础的数据结构,它由各个节点组成,每个节点都包含数据和指向下一个节点的指针。链表包含头节点和尾节点,以及节点间的链接关系。 示例代码如下: public class ListNode { int val; ListNode next; ListNode(int x) { val…

    other 2023年6月27日
    00
  • CSS代码检查工具stylelint的使用方法详解

    下面为大家详细讲解“CSS代码检查工具stylelint的使用方法详解”。 什么是stylelint? stylelint是一个基于Node.js构建的CSS代码检查工具,它可以帮助我们检查CSS代码规范性是否符合规定的规则,从而提高CSS代码的质量和可维护性。 使用步骤 安装stylelint: 在命令行中执行以下命令进行安装: npm install s…

    other 2023年6月27日
    00
  • git分支的创建和切换

    当我们在进行软件开发时,通常需要在同一个代码库中进行多个开发和测试。Git分支是一个非常有用的功能,它允许我们在一个代码库中创建多个分支,以便在不影响主分支的情况下进行开发和测试。本文将详细介绍如何在Git中创建和切换分支,并提供两个示例说明。 创建分支 在Git中,我们可以使用git branch命令创建一个新分支。以下是创建一个名为feature的新分支…

    other 2023年5月7日
    00
  • Windows11下MySQL 8.0.29 安装配置方法图文教程

    下面是详细讲解“Windows11下MySQL 8.0.29 安装配置方法图文教程”的完整攻略。 步骤一:下载MySQL 8.0.29 打开MySQL官网:https://dev.mysql.com/downloads/mysql/ 在下载页面中,选择“MySQL Community (GPL) Downloads”。 在“MySQL Community S…

    other 2023年6月20日
    00
合作推广
合作推广
分享本页
返回顶部