例如:
当需要一个容器,能存储5个数据,者5个数据有1字节的,有2字节的也有4字节的时,用数组
不能满足要求了;此时需要用到结构;
1.关于结构
1)结构的定义
struct st //struct是一个关键字 st是用户自己定义的一个名字
{
//可以定义多种类型
int a;
char b;
short c;
};
2)结构的使用
void Function(person p)
{
st s; //声明一个自定义结构类型的数据;
s.a = 10; //给结构中的数据赋值
s.b = 20;
s.c = 30;
}
说明:结构体在定义的时候,除了自身以外,可以使用任何类型。
也可以再结构中使用结构;
struct st1
{
int a;
int b;
};
struct st2
{
char a;
short b;
int arr[10];
st1 s;
};
void Funtion()
{
st2 s2;
s2.a = 'A';
s2.b = 12;
s2.arr[0] = 1;
s2.arr[1] = 2;
s2.arr[3] = 3;
s2.s.a = 100;
s2.s.b = 200;
printf("%d\n",s2.s.a);
}
3)结构作返回值
代码:
struct student{
char sex;
int age;
int score;
};
student fun()
{
student s;
s.sex = 1;
s.age = 12;
s.score = 100;
return s;
}
int main(int argc, char* argv[])
{
student s = fun();
getchar();
return 0;
}
反汇编:
调用fun函数前:
如果要返回一个结构,外层函数在编译时会给返回值预留空间;
此时push进去的就是外层函数用来存储返回值的地址;
返回值:
总之:
将结构体作为参数或返回值时,需要对一大片内存来回复制,非常消耗内存;
最好不要用结构体当参数或返回值;
可以将结构体定义为全局变量,或者用指针;
2.sizeof函数
sizeof函数用来获取类型或数据的字节数;
1)基本类型的sizeof,可以使用类型,也可以使用变量
printf("%d\n",sizeof(char));
printf("%d\n",sizeof(short int));
printf("%d\n",sizeof(int));
printf("%d\n",sizeof(long int));
printf("%d\n",sizeof(__int64));
printf("%d\n",sizeof(float));
printf("%d\n",sizeof(double));
int x = 10;
printf("%d\n",sizeof(x));
2)数组类型的sizeof
char arr1[10] = {0};
short arr2[10] = {0};
int arr3[10] = {0};
printf("%d\n",sizeof(arr1));
printf("%d\n",sizeof(arr2));
printf("%d\n",sizeof(arr3));
printf("%d\n",sizeof(arr1[10]));
printf("%d\n",sizeof(arr2[10]));
printf("%d\n",sizeof(arr3[10]));
3)结构体类型的sizeof
struct S1
{
char a;
int b;
char c;
};
struct S2
{
int a;
char b;
char c;
};
int main(int argc, char* argv[])
{
S1 s1;
S2 s2;
printf("%d\n",sizeof(s1));
printf("%d\n",sizeof(s2));
printf("%d\n",sizeof(S1));
printf("%d\n",sizeof(S2));
return 0;
}
3.结构对齐
1)结构体的大小
例如:下面的结构sizeof获得的结果为24
struct Test
{
int a ;
__int64 b ;
char c ;
char d ;
};
而相同的结构,调换了成员顺序后sizeof的结果为16
struct Test
{
__int64 b ;
int a ;
char c ;
char d ;
};
产生这一现象的原因是结构的数据对齐;
2)为什么有结构对齐
本质上是效率和空间二选一的结果;
3)对齐参数
对齐参数:n为字节对齐数,其取值为1、2、4、8,默认是8。
如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,
即是说,结构体成员的偏移量应该取二者的最小值.
自定义对齐参数的代码:将结构体的对齐参数设为n
#pragma pack(n)
结构体
#pragma pack()
例如:同样的结构在不同对齐参数下的内存空间
4)vc6中设置默认对齐参数
项目右键-->setting-->C/C++-->Code Generation
如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,
即是说,结构体成员的偏移量应该取二者的最小值,
5)对齐原则
原则一:数据成员对齐规则:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从
该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储).
原则二:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
原则三:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储.)
原则四:对齐参数如果比结构体成员的sizeof值小,该成员的偏移量应该以此值为准.
也就是说,结构体成员的偏移量应该取二者的最小值.
6)结构对齐案例
7)建议
为了节省内存空间;建议结构中的成员按照数据类型由小到大的顺序进行书写
4.typedef
typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。
这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
1)对已有类型定义别名
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
2)一维数组类型的定义格式
typedef int vector[10];
int main(int argc, char* argv[])
{
vector v;
v[0] = 1;
v[1] = 2;
v[2] = 3;
v[3] = 4;
v[4] = 5;
return 0;
}
3) 二维数组类型的定义格式
typedef int name[5][5];
typedef int nameTable[5][5][5];
int main(int argc, char* argv[])
{
name v;
nameTable n;
v[0][0] = 1;
v[0][1] = 2;
v[0][2] = 3;
v[0][3] = 4;
v[0][4] = 5;
n[0][0][0] = 1;
return 0;
}
4)结构体的定义格式
typedef struct student
{
int x;
int y;
}stu;
5.给字符数组赋值
如果在c语言中想要保存字符串,可以用char数组;
头文件string.h中的strcpy函数可以用来给字符数组赋值;
步骤:
第一步: #include "string.h"
第二步:
char arr[10];
strcpy(arr,"中国");
例如:
#include "stdio.h"
#include "string.h"
typedef struct student{
char sex;
int age;
int score;
char name[30];
}stu;
void fun()
{
stu s[5]; //结构数组
s[0].sex = 'M';
s[0].age = 12;
s[0].score = 100;
strcpy(s[0].name, "张三");
printf("sex:%c,age:%d,score:%d,name:%s",s[0].sex,s[0].age,s[0].score,s[0].name);
}
int main(int argc, char* argv[])
{
fun();
getchar();
return 0;
}