结构体
结构体变量的定义及初始化
写法1:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu s1;
strcpy(s1.name, "zhangsan");
s1.age = 18;
s1.sex = 'M';
//如果是指针操作 必须先明确指针的指向
struct Stu *p1 = (struct Stu *)malloc(sizeof(struct Stu));
strcpy(p1->name, "lisi");
p1->age = 20;
p1->sex = 'W';
写法2:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu s1 = {"zhangsan", 18, 'W'};
写法3:
struct Stu{
char name[32];
int age;
char sex;
}s1;
strcpy(s1.name, "zhangsan");
s1.age = 18;
s1.sex = 'M';
写法4:
struct Stu{
char name[32];
int age;
char sex;
}s1 = {"zhangsan", 18, 'W'};
写法5:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu s1 = {
.name = "zhangsan",
.sex = 'M'
};
写法6:
struct Stu{
char name[32];
int age;
char sex;
}s1;
s1 = (struct Stu){"lisi", 20, 'W'};
结构体数组的赋值和初始化
写法1:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu hqyj[3];//定义了一个结构体数组 定义好之后就不能整体赋值了
strcpy(hqyj[0].name, "zhangsan");
hqyj[0].age = 18;
hqyj[0].sex = 'W';
strcpy(hqyj[1].name, "lisi");
hqyj[1].age = 20;
hqyj[1].sex = 'M';
写法2:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu hqyj[3] = {
{"zhangsan", 18, 'W'},
{"lisi", 20, 'M'},
{"wangwu", 25, 'W'}
};
写法3:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu hqyj[3] = {
[0] = {"zhangsan", 18, 'W'},
[2] = {"lisi", 20, 'M'}
};
写法4:
struct Stu{
char name[32];
int age;
char sex;
};
struct Stu hqyj[3] = {
[0] = {
.name = "zhangsan",
.age = 18
},
[2] = {
.age = 20,
.sex = 'M'
}
};
结构体中可以包含其他结构体的变量
#include <stdio.h>
struct Test1{
int a;
};
struct Test2{
int b;
char c;
struct Test1 d;
//struct Test2 e;//错误的 不能包含自己结构体类型的变量
struct Test2 *p;//正确的 可以包含自己结构体类型的指针 链表中就是这样使用的
};
int main(int argc, const char *argv[])
{
struct Test2 value;
value.b = 10;
value.c = 'M';
value.d.a = 20;
printf("%d %c %d\n", value.b, value.c, value.d.a);//10 M 20
return 0;
}
结构体中可以包含函数指针
#include <stdio.h>
#include <stdlib.h>
/*
struct Test{
int a;
char b;
//C语言中 结构体中不允许定义函数 C++中可以
int my_add(int x, int y){
return x+y;
}
};
*/
int my_add(int x, int y){
return x+y;
}
int my_sub(int x, int y){
return x-y;
}
struct Test{
unsigned int a;
unsigned char b;
int (*p)(int, int);//C语言的结构体可以封装函数指针
};
int main(int argc, const char *argv[])
{
struct Test t1 = {10, 20, my_add};
printf("%d\n", t1.p(t1.a, t1.b));//30
printf("%d\n", t1.p(30, 40));//70
struct Test *p1 = (struct Test *)malloc(sizeof(struct Test));
p1->a = 100;
p1->b = 200;
p1->p = my_sub;
printf("%d\n", p1->p(p1->a, p1->b));//-100
printf("%d\n", p1->p(30, 40));//-10
free(p1);
p1 = NULL;
return 0;
}
结构体对齐
-----------------------------------64位系统--------------------------------
就是按照最大的元素进行对齐的
//sizeof(long double) == 16
struct A{
char a;
long double b;
};//–>32字节
-----------------------------------32位系统--------------------------------
64位系统将程序按32位编译, 需要加编译选项 -m32
对齐规则:
1.如果结构体中成员都是小于4字节的,按最大的成员对齐
2.如果结构体中有成员大于等于4字节,都按4字节对齐
3.要特别注意char和short连续存储的问题
结构体中包含其他结构体变量时的对齐规则:
#include <stdio.h>
struct A{
int a;
char b;
};
struct B{
struct A m;
char c;
int d;
};//16字节 因为A的大小是8字节 虽然A的成员只占用了5字节
//但是为了满足A的对齐 多分了 3个字节
//这3个字节是没法被B的成员占用的
//----------------------------------
struct C{
short a;
short b;
short c;
};
struct D{
struct C m;
char d;
int e;
};//12字节 因为结构体C是6个字节,没有因为满足自身的对齐而多分配空间
//把C放在D中的时候 为了满足D的对齐,相当于D给C多分了2个字节
//多分的这两个字节 D中的成员是可以占用的
int main(int argc, const char *argv[])
{
printf("sizeof(struct B) = %d\n", sizeof(struct B));//16
printf("sizeof(struct D) = %d\n", sizeof(struct D));//12
return 0;
}
结构体位域
结构体位域是压缩结构体的一种手段。
#include <stdio.h>
struct LED{
unsigned char led1:1;//此处是使用 :1 指定成员只占用1个bit位
unsigned char led2:1;
unsigned char led3:1;
unsigned char led4:1;
unsigned char led5:1;
unsigned char led6:1;
unsigned char led7:1;
unsigned char led8:1;
};
int main(int argc, const char *argv[])
{
printf("sizeof(struct LED) = %ld\n", sizeof(struct LED));//1
struct LED my_led;
my_led.led1 = 0;
my_led.led2 = 1;
return 0;
}
共用体(联合体)(union)
格式
union 共用体名{
类型1 成员1;
类型2 成员2;
...
类型3 成员3;
};
注意事项
1.共用体中所有的成员是共享同一块内存空间的
2.共用体所有成员的首地址都是相同的
3.共用体的大小取决于类型最大的成员
4.共用体的使用和结构体基本是一模一样的
注意:
因为共用体的所有成员共享同一块儿内存空间。修改一个成员,其他的成员的值也会一起发生变化,所以要谨慎使用。
例如:
#include <stdio.h>
#include <string.h>
typedef union Test{
char a;
short b;
int c;
}hqyj;
int main(int argc, const char *argv[])
{
printf("sizeof(hqyj) = %ld\n", sizeof(hqyj));//4
union Test v1;
hqyj v2;
memset(&v2, 0, sizeof(v2));//给v2的4个字节都赋值成 0
printf("&v2.a = %p\n", &v2.a);//一样的
printf("&v2.b = %p\n", &v2.b);
printf("&v2.c = %p\n", &v2.c);
//修改 v2 的 a成员的值为100
v2.a = 100;
//其他成员的值也会发生变化 因为用的是同一块内存空间
printf("v2.a = %d\n", v2.a);//100
printf("v2.b = %d\n", v2.b);//100
printf("v2.c = %d\n", v2.c);//100
return 0;
}
使用共用体写一个简单的代码,来测试你使用的主机是大端存储还是小端存储?
#include <stdio.h>
union Test{
int a;
char b;
};
int main(int argc, const char *argv[])
{
union Test t;
t.a = 0x12345678;
if(0x78 == t.b){
printf("小端\n");
}else if(0x12 == t.b){
printf("大端\n");
}
return 0;
}