详解C语言中的内存四区模型及结构体对内存的使用_C 语言

内存四区
1、代码区
代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。
2、静态区
所有的全局变量以及程序中的静态变量都存储到静态区。
3、栈区
栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。对于自动变量,什么时候入栈,什么时候出栈,是不需要程序控制的,由C语言编译器。实现栈不会很大,一般都是以K为单位的。
当栈空间以满,但还往栈内存压变量,这个就叫栈。溢出对于一个32位操作系统,最大管理管理4G内存,其中1G是给操作系统自己用的,剩下的3G都是给用户程序,一个用户程序理论上可以使用3G的内存空间。
注意:C语言中函数参数入栈的顺序是从右往左。
4、堆区
堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
代码示例:

#include <stdio.h> 

int c = 0; // 静态区 

void test(int a, int b) // 形参a,b都在栈区
{
  printf("%d, %d\n", &a, &b);
} 

int *geta() // 函数的返回值是一个指针
{
  int a = 100; // 栈区
  return &a;
} // int a的作用域就是这个{} 

int main()
{
  int *p = geta(); // 这里得到一个临时栈变量的地址,这个地址在函数geta调用完成之后已经无效了
  *p = 100;
  printf("%d\n", *p);
  static int d = 0; // 静态区
  int a = 0; // 栈区
  int b = 0; 

  printf("%d, %d, %d, %d, %d\n", &a, &b, &c, &d, main);
  test(a, b);
  return 0;
} 

/*
输出结果
100
2619740, 2619728, 9404720, 9404724, 9376059
2619512, 2619516
*/ 

堆使用注意事项:

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

int *geta() // 错误,不能将一个栈变量的地址通过函数的返回值返回
{
  int a = 0;
  return &a;
} 

int *geta1() // 可以通过函数的返回值返回一个堆地址,但记得,一定要free
{
  int *p = (int *)malloc(sizeof(int)); // 申请了一个堆空间
  return p;
} 

int *geta2() // 合法的,但是记住这里不能用free
{
  static int a = 0; // 变量在静态区,程序运行过程中一直存在
  return &a;
} 

void getHeap(int *p)
{
  printf("p = %p\n", &p);
  p = (int *)malloc(sizeof(int) * 10);
} // getHeap执行完之后,p就消失了,导致他指向的具体堆空间的地址编号也随之消失了
// 这里发生了内存泄漏 

void getHeap1(int **p)
{
  *p = (int *)malloc(sizeof(int) * 10);
} // 这里的操作就是正确的 

int main()
{
  int *p = NULL;
  printf("p = %p\n", &p);
  getHeap(p); // 实参没有任何改变
  getHeap1(&p); // 得到了堆内存的地址
  printf("p = %d\n", p); 

  p[0] = 1;
  p[1] = 2;
  printf("p[0] = %d, p[1] = %d\n", p[0], p[1]);
  free(p); 

  return 0;
} 

结构体内存对齐模式

结构体内存对齐模式各种情况详解

#include <stdio.h> 

struct A
{
  int a; // 此时结构体占用4个字节
  char b; // 此时结构体占用8个字节
  char c; // 还是8个字节
  char d; // 还是8个字节
  char e; // 还是8个字节
  char f; // 现在是12个字节
}; 

struct B
{
  char a; // 1个字节
  char b; // 2个字节
  char c; // 3个字节
}; 

struct c
{
  char name[10]; // 10个字节
  char a; // 11个字节
  // 对于char型数组来说,会把数组每个元素当作一个char类型
}; 

struct d
{
  int name[10]; // 40个字节
  char a; // 44个字节
  char b; // 44个字节
}; 

struct e
{
  char a; // 1个字节
  int b; // 8个字节
  char c; // 12个字节
  // 这种写法内存的消耗相比A就会变大
}; 

struct f
{
  char a; // 1
  short b; // 4注意这里short占用的是剩下三个字节中的后两个
  // 内存对齐总是以2的倍数对齐
  char c; // 所以此时是6
  int d; // 12
  short e; // 16
  char f; // 16
}; 

结构体变相实现数组赋值

struct name
{
  char array[10];
}; 

int main()
{
  char name1[10] = "name1";
  char name2[20] = "name2";
  name1 = name2; // 这里是出错的,不能在数组之间进行赋值
  struct name a1 = { "hello" };
  struct name a2 = { 0 };
  a2 = a1; // 这里通过结构体可以赋值的特性变相实现了数组的赋值
  return 0;
}

结构体内存泄漏

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

union A
{
  char a;
  char *b; // 联合体的指针成员要特别注意
}; 

int main()
{
  A a;
  a.b = (char *)malloc(10); // b指向了一个堆的地址
  // 如果联合体中有指针成员,那么一定要使用完这个指针,并且free指针之后才能使用其他成员
  a.a = 10; // b的值也成了10了
  free(b); // 此时释放b是错误的,因为在上面一行对a进行赋值时,已经将b的值更改了,这里造成了内存泄漏
  return 0;
} 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c语言
, 内存
结构体
c语言结构体详解、c语言file结构体详解、c语言结构体、c语言 结构体初始化、c语言结构体定义,以便于您获取更多的相关知识。

时间: 2024-12-02 16:38:44

详解C语言中的内存四区模型及结构体对内存的使用_C 语言的相关文章

C++动态分配和撤销内存以及结构体类型作为函数参数_C 语言

C++动态分配内存(new)和撤销内存(delete) 在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除.在C语言中是利用库函数malloc和free来分配和撤销内存空间的.C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数. 注意: new和delete是运算符,不是函数,因此执行效率高. 虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算

详解Android开发中Activity的四种launchMode_Android

Activity栈主要用于管理Activity的切换.当使用Intent跳转至某个目标Activity,需要根据目标Activity的加载模式来加载. Activity一共有以下四种launchMode: 1.standard:默认,每次使用Intent跳转到目标Activity时都创建一个新的实例.坏处是每次进入都要创建新的实例,执行OnCreate方法. 2.singleTop:如果要跳转的目标Activity正好在task的顶部(说明当前肯定不在目标task里,例如我在微信首页,然后想使用

解析C语言中结构体struct的对齐问题_C 语言

首先看一下结构体对齐的三个概念值: 数据类型的默认对齐值(自身对齐): 1.基本数据类型:为指定平台上基本类型的长度.如在32位机器中,char对齐值为1,short为2,int,float为4,double为8: 结构体:其数据成员中默认对齐值最大的那个值. 2.指定对齐值:#pragma pack (value)时的指定对齐值value. 3.数据类型的有效对齐值:默认对齐值和指定对齐值中小的那个值. 有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式.有效对齐值N是最

C语言中的结构体的入门学习教程_C 语言

C语言中数组允许定义类型的变量,可容纳相同类型的多个数据项,但结构体在C语言编程中,它允许定义不同种类的数据项可供其他用户定义的数据类型. 结构是用来代表一个记录,假设要跟踪图书馆的书籍.可能要跟踪有关每本书以下属性: Title - 标题 Author - 作者 Subject - 科目 Book ID - 编号 定义结构体定义一个结构体,必须使用结构体的struct语句.该struct语句定义了一个新的数据类型,程序不止一个成员.struct语句的格式是这样的: struct [struct

详解Android开发中Activity的四种launchMode

Activity栈主要用于管理Activity的切换.当使用Intent跳转至某个目标Activity,需要根据目标Activity的加载模式来加载. Activity一共有以下四种launchMode: 1.standard:默认,每次使用Intent跳转到目标Activity时都创建一个新的实例.坏处是每次进入都要创建新的实例,执行OnCreate方法. 2.singleTop:如果要跳转的目标Activity正好在task的顶部(说明当前肯定不在目标task里,例如我在微信首页,然后想使用

浅谈C语言中的强符号、弱符号、强引用和弱引用_C 语言

首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引用.在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样感觉的朋友交流也希望高人指点. 首先我们看一下书中关于它们的定义. 引入场景:(1)文件A中定义并初始化变量i(int i = 1), 文件B中定义并初始化变量i(int i = 2).编译链接A.B时会报错b.o:(.data+0x0): multiple definition of `i':a.o:(.d

C语言中交换int型变量的值及转换为字符数组的方法_C 语言

不使用其他变量交换两个整型的值: #include <stdio.h> void main(){ int a = 3; int b = 4; a = a ^ b;//使用异或交换 b = b ^ a; a = a ^ b; printf("%d, %d\n", a, b); a = a - b;//使用加减交换 b = a + b; a = b - a; printf("%d, %d\n", a, b); a ^= b ^= a ^= b; printf

CSS标签语法:详解选择符中的关系选择符

文章简介:CSS标签语法:详解选择符中的关系选择符. 相信大家都对CSS选择符都不陌生,选择符包含:元素选择符.关系选择符.属性选择符.伪类选择符.伪对象选择符.在众多的选择符中,可以让我们根据自己的需要更加灵活性的选择合适的选择符来对样式进行编写,达到最大的质量和效率. 今天就为大家介绍下选择符中的关系选择符,"关系"这可是一等一的大事啊,我们得理清楚,这样做事情才能更加的有效率.不然在CSS中有你受的,哈哈.关系选择符有四个类别:包含选择符.子选择符.相邻选择符.兄弟选择符.接下来

详解Java编程中向量(Vector)的应用_java

Vector(向量)是 java.util 包中的一个类,该类实现了类似动态数组的功能. 向量和数组相似,都可以保存一组数据(数据列表).但是数组的大小是固定的,一旦指定,就不能改变,而向量却提供了一种类似于"动态数组"的功能,向量与数组的重要区别之一就是向量的容量是可变的. 可以在向量的任意位置插入不同类型的对象,无需考虑对象的类型,也无需考虑向量的容量. 向量和数组分别适用于不同的场合,一般来说,下列场合更适合于使用向量: 如果需要频繁进行对象的插入和删除工作,或者因为需要处理的对