一、声明结构类型
结构是包含了一些值的集合。
结构类型声明的含义:描述了一个结构的组织布局。
e.g.
struct title {
int a;
char b [ num ] ;
} ;
注:title是结构类型的标记。
二、创建结构类型的变量
创建结构类型的变量:struct title library;
注:如果需要多次使用结构模板,就要使用带标记的形式。
三、初始化结构
e.g.
struct title library = { 15,"hello" } ;
注:使用在一对花括号中括起来的初始化列表进行初始化,各初始化项用逗号隔开。
四、访问结构类型的成员
结构成员运算符( . )
e.g. library . b
注: . 比&的优先级高。
五、结构数组
1、声明结构数组
e.g. struct title library [ MAX ] ;
2、访问结构数组成员
e.g. library [ 0 ] . b
注:library [ 0 ]是结构变量名。
3、使用结构数组的函数
#include <stdio.h>
#define FUNDLEN 50
#define R 2
struct funds
{
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};
double sum(const struct funds money [],int n);
int main()
{
struct funds account[R] = {
{
"A Bank",
5000.0,
"Hello",
1000.1
},
{
"B Bank",
4000.0,
"world",
2000.1
}
};
printf("Total is %.2f\n",sum(account,R)); //数组名是数组首元素的地址,
//所以account等价于&account[0]
return 0;
}
double sum(const struct funds money[],int n)
{
double total;
int i;
for (i=0,total=0;i<n;i++)
{
total+=money[i].bankfund+money[i].savefund;
}
return total;
}
六、嵌套结构
#include <stdio.h>
#define LEN 20
const char * msgs[5] =
{
" Thank you for the wonderful evening, ",
"You certainly prove that a ",
"is a special kind of guy. We must get together",
"over a delicious ",
" and have a few laughs"
};
struct names { // first structure
char first[LEN];
char last[LEN];
};
struct guy { // second structure
struct names handle; // nested structure
char favfood[LEN];
char job[LEN];
float income;
};
int main(void)
{
struct guy fellow = { // initialize a variable
{ "Ewen", "Villard" },
"grilled salmon",
"personality coach",
68112.00
};
printf("Dear %s, \n\n", fellow.handle.first);
printf("%s%s.\n", msgs[0], fellow.handle.first);
printf("%s%s\n", msgs[1], fellow.job);
printf("%s\n", msgs[2]);
printf("%s%s%s", msgs[3], fellow.favfood, msgs[4]);
if (fellow.income > 150000.0)
puts("!!");
else if (fellow.income > 75000.0)
puts("!");
else
puts(".");
printf("\n%40s%s\n", " ", "See you soon,");
printf("%40s%s\n", " ", "Shalala");
return 0;
}
七、结构指针
1、定义
e.g. struct title * book ;
如果book是一个title类型的结构变量名,book=&library;
注:结构名不是结构变量的地址,因此要在结构名前面加上&。
2、用指针访问成员
第一种方法:间接结构成员运算符:结构指针->成员变量
如果book=&library , 那么 book-> b等价于 library . b。
第二种方法:library [ 0 ] .b == ( *book ).b
注:必须使用(),因为 . 运算符的优先级比 * 运算符的优先级高。
即:library [ 0 ] .b == ( *book ).b == book-> b
八、结构体传参
#include <stdio.h>
struct S
{
int a;
int b
};
void print1(struct S s)
{
printf("%d\n",s.a);
}
void print2(struct S *z)
{
printf("%d\n",z->a);
}
int main()
{
struct S m = { 0, 1 } ;
print1(m);
print2(&m);
return 0;
}
注:第一个函数传递结构体;第二个函数传递结构体地址。
九、向函数传递结构信息
1、把结构作为参数传递
// 定义一个包含两个整型成员的结构体:
struct Point {
int x;
int y;
};
// 定义一个函数,接受一个Point类型的结构体变量,并打印它的成员:
void printPoint(struct Point p) {
printf("x = %d, y = %d\n", p.x, p.y);
}
// 定义一个Point类型的变量,并把它传递给printPoint函数:
struct Point p = {3, 4};
printPoint(p);
2、把结构成员作为参数传递
#include <stdio.h>
#define FUNDLEN 50
struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};
double sum(double, double);
int main(void)
{
struct funds stan = {
"Garlic-Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};
printf("Stan has a total of $%.2f.\n",
sum(stan.bankfund, stan.savefund) );
return 0;
}
/* adds two double numbers */
double sum(double x, double y)
{
return(x + y);
}
3、把结构地址作为参数传递
#include <stdio.h>
#define FUNDLEN 50
struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};
double sum(const struct funds *); /* argument is a pointer */
int main(void)
{
struct funds stan = {
"Garlic-Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};
printf("Stan has a total of $%.2f.\n", sum(&stan));
return 0;
}
double sum(const struct funds * money)
{
return(money->bankfund + money->savefund);
}
十、其他的结构特性
1、可以把一个结构赋值给另一个结构,但是数组不能。
e.g. bike = cycle;//其中book和cycle都是结构名
2、可以把一个结构初始化为相同类型的另一个结构。
e.g. struct name right = {"Tom","James"};
struct name false=right;
3、用字符数组来存储结构中的字符串,不推荐用字符指针。但是如果用malloc()分配内存并使用指针存储该地址,那么在结构中使用指针处理字符串。
十一、结构的复合字面量
语法:把类型名放在圆括号中,后面紧跟一个用花括号括起来的初始化列表。
e.g. 一个表示学生信息的结构体类型:
struct student {
char name[20];
int age;
char gender;
};
复合字面量:
struct student s = {"Tom", 18, 'M'};
e.g.还可以把复合字面量作为函数的参数。
十二、结构体内存对齐
(1)、结构体的对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到对齐数的整数倍的地址处。其中:对齐数=编译器默认的一个对齐数与该成员大小其中的较小值。注:VS中默认的对齐数值为8
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
(2)、为什么存在内存对齐
1.移植原因:
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。结构体的内存对齐是拿空间来换取时间的做法。