C语言之动态内存管理_柔性数组篇(2)

简介: C语言之动态内存管理_柔性数组篇(2)

今天接着来讲解一下柔性数组知识。

柔性数组的特点

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

  • 结构体中
  • 最后一个成员
  • 未知大小的数组【柔性数组】
struct Stu
{
  char c;
  int i;
  int arr[];
  //也可以这样写int arr[0]
  //未知大小的数组 -柔性数组成员
};
  • 结构中的柔性数组成员前面必须至少一个其他成员。
  • sizeof 返回的这种结构大小不包括柔性数组的内存。
  • 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

我们来验证一下 【sizeof 返回的这种结构大小不包括柔性数组的内存。】--->【验证成功】


#include<stdio.h>
struct Stu
{
  char c;//1 
  int i;//4  
  //对齐规则:8
  int arr[];
  //也可以这样写int arr[0]
  //未知大小的数组 -柔性数组成员
};
int main()
{
  printf("%d", sizeof(struct Stu));
  return 0;
}

验证完之后,我们再来学习一下【动态内存函数在柔性数组上的应用】吧!


#include<stdio.h>
struct Stu
{
  char c;//1 
  int i;//4  
  //对齐规则:8
  int arr[];
  //也可以这样写int arr[0]
  //未知大小的数组 -柔性数组成员
};
int main()
{
  struct Stu* p = (struct Stu*)malloc(sizeof(struct Stu)+20);//arr里放5个整型
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  free(p);
  p = NULL;
  return 0;
}

#include<stdio.h>
struct Stu
{
  char c;//1 
  int i;//4  
  //对齐规则:8
  int arr[];
  //也可以这样写int arr[0]
  //未知大小的数组 -柔性数组成员
};
int main()
{
  struct Stu* p = (struct Stu*)malloc(sizeof(struct Stu)+20);//arr里放5个整型
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  //发10个整型
  struct Stu* s = (struct Stu*)realloc(p, sizeof(struct Stu) + 40);
  if (s != NULL)
  {
    p = s;
  }
  else
  {
    perror("realloc");
    return 1;
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}

想必大家都知道为什么叫柔性数组,因为【利用realloc任意调整数组的空间大小】记得及时释放

柔性数组需要对齐吗?动动小手测试一下。需要40

柔性数组的使用

对柔性数组赋值1,2,3,4,5并打印出来。

#include<stdio.h>
#include<stdlib.h>
struct Stu
{
  char c;//1 
  int i;//4  
  //对齐规则:8
  int arr[];
  //也可以这样写int arr[0]
  //未知大小的数组 -柔性数组成员
};
int main()
{
  struct Stu* p = (struct Stu*)malloc(sizeof(struct Stu)+20);//arr里放5个整型
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  p->c = 't';
  p->i = 7;
  int i = 0;
  for (i = 0;i < 5; i++)
  {
    p->arr[i] = i+1;
  }
  for (i = 0; i < 5; i++)
  {
    printf("%d ", p->arr[i]);
  }
  //放10个整型
    struct Stu* s = (struct Stu*)realloc(p, sizeof(struct Stu) + 40);
  if (s != NULL)
  {
    p = s;
  }
  else
  {
    perror("realloc");
    return 1;
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}

柔性数组还可以应用于【通讯录 】,后期我们也会去实现通讯录,并用【柔性数组】优化。

动态内存函数增容柔性数组模拟实现

  • 需要释放两次和开辟两次空间
  • 频繁的不连续开辟,内存碎片很多,内存的利用率很低
#include<stdio.h>
#include<stdlib.h>
struct S
{
  char c;
  int i;
  int* a;
};
int main()
{
  //为结构体开辟空间
  struct S* ps = (struct S*)malloc(sizeof(struct S));
  if (ps == NULL)
  {
    perror("malloc");
    return 1;
  }
  ps->c = 'T';
  ps->i = 7;
  ps->a = (int*)malloc(20);
  if ( ps->a == NULL)//注意写法ps->a
  {
    perror("malloc");
    return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 5; i++)
  {
    ps->a[i] = i + 1;
  }
  for (i = 0; i < 5; i++)
  {
    printf("%d ", ps->a[i]);
  }
  //不够继续增加容
  int* pd = (int*)realloc(ps->a, 40);
  if (pd != NULL)
  {
    ps->a = pd;
  }
  else
  {
    perror("realloc");
    return 1;
  }
  printf("\n");
  //再次赋值
  int j = 0;
  for (j = 0; j < 10; j++)
  {
    ps->a[j] = j + 1;
  }
  for (j = 0; j < 10; j++)
  {
    printf("%d ", ps->a[j]);
  }
  //释放
  free(ps->a);
  ps->a = NULL;
}

柔性数组的优势

通过上面两端代码【柔性数组】和【指针】的比较,即便它们的功能一致,我们可以清晰的发现【柔性数组的优势】。

【优点1】方便释放 一次性就释放完全


如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。


【优点2】这样有利于访问的速度,减少内存碎片,提高空间利用率


连续的内存有益于提高访问速度,也有益于减少内存碎片。


最后,有一篇文章,感谢他让我受益匪浅。  

C语言结构体里的成员数组和指针 | 酷 壳 - CoolShell


【建议书】C陷阱与缺陷  高质量C\C++ 剑指offer 明解C语言等等


最后我想对我自己说,其实学习就是这样,刚开始并不喜欢计算机这门专业。其实我很想去选小语种西班牙语去到国外做翻译去看世界,而且我的理科思维并不好,但是在选择这门学科之后,当我开始认真的学习一些C语言的语法之后,我看到我自己独立写出来的游戏小程序的时候,还是挺有成就感,特别看到博客被大家看到,传递一些知识,还是很幸福的。写博客挺费时间的,但是我希望小唐可以一直坚持的学习,坚持写博客和交流知识。慢慢走,每一步都算数的。


✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com

联系------→【邮箱:2784139418@qq.com】

目录
相关文章
|
30天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
45 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
30天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
61 6
|
2月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
51 6
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
148 13
|
2月前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
2月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
65 1
|
2月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
30天前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
62 10