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++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
1月前
|
编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(上)
动态内存分配与管理详解(附加笔试题分析)
49 1
|
4天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
30 12
|
1天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
25天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
36 3
|
1月前
|
程序员 编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(下)
动态内存分配与管理详解(附加笔试题分析)(下)
46 2
|
1月前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
1月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
27天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
23 0
|
1月前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
19 0