一. 结构类型:
1. 概念: 结构由一组不同的数据组成的.
2. 定义: struct 结构名
{
数据类型 成员名1;
数据类型 成员名2;
……
数据类型 成员名n;
};
例如:
struct person{
char Name[100] ;
int Age ;
char Sex ;
};
二. 结构变量的定义和初始化:
1. 定义: struct person Wang ;初始化: struct person Wang = {…} ;
2. 定义:
struct person
{
…;
}Wang ;※ 当结构名不写的时候, 必须用第二个定义方法.
三. 指向结构变量的指针:
(1). 一般形式为: 结构名 *结构指针变量名; (相当于声明)
结构名 *结构指针变量名=&结构变量; (相当于定义)
如: struct stPerson *pWang = &Wang ;
①. 静态内存初始化:
a. struct stPerson *pWang = {…} ; // 错误!
b. struct stPerson Wang = {…} ;
*p= Wang ; // 正确.
②. 动态内存初始化:
struct stPerson *pWang = (structstPerson*) malloc ( sizeof(struct stPerson) ) ;
strcpy( pWang->m_szName,“laoWang” ) ; // 赋值.
pWang->m_nAge= 30 ;
pWang->m_chSex= ’M’ ;
※ struct stPerson *pWang = (structstPerson*) malloc ( sizeof(struct stPerson)* X ) ;
X意义: 要存的结构的数量, 比如说要存三个人的资料, 就写3.
清零:1. memset( pWang, 0, sizeof(structstPerson) ) ; // 清整个结构.
memset(pWang->m_szName, 0, sizeof( pWang->szName) ) ; // 清结构内的单个成员.
2. 利用数组: struct stPerson array[3]={0};
(4). 对结构用函数来初始化(跟赋值一样):
void InitPerson( struct stPerson* _person)
{
memset(_person->m_pName, '\0', 100 ) ;
_person->m_nAge= 0 ;
_person->m_chSex= '\0' ;
}
(5). 嵌套结构的初始化:
struct stDate
{
int nYear ;
int nMonth ;
int nDay ;
};
struct stPerson
{
char m_szName[100] ;
int m_nAge ;
char m_chSex ;
structstDate m_Birthday ; // 注意嵌套定义的格式.
};
struct stPersonWang = { “laowang”, 30, ‘M’, {1999, 3, 10} } ; // 多一层嵌套就多一个大括号.
(6). 结构里双重指针的内存申请和释放:
struct stPerson
{
char *m_pName ;
char m_chSex ;
int nAge ;
} ;
struct stPerson *pWang = (struct stPerson*)malloc ( sizeof (structstPerson) ) ;
pWang->m_pName = (char*)malloc (sizeof(char)*100 ) ;
pWang->m_pName = NULL ; // 可以不写.strcpy( m_pName, “laoWang” ) ;
free( pWang->pName ) ; // ①
free(pWang) ; //②
pWang = NULL ;
(7). 结构可以嵌套定义, 不能递归定义.
struct A
{
int n;
A a; // 死循环.
}
三. 结构变量成员的访问:
一般形式为: 结构变量名.成员名 如:
_person.szName
如果成员本身又是一个结构, 则必须按层寻找(嵌套访问):
_person.birthday.nYear 或 _person->birthday.nYear
四 计算结构体长度:
1. 在数据在内存按顺序排列,存储顺序和定义先后次序相同.
2. 以最大的成员长度为单位,给分配结构体分配内存, 而且是按顺序从上往下排(自动补齐原则):
(1). struct stPerson
{
char a; //sizeof结果为16. 因为是按double来分的, a和b是同类型的,
char b; 挨着存都能存进8字节中(只要不超出就算8个char 也一样)
doubled;
}
(2). struck stPerson
{
char a; //sizeof结果为16. 虽然a.b.c是不同类型的, 在第一个8字节里, a.b为同类型, 他们一共分了4个字节,
char b; 剩下的4字节给了c.
double d; int c;
}
(3). struck stPerson
{
char a; //sizeof结果为24. 不同类型的排列会各分8个字节, 所以以后排列的时候尽量同类型的排列在一块.
char b; int c;
double d;
}
3. 数据的尾地址和分配单元的尾地址之差必须是这个数据长度的整数倍。(数据的首地址到分配单元的首地址之间的空间必须是这个数据长度的整数倍)
4. 空结构体占有一个字节的空间。
struct Person
{ //sizeof(Person) 等于 1.
};
总结:
(1). 结构体成员可以跨分配单元存放。
(2). 整个结构的分配单元大小是由所有单独的成员中最大的长度决定。
(3). 给结构体分配空间时,保证可能结构体数组的连续性。
分析方法:先分析结构体成员内存情况,再分析它再结构体中的分配情况。
五. 结构数组:
1. 定义: struct 结构名 数组变量[]={ {}, {},{}…{} };
2. 指向结构数组的指针: 指针可以指向一个结构数组, 用法和以前一样, 只不过是结构指针变量的值是整个结构数组的首地址而已.
六. 结构指针变量作函数参数:
1. 将整个结构作为参数传递(值传递):
void ShowData( structsePerson person)
2. 将结构的地址作为参数传递(地址传递):
void ShowData( structstPerson* _person )
※ 尽量用地址传递, 因为如果结构在栈区的话, 由于数据太大, 整个数据传过去会很慢.
七. typedef关键字的使用:
意义: 是为了给数据类型起个别名.
格式: typefef 原类型名 新类型名(一般用大写表示);
1. 数组用法:typedef char NAME[30];
NAME a; <==> chara[30];
2. 函数用法: void (*p)( int,int )=&f;
typedef void(*p FEUN)(int, int);
PEUN p=&f;
3. 结构用法:typedef strust stPerson
{
…;
}PERSON;
4. (1). typedef和#define的区别:
struct P
{
};
#define P * S
typedef P * S2;
S a, b; <==> P * a, P b;
S2 a, b; <==>P *a, p* b;
总结: 前者有类型, 只是类型用别名代替了, 而后者没有类型, 只是单纯的替换.
(2). typedef和#define的优点:
#define 可以使用 #ifdef, #ifndef等来进行逻辑判断, 还可以使用#undef来取消定义.
typedef: 它符合范围规则, 使用它定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而#define则没有这种特性.