c语言学习第三十二课---内存开辟位置与柔性数组

简介: c语言学习第三十二课---内存开辟位置与柔性数组

c/c++程序的内存开辟

1.栈区:在执行函数时,函数的内部的储存单元都可以在栈上创建,结束时自动被释放。栈区的分配预案算内置预处理器模块,效率很高,但是分配的内存容量有限。存放不下就会产生栈溢出的现象。

栈区主要存放运行函数时被分配的局部变量,函数参数,返回数据,返回地址等        

2.堆区:一般由程序员分配释放,若若程序员不释放,结束时可能被OS回收,分配方式类似链表。

3.数据段:也是静态区,存放全局变量,静态数据。程序结束时有系统释放。

4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。

526a10656b314fb2b0e5919d5d5f14da.png

realloc函数补充

505c39e138864436a3540ff132cab159.png

realloc也可以像malloc一样申请空间

若第一个参数给的不是所扩容的指针,而是空指针,如realloc(NULL,20),那就是如malloc一样申请20个字节的空间。

柔性数组

在 c99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。

typedef struct st_type
{
  int i;
  int a[0];//柔性数组成员
};

柔性数组特点1:

.结构体中柔性数组成员前面必须至少有一个其他成员

   两种写法

typedef struct st_type
{
  int i;
  int a[0];//柔性数组成员
};
//或者这样写
struct S
{
  int n;
  char c;
  int arr[];//大小未知
};

柔性数组特点2:

.sizof返回的这种结构大小不包过柔性数组的内存

struct S
{
  int n;
  char c;
  int arr[];//未知,不知道它该占多大空间
};
int main()
{
  printf("%d", sizeof(struct S));//结果为8
}

这里的空间大小不会包括柔性数组成员的大小,大小计算参考之前结构体内容。

柔性数组特点3:

.包含柔性数组成员的结构用malloc函数惊醒内存分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的大小。

在创建结构体变量时,这里创建结构体的方式发生了改变,用动态内存开辟它的空间。

struct S
{
  int n;
  char c;
  int arr[];
};
int main()
{
  //假设柔性数组里我们想放10个整型数据
  struct S*  ptr=(struct S*)malloc(sizeof(struct S)+10*sizeof(int));
  if (ptr== NULL)
  {
    printf("%s\n", strerror(errno));
    return 1;
  }
  //使用
  ptr->n = 100;
  ptr->c = "w";
  for (int i = 0; i < 10; i++)
  {
    ptr->arr[i] = i;
    printf("%d", ptr->arr[i]);
  }
  //调整数组大小  大小调整为20ge 整形
  struct S* tmp = (struct S*)realloc(ptr, sizeof(struct S) + sizeof(int) * 20);
  if (tmp == NULL)
  {
    printf("%s\n", strerror(errno));
    return 1;
  }
  //使用
  ptr->n = 100;
  ptr->c = "w";
  for (int i = 0; i < 20; i++)
  {
    ptr->arr[i] = i;
    printf("%d", ptr->arr[i]);
  }
  //释放
  free(ptr);
  ptr - NULL;
}

利用malloc函数开辟结构体空间大小。

这里的柔性数组成员类似 int arr[10]存放10个整形数据,但是因为该数组的空间是由malloc开辟的,因此我们可是使用realloc函数来对空间进行调整根据我们的需求

通过调整结构体大小动态调整数组大小,柔性可变,故为柔性数组。

通过指针实现柔性数组的动态特点。

这里开辟空间时,只能先开辟结构体的空间,再开辟结构体里指针的空间。

这里的两个例子作用都是存放一到十的10个整形数据,扩容后存放一到二十的20个整型数组。

struct S
{
  int n;
  char c;
  int* arr;
};
int main()
{
  struct S* ptr = (struct S*)malloc(sizeof(struct S));
  if (ptr == NULL)
  {
    printf("%s\n", strerror(errno));
    return 1;
  }
  int* tmp = (int*)malloc(sizeof(int) * 10);
  if (ptr == NULL)
  {
    printf("%s\n", strerror(errno));
    return 1;
  }
  else
  {
    ptr->arr = tmp;//把开辟出来的空间给结构体里的指针
  }
  //使用
  ptr->n = 100;
  ptr->c = "w";
  for (int i = 0; i < 10; i++)
  {
    ptr->arr[i] = i;
    printf("%d", ptr->arr[i]);
  }
  //调整
  int *pc=realloc(ptr->arr, sizeof(int) * 20);
  if (pc == NULL)
  {
    return 1;
  }
  else
  {
    ptr->arr = pc;
  }
  //在使用
  ptr->n = 100;
  ptr->c = "w";
  for (int i = 0; i < 20; i++)
  {
    ptr->arr[i] = i;
    printf("%d", ptr->arr[i]);
  }
  //释放
  free(ptr->arr);
  ptr->arr = NULL;
  free(ptr);
  ptr = NULL;
  return 0;
}

注意:这里再释放时,我们刚开始下开辟的是结构体的空间,后开辟的结构体中指针的空间(扩容也是对结构体里的指针),故释放先释放结构体中指针的空间,在释放结构体的空间。

两者的区别

方案一(柔性数组)

malloc一次,free一次  

容易维护空间,不易出错,且malloc次数少,内存碎片少,空间利用率相对较高。

方案二(指针表示)

malloc两次,free两次,维护难度加大,容易出错  

malooc越多,内存碎片会增多,内存的使用率较低。

其实这里的内存节约也没多少,主要是理解其中特点。


相关文章
|
2月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
110 26
|
2月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
225 15
|
9月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
271 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
9月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
284 6
|
10月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
230 1
|
C# C语言 C++
从头开始学习c语言
以前的时候学习C语言时候认为C语言不过是一个学习的工具,学习一些理论知识就达到目的了,谁会用这么傻的语言啊,连个界面也没有,不像vb一下子就做出一个窗体来,放上几个按钮就可以了 后来学习C++的时候,认为C++与C是一种完全不同的语言,两者基本没有什么兼容性,当时在学校里看书的时候,一直比较纳闷为会c++的书上会写C++/C语言教程,到了现在才明白,我去C++与C本来就是一体是一脉相承的
1089 0
|
8月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
357 23
|
7月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
157 1
一文彻底搞清楚C语言的函数
|
8月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
299 15
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
|
8月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
138 24