第五十五天学习记录:C语言进阶:动态内存管理Ⅲ

柔性数组

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

柔性数组的特点:
。结构体中的柔性数组成员前面必须至少有一个其他成员。
。sizeof返回的这种结构大小不包括柔性数组的内存。
。包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

#define _CRT_SECURE_NO_WARNINGS 1

#include 

struct S
{
	int n;
	int arr[];//未知大小的-柔性数组成员-数组的大小是可以调整的
};

int main()
{
	struct S s;
	printf("%d\n", sizeof(s));//4
	return 0;
}

第一种写法:

#define _CRT_SECURE_NO_WARNINGS 1

#include 
#include 

struct S
{
	int n;
	int arr[0];//未知大小的-柔性数组成员-数组的大小是可以调整的
};

int main()
{
	struct S* ps =(struct S*)malloc(sizeof(struct S)+5*sizeof(int));
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;//0 1 2 3 4
	}
	struct S* ptr = realloc(ps, 44);
	if (ptr != NULL)
	{
		ps = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;//5 6 7 8 9
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//释放
	free(ps);
	ps = NULL;
	return 0;
}

第二种写法(替代柔性数组):

#define _CRT_SECURE_NO_WARNINGS 1

#include 
#include 

struct S
{
	int n;
	int* arr;
};

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	ps->arr = malloc(5 * sizeof(int));
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;//0 1 2 3 4
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//调整大小
	int* ptr=realloc(ps->arr, 10*sizeof(int));
	if (ptr != NULL)
	{
		ps->arr = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;//5 6 7 8 9
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//释放
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

柔性数组的两个好处:
好处一:
方便内存释放
好处二:
这样有利于访问速度

问:柔性数组的结构体为什么前面需要有一个int?
ChatAI答:
柔性数组是指结构体中的最后一个元素是不定长数组,其长度在运行时才确定。柔性数组通常用于动态地管理一些变长数据的情况,如字符串、动态数组、缓冲区等。

在定义一个包含柔性数组的结构体时,需要保证柔性数组是结构体的最后一个元素,这是因为结构体分配内存时,其大小是根据结构体中所有元素的大小之和来确定的,而不定长数组的大小是根据运行时动态分配的,因此只有放在最后一个元素位置上才能保证整个结构体的大小是确定的。

然而,由于 C 语言没有提供直接动态定义结构体的方式,即不确定结构体的大小,所以需要为柔性数组的结构体指定一个固定大小,默认情况下为 0。这个固定大小的长度表示柔性数组前面的元素个数,一般使用 int 类型,具体大小根据实际情况而定。

例如,下面是一个包含柔性数组的结构体的示例,其中 data 是一个不定长数组,count 表示数组元素个数:

struct flex_array {
    int count;      // 柔性数组前面的元素个数
    int data[];     // 不定长数组,必须放在结构体最后
};

对于这个结构体,可以使用如下方式定义一个不定长数组:

struct flex_array* p_array = malloc(sizeof(struct flex_array) + sizeof(int) * count);
if (p_array != NULL) {
    p_array->count = count;
    // 使用柔性数组,如 p_array->data[0] = 42;
}

在使用柔性数组时,需要使用 malloc 函数同时为柔性数组和固定大小的结构体元素分配内存空间,计算内存大小时需要考虑柔性数组的元素个数。然后,可以通过指向结构体的指针进行柔性数组的访问和操作。

老师推荐值得一看的文章:
https://coolshell.cn/articles/11377.html

问:struct test t;结构体默认内部项目都是0吗?
ChatIAI答:
在C语言中,如果一个结构体变量没有被初始化,其中的每个成员变量的值是未定义的(也就是随机的)。如果你想要确保结构体中的所有成员都为0,可以使用以下方法:

  1. 在定义结构体变量时将其全部初始化,例如:
struct test t = {0};

这将把结构体中所有成员变量的值都初始化为0。

  1. 使用memset()函数将结构体变量的内存清零,例如:
struct test t;
memset(&t, 0, sizeof(struct test));

此方法将清除结构体变量的所有内存,并将其所有成员变量的值设置为0。

需要注意的是,对于复杂的结构体类型,如果其中包含指针成员变量等非基本数据类型,使用memset()将结构体变量的内存清零可能会导致内存泄漏或者指针变成野指针,因此需要特别注意。

特别注意以下代码:

#include 
#include 

struct test {
	int i;
	short c;
	char *p;
	char s[10];
};
int main() {
	struct test *pt = NULL;
	printf("&s = %x\n", pt->s); 
	printf("&i = %x\n", &pt->i); 
	printf("&c = %x\n", &pt->c);
	printf("&p = %x\n", &pt->p);
	return 0;
}

代码转自:https://coolshell.cn/articles/11377.html
问:为什么pt->s和&pt->s都可以,但是&pt->p和pt->p不一样?
ChatAI答:
在C语言中,结构体成员变量可以是基本数据类型(如int、short等)、数组或指针。对于基本数据类型和数组类型的结构体成员,它们的值都被存储在结构体的内存空间中。因此,使用&pt->i和&pt->s是等价的,它们都可以用来获取结构体成员变量i和s的内存地址。

但是对于指针类型的结构体成员变量p,它的值是一个地址,这个地址指向的是另外一块内存空间(指针所指向的内存空间)。因此,使用&pt->p可以获取指向指针变量p本身的内存地址,而不是指向p所指向的内存空间的地址。因此,pt->p和&pt->p不是等价的,它们分别表示指针变量p所指向的内存空间的地址和指针变量p本身的内存地址。如果要获取指针变量p所指向的内存空间的地址,应该使用pt->p而不是&pt->p。

问:在C语言中,为什么printf(1)报错,printf(0)不报错。
ChatAI答:
在C语言中,printf()是一个标准库函数,用于将字符串和其他数据输出到标准输出流中(通常是控制台或文件)。

当你调用printf(1)时,参数1将被视为一个整数类型的表达式。但是printf()要求第一个参数必须是格式化字符串(格式化字符串确定如何将后续参数格式化为字符串输出)。因此,编译器会报错并指出你的代码有语法错误。

当你调用printf(0)时,参数0将被视为一个NULL指针。虽然这种用法是合法的,但它不符合printf()的预期行为,因为printf()需要一个格式化字符串参数。因此,编译器不会报错,但程序可能不会按照你的期望输出任何东西。

在C语言中,函数的参数类型和数量必须与函数声明或定义一致,否则编译器会报告错误。因此,你应该使用printf()的正确格式来调用它,例如:

printf("%d", 1);

这将把1作为整数输出到控制台上。

自行摸索:

#define _CRT_SECURE_NO_WARNINGS 1

#include 
#include 

struct S
{
	int n;
	int* arr;
};

int main()
{
	struct S s = { 0 };
	struct S* p = &s;
	printf("%p\n", &s);
	printf("%p\n", &s.n);
	printf("%p\n", &s.arr);
	printf("%p\n", p);
	printf("%p\n", &p->n);
	printf("%p\n", &p->arr);
	p->arr = malloc(40);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p->arr[i] = i;//0 1 2 3 4
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", p->arr[i]);
	}
	free(p->arr);
	p->arr = NULL;
	return 0;
}

输出:
第五十五天学习记录:C语言进阶:动态内存管理Ⅲ_第1张图片

你可能感兴趣的:(编程语言学习,c语言,学习)