分享一个结构体指针动态分配内存的C语言程序

C语言中不支持用变量来定义数组的个数,因此C语言中想要动态分配内存,常用的方法是指针+malloc()\calloc()\realloc()的方式。

这里仅针对结构体指针+calloc()实现“动态结构体数组”。这里之所以称之为”动态结构体数组“,是因为该种方法定义出来的本质上不是结构体数组,当在功能上却与结构体数组无大异。

同时在该程序中,我将结构体中的字符串数组全部定义为字符指针变量,并在其赋值时利用函数先为该字符指针变量分配最佳内存。

由此,利用该"动态结构体数组",达到了内存的最佳利用。

程序中有详细的注释,有出错的地方,还望大家给予指正,下面附上代码。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
/***
	0 - 结构体指针动态分配内存;1 - 静止结构体变量、数组  **/ 
#define MODE 0
/*******  技能结构体  ********/
typedef struct _skill
{
	char* pSkill_1;
	char* pSkill_2;
}structSkill;
/*******  英雄结构体(嵌套了技能结构体)  *******/
typedef struct _hearo
{
	int   id;
	char*  pName;
	int   age;
	char*  pPhone;
	
	structSkill sSkill;
}structHearo;
/************************************************************************/
/* 验证利用结构体指针传递函数形参的函数                                   */
/************************************************************************/
void Test( structHearo* spH )
{
	spH->age = 100;
	strcpy( spH->pName, "广州" );   // 这个地方传递了5个字节给地址pName所指的内存,倘若当时为pName所分配的内存小于5,则在释放该指针所指内存时会报错
}
/************************************************************************/
/* 获得包含结束符字符串的实际长度(相对应与定义长度);
   注意,由于gets()得到的是以'\n'结束的字符串,暂不支持对其获得的字符串进行测量!
   输入:想要测量长度的字符串地址;输出:测量得到的字符串实际长度       */
/************************************************************************/
int Get_String_LEN( char* str )
{
	int i;
	for( i=0; i<50; i++ )
	{
		if( str[i] == '\0' )
			return i+1;
		else ;
	}
	return 0;
}
/************************************************************************/
/* 主函数                                                               */
/************************************************************************/
int main( )
{
	int i, num;
	char aTempName[50];   // 此字符数组做中间数组,用于姓名\电话号码长度的测量,应定义足够大
	/***
		定义结构体数组,并初始化  **/
	structHearo saHearo[2] = { {9527, "唐伯虎", 250, "13843818438", {"放屁", "飞天"}},
				   {9528, "点秋香", 16,  "52020205200", {"化妆", "美颜"}} 
							 };
#if MODE == 0    // 结构体指针动态分配内存模式
	/***
		定义结构体指针变量 **/
	structHearo* spHearo;
	printf("\n");
	printf("请输入想要添加的英雄个数:");
	scanf( "%d", &num );   // 获取英雄个数,用于结构体指针动态分配内存
//	spHearo = (structHearo*)malloc(sizeof(structHearo)*num);
	spHearo = calloc( num, sizeof(structHearo) );

	printf("%d\n", _msize(spHearo) );   // 该函数可以获取指针所指区域的字节大小
	/***
		循环打印结构体数组中的内容  **/
	printf("系统自带英雄:编号\t名字\t年龄\t电话\t\t技能\n");
	for( i=0; i<2; i++ )
	{
		printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
			   saHearo[i].id,saHearo[i].pName,saHearo[i].age,saHearo[i].pPhone,saHearo[i].sSkill.pSkill_1,saHearo[i].sSkill.pSkill_2 );
	}
	printf("\n");
	for( i=0; i<num; i++ )
	{
		printf("请输入自定义英雄%d信息:\n", i );
		printf("编号:");
		scanf_s( "%d", &((spHearo+i)->id), 4 );
		printf("姓名:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		spHearo[i].pName = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		//printf("%d\n", Get_String_LEN( aTempName ) );
		//printf("%d\n", _msize( spHearo[i].name ) );  // 可以取消该两处注释,看一下结构体中的指针变量的内存空间分配情况
		strcpy_s( spHearo[i].pName,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( spHearo[i].pName ) );

		printf("年龄:");
		scanf_s( "%d", &(spHearo[i].age), 4 );

		printf("电话:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		spHearo[i].pPhone = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( spHearo[i].pPhone,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( spHearo[i].pPhone ) );

		printf("技能1:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		spHearo[i].sSkill.pSkill_1 = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( spHearo[i].sSkill.pSkill_1,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( spHearo[i].sSkill.pSkill_1 ) );

		printf("技能2:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		spHearo[i].sSkill.pSkill_2 = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( spHearo[i].sSkill.pSkill_2,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( spHearo[i].sSkill.pSkill_2 ) );
	}
	printf("%d\n", _msize(spHearo) );

	printf("自定义  英雄:编号\t名字\t年龄\t电话\t\t技能\n");
	for( i=0; i<num; i++ )
		{
			printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
				   spHearo[i].id,spHearo[i].pName,spHearo[i].age,spHearo[i].pPhone,spHearo[i].sSkill.pSkill_1,spHearo[i].sSkill.pSkill_2);
		}

	Test( spHearo );
	printf("更改后自定义英雄:编号\t名字\t年龄\t电话\t\t技能\n");
	for( i=0; i<num; i++ )
	{
		printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
			spHearo[i].id,spHearo[i].pName,spHearo[i].age,spHearo[i].pPhone,spHearo[i].sSkill.pSkill_1,spHearo[i].sSkill.pSkill_2);
	} 

	for( i=0; i<num; i++ )
	{
		free( spHearo[i].sSkill.pSkill_1 );
		spHearo[i].sSkill.pSkill_1 = NULL;
		free( spHearo[i].sSkill.pSkill_2 );
		spHearo[i].sSkill.pSkill_2 = NULL;
	}
	for( i=0; i<num; i++ )
	{
		free( spHearo[i].pName );
		spHearo[i].pName = NULL;
		free( spHearo[i].pPhone );
		spHearo[i].pPhone = NULL;
	}
	free( spHearo );    // 释放内存空间
	spHearo = NULL;     // 空指针

#elif MODE == 1    // 静止结构体变量、数组 
	/***
		定义2组结构体;由于c语言中不可以以变量定义数组个数,因此直接定义结构体数组,不能动态构建结构体数组的个数  **/
	structHearo sHearo[2];     
	/*****	循环打印结构体数组中的内容  ***/
	printf("系统自带英雄:编号\t名字\t年龄\t电话\t\t技能\n"); 
	for( i=0; i<2; i++ )
	{
		printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
			   saHearo[i].id,saHearo[i].pName,saHearo[i].age,saHearo[i].pPhone,saHearo[i].sSkill.pSkill_1,saHearo[i].sSkill.pSkill_2 );
	}
	/*****	动态录入结构体变量中的成员值  ***/
	printf("\n");
	for( i=0; i<2; i++ )
	{
		printf("请输入自定义英雄%d信息:\n", i+1 );
		printf("编号:");
		scanf_s( "%d", &(sHearo[i].id), 4 );

		printf("姓名:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		sHearo[i].pName = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		//printf("%d\n", Get_String_LEN( aTempName ) );
		//printf("%d\n", _msize( spHearo[i].name ) );  // 可以取消该两处注释,看一下结构体中的指针变量的内存空间分配情况
		strcpy_s( sHearo[i].pName,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( sHearo[i].pName ) );

		printf("年龄:");
		scanf_s( "%d", &(sHearo[i].age), 4 );

		printf("电话:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		sHearo[i].pPhone = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( sHearo[i].pPhone,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( sHearo[i].pPhone ) );
		
		printf("技能1:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		sHearo[i].sSkill.pSkill_1 = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( sHearo[i].sSkill.pSkill_1,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( sHearo[i].sSkill.pSkill_1 ) );
		
		printf("技能2:");
		scanf_s( "%s", aTempName, 50 );      // 先将字符串存放在中间字符串变量下
		/***
			将该中间字符串变量送去测长度,并将返回的长度用于结构体数组下的指针变量的空间分配  **/
		sHearo[i].sSkill.pSkill_2 = calloc( Get_String_LEN( aTempName ), sizeof(char) ); 
		strcpy_s( sHearo[i].sSkill.pSkill_2,  Get_String_LEN( aTempName ), aTempName ); // 采用字符串复制函数为结构体中的字符串赋值
		printf("%d\n", _msize( sHearo[i].sSkill.pSkill_2 ) );
	}

	printf("自定义  英雄:编号\t名字\t年龄\t电话\t\t技能\n");
	for( i=0; i<2; i++ )
	{
		printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
			sHearo[i].id,sHearo[i].pName,sHearo[i].age,sHearo[i].pPhone,sHearo[i].sSkill.pSkill_1,sHearo[i].sSkill.pSkill_2);
	}

	Test( sHearo );
	printf("更改后自定义英雄:编号\t名字\t年龄\t电话\t\t技能\n");
	for( i=0; i<2; i++ )
	{
		printf("              %-4d\t%-6s\t%-3d\t%s\t%-4s %-4s\n", 
			sHearo[i].id,sHearo[i].pName,sHearo[i].age,sHearo[i].pPhone,sHearo[i].sSkill.pSkill_1,sHearo[i].sSkill.pSkill_2);
	}
	for( i=0; i<2; i++ )     // 释放内存
	{
		free( sHearo[i].sSkill.pSkill_1 );
		sHearo[i].sSkill.pSkill_1 = NULL;
		free( sHearo[i].sSkill.pSkill_2 );
		sHearo[i].sSkill.pSkill_2 = NULL;
	}
	for( i=0; i<2; i++ )   // 释放内存
	{
		free( sHearo[i].pName );
		sHearo[i].pName = NULL;
		free( sHearo[i].pPhone );
		sHearo[i].pPhone = NULL;
	}
#endif
	return 0;
}

本程序,倾注了笔者的不少心血。未经作者允许,严禁转载与商用!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值