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;
}
本程序,倾注了笔者的不少心血。未经作者允许,严禁转载与商用!!