C语言-柔性数组与几道动态内存相关的经典笔试题(12.2)

简介: C语言-柔性数组与几道动态内存相关的经典笔试题(12.2)

思维导图:



1.柔性数组

1.1柔性数组的特点

例:


#include 
typedef struct S
{
  int n;
  char arr[];//大小是未知的//这是柔性数组成员
}S;
int main()
{
  printf("&d\n", sizeof(S));//不计算大小
}

输出:


输出:4

柔性数组的特点:


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


2.sizeof 返回的这种结构大小不包括柔性数组的内存。


3.包含柔性数组成员的结构用malloc函数进行内存的动态分配,


并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。


1.2柔性数组的使用

例:


#include 
#include 
#include 
typedef struct S
{
  int n;
  char arr[];//大小是未知的
}S;
int main()
{
  //开辟
  S* ps = (S*)malloc(sizeof(S) + 10 * sizeof(char));//结构体大小+柔性数组需要的大小
  //判断
  if (ps == NULL)
  {
  perror("malloc");
  return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  ps->arr[i] = 'Q';
  printf("%c ", ps->arr[i]);
  }
  //增容
  //.....
  //释放
  free(ps);
  ps = NULL;
  return 0;
}

输出:


输出:Q Q Q Q Q Q Q Q Q Q

1.3柔性数组的优势

其实柔性数组能实现的操作,利用指针也能实现:


例:


#include 
#include 
#include 
typedef struct S
{
  int n;
  char* arr;
}S;
int main()
{
  //开辟内存空间
  S* ps = (S*)malloc(sizeof(S));
  if (ps == NULL)
  {
  return 1;
  }
  ps->n = 100;
  ps->arr = (char*)malloc(sizeof(char) * 10);
  if (ps->arr == NULL)
  {
  perror("malloc:");
  return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  ps->arr[i] = 'Q';
  printf("%c ", ps->arr[i]);
  }
  //增容
  char*ptr=(char*)realloc(ps->arr, 20 * sizeof(char));
  if (ptr != NULL)
  {
  ps->arr = ptr;
  }
  else
  {
  perror("realloc");
  return 1;
  }
  //释放
  free(ps->arr);
  ps->arr = NULL;
  free(ps);
  ps = NULL;
  return 0;
}


输出:


输出:Q Q Q Q Q Q Q Q Q Q

但是用柔性数组实现更好一些:


1.使用柔性数组方便内存的释放,只需要一次free。


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


总而言之,柔性数组给我们解决问题提供了更多的可能。


2.几道经典笔试题

2.1题目1

#include 
#include 
#include 
void GetMemory(char* p)
{
  p = (char*)malloc(100);//申请内存地址
}//p变量销毁了,malloc空间未释放,导致内存泄漏
void test()
{
  char* str = NULL;
  GetMemory(str);
  strcpy(str, "hello world");//访问的是0地址//不允许访问//程序崩溃
  printf(str);
}


注:记得及时释放开辟的动态内存。


正确的写法:


我们可以通过传值调用使传过去的指针指向开辟动态内存。


#include 
#include 
#include 
//正确的写法
void GetMemory(char** p)
{
  *p = (char*)malloc(100);//申请内存地址
}
void test()
{
  char* str = NULL;
  GetMemory(&str);//传址调用
  strcpy(str, "hello world");
  printf(str);
  //释放
  free(str);
  str = NULL;
}
int main()
{
  test();
  return 0;
}


输出:


输出:hello world

当然,也可以通过函数返回值的形式,


将指向动态内存空间的指针返回:


#include 
#include 
#include 
//更多的方法
char* GetMemory()
{
  char*p = (char*)malloc(100);//申请内存地址
  return p;//返回地址
}
void test()
{
  char* str = NULL;
  str = GetMemory();
  strcpy(str, "hello world");
  printf(str);
  //释放
  free(str);
  str = NULL;
}
int main()
{
  test();
  return 0;
}

输出:


输出:hello world

2.2题目2

#include 
#include 
#include 
char* GetMemory()
{
  char p[] = "hello world";
  return p;//返回栈空间的地址
}//p数组销毁了
void test()
{
  char* str = NULL;
  str = GetMemory();
  printf(str);//非法访问  
}
int main()
{
  test();
  return 0;
}


注 :不要访问没有开辟的内存空间,非常危险。


再看一个类似的例子:


#include 
//类似的问题
int* test()
{
  int a = 0;
  return &a;
}//int a的空间被销毁了
int main()
{
  int* p = test();
  printf("hehe\n");//栈区中原本存放a变量的空间被覆盖了
  printf("%d\n", *p);//打印随机值(非法访问)
  return 0;
}

输出:


输出:5

最后就输出了个随机值。


2.3题目3

#include 
#include 
#include 
void GetMemory(char** p, int num)
{
  *p = (char*)malloc(num);//开辟空间
}
void Test(void)
{
  char* str = NULL;
  GetMemory(&str, 100);//传址调用
  //使用
  strcpy(str, "hello");
  printf(str);
  //我们发现它没有释放内存//导致内存泄漏
}

注:一定要记得释放内存!


2.4题目4

#include 
#include 
#include 
void test()
{
  char* str = (char*)malloc(100);//开辟空间
  strcpy(str, "hello");
  free(str);//str释放了
  if (str != NULL)//str被释放后已经是野指针了
  {
  strcpy(str, "world");//非法访问
  printf(str);
  }
}
int main()
{
  test();
  return 0;
}

指针释放后再使用会导致野指针。


我们可以改进这段代码:


#include 
#include 
#include 
void test()
{
  char* str = (char*)malloc(100);//开辟空间
  strcpy(str, "hello");
  free(str);//str释放了
  str = NULL;//主动置为空才行
  if (str != NULL)
  {
  strcpy(str, "world");//非法访问
  printf(str);
  }
}

这样就不会出错了。


写在最后:

以上就是本篇文章的内容了,感谢你的阅读。


如果喜欢本文的话,欢迎点赞和评论,写下你的见解。


如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。


之后我还会输出更多高质量内容,欢迎收看。


相关文章
|
1天前
|
C语言
c语言:字符串和内存函数介绍-2
c语言:字符串和内存函数介绍
5 0
|
1天前
|
C语言
c语言:字符串和内存函数介绍-1
c语言:字符串和内存函数介绍
8 0
|
1天前
|
程序员 编译器 C语言
C语言——动态内存管理
C语言——动态内存管理
|
1天前
|
存储 小程序 编译器
C语言进阶—深度剖析数据在内存中的存储
C语言进阶—深度剖析数据在内存中的存储
|
2天前
|
C语言
【C语言】柔性数组(可变长数组)
【C语言】柔性数组(可变长数组)
|
2天前
|
程序员 编译器 C语言
【C语言】动态内存管理(malloc,free,calloc,realloc)-- 详解
【C语言】动态内存管理(malloc,free,calloc,realloc)-- 详解
|
2天前
|
安全 编译器 C语言
【C语言】字符串和内存函数的介绍 -- 详解
【C语言】字符串和内存函数的介绍 -- 详解
|
2天前
|
存储 编译器 C语言
【C语言】深度剖析数据在内存中的存储
【C语言】深度剖析数据在内存中的存储
|
2天前
|
程序员 C语言
c语言动态内存分布
c语言动态内存分布
|
2天前
|
C语言
c语言小课设--通讯录(动态内存管理+可持久化数据)
c语言小课设--通讯录(动态内存管理+可持久化数据)