目录
思维导图:
1.柔性数组
1.1柔性数组的特点
1.2柔性数组的使用
1.3柔性数组的优势
2.几道经典笔试题
2.1题目1
2.2题目2
2.3题目3
2.4题目4
写在最后:
思维导图:

1.柔性数组
1.1柔性数组的特点
例:
#include <stdio.h>
typedef struct S
{
	int n;
	char arr[];//大小是未知的//这是柔性数组成员
}S;
int main()
{
	printf("&d\n", sizeof(S));//不计算大小
} 
输出:
输出:4 
柔性数组的特点:
1.结构中的柔性数组成员前面必须至少一个其他成员。
2.sizeof 返回的这种结构大小不包括柔性数组的内存。
3.包含柔性数组成员的结构用malloc函数进行内存的动态分配,
并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
1.2柔性数组的使用
例:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
//正确的写法
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
//更多的方法
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
char* GetMemory()
{
	char p[] = "hello world";
	return p;//返回栈空间的地址
}//p数组销毁了
void test()
{
	char* str = NULL;
	str = GetMemory();
	printf(str);//非法访问	
}
int main()
{
	test();
	return 0;
} 
注 :不要访问没有开辟的内存空间,非常危险。
再看一个类似的例子:
#include <stdio.h>
//类似的问题
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
void test()
{
	char* str = (char*)malloc(100);//开辟空间
	strcpy(str, "hello");
	free(str);//str释放了
	str = NULL;//主动置为空才行
	if (str != NULL)
	{
		strcpy(str, "world");//非法访问
		printf(str);
	}
} 
这样就不会出错了。
写在最后:
以上就是本篇文章的内容了,感谢你的阅读。
如果喜欢本文的话,欢迎点赞和评论,写下你的见解。
如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。
之后我还会输出更多高质量内容,欢迎收看。


















