C语言:十七、结构体


十七、 结构体

17.1 定义及初始化

  • 结构体内部,无具体数据,不分配内存
    不能进行赋值。
#include<stdio.h>

typedef unsigned long long unit64;//类型重定义
//添加typedef之前,为该数据类型的变量,添加typedef则变量名变为此种数据类型

struct Birthday
{
	int year;
	int month;
	int day;
};

struct Student//自定义数据类型,结构体
{
	char name[20];
	int age;
	struct Birthday bir;//可使用已定义的数据类型
	//struct Student a;//不可使用
	//struct Student* p;//指针可使用,多用于链表
};

/*
typedef struct Student//自定义结构体时,直接对数据类型名进行重定义
{
	char name[20];
	int age;
}Student;
*/

int main()
{
	struct Student stu1 = { "liubei",20 };//定义一个stuct Student类型的stu1变量,并初始化
	//struct Student stu2;//局部变量,未初始化

	stu1.age = 38;//访问该数据类型中的部分内容

	Student stu2 = { "caocao",18 };//C++中可省略结构体关键字,C中不能省略

	//unsigned long long a = 100;
	unit64 a = 100;//unit64 == unsigned long long,需要在前面进行typedef重命名

	return 0;
}

17.2 定义普通变量

#include<stdio.h>

struct //若省略A,则为定义了一个无名的结构体数据类型,一般可用于函数内部
{
	int a;
}C;

struct A
{
	int a;
	int b;
};//如不加typedef,则为定义了一个具有该结构体数据类型的全局变量

typedef struct B
{
	int a;
	int b;
}B;

int main()
{
	A sa, sb;
	sa.a = 10;
	sa.b = 20;
	sb = sa;//将sa中a,b的值都赋给sb
	//一个数据类型,可看做一个整体,也属于聚合,但与数组不同
	sb.a = sa.a;

	B sc;
	//sc = sa;//不属于一个数据类型
	sc.a = sa.a;

	return 0;
}

17.3 结构体指针变量

#include<stdio.h>

void Show(Student stu)
{
	printf("%s,%d\n", stu.name, stu.age);
}

void Show_1(Student* pstu)
{
	printf("%s,%d\n", (*pstu).name, (*pstu).age);//.的优先级高于*
	printf("%s,%d\n", pstu->name, pstu->age);//可使用指向符,较为方便
}

int main()
{
	Show(stu1);
	Show_1(&stu1);

	return 0;
}
#include<stdio.h>

typedef struct A
{
	int a;
	int* b;
}A;

struct B
{
	A sa;
	A* sp;
	int c;
	struct B* sd;
};

int main()
{
	B n;
	B* bp = &n;

	n.sa.a;
	n.sa.b;
	n.sp->a;//指针访问下一级用指向符
	n.sp->b;
	n.c;
	n.sd->c;
	n.sd->sd;

	bp->sa.a;
	bp->sa.b;
	bp->sp->a;
	bp->sp->b;
	bp->c;
	bp->sd;

	return 0;
}

17.4 结构体数组

#include<stdio.h>

typedef struct Student
{
	char name[20];
	int age;
}Student;

void Show(Student *p,int len)
{
	for (int i = 0; i < len; i++)
	{
		printf("%s,%d\n", p[i].name, p[i].age);
	}
}

int main()
{
	Student stu1 = { "liubei",20 };

	Student arr[3] = { {"liubei",20},{"caocao",30},{"sunquan",18} };//结构体数组

	/*
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%s,%d\n", arr[i].name, arr[i].age);
	}
	*/

	Show(arr, sizeof(arr) / sizeof(arr[0]));

	return 0;
}

17.5 结构体大小

  • 内存对齐:
    结构体成员要放在能够被自身大小整除的地址号上。
    char类型1个字节,任何地址;
    int整型4个字节,4的倍数。
    结构体大小需能够整除最大成员所占字节数
#include<stdio.h>

struct A//8个字节
{
	char a;//1+3
	int b;//4
};

struct B//8个字节
{
	char a;//1+1
	short b;//2
	int c;//4
};

struct C//24个字节
{
	char a;//1+3
	int b;//4
	int c;//4+4
	double d;//8
};

struct D//8个字节
{
	int c;//4
	char a;//1+3,接下一个int,向后对齐
};

struct E//12个字节
{
	char a;//1+3
	int b;//4
	short c;//2+2,向后对齐让int位于4的位数地址上
};

struct F//16个字节
{
	char a;//1+3
	struct GG
	{
		char b;//1+3
		int c;//4
	}g;
	int d;//4
};//考虑单个最大字节

struct H//24个字节
{
	char a;//1+7
	double d;//8
	int c;//4+4
};

struct I//12个字节
{
	char a;//1+4
	int B[2];//8
};

struct J//4个字节
{
	char a;//1+1
	struct KK
	{
		char b;
		int c;
	};//只声明了一个结构体数据类型,没有定义变量
	short d;//2
};

struct L//16个字节
{
	char a;//1+3
	struct
	{
		int b;//4
		short c;//2+2
	};//定义了一个无名的结构体数据类型的变量
	int d;//4
};

int main()
{
	printf("%d\n", sizeof(D));

	return 0;
}
  • 考虑不同内存对齐问题,填充气泡
struct B//8个字节
{
	char a;
	char x;//保留,不适用
	short b;
	int c;
};
  • 修改默认对齐大小
#pragma pack(2)//以2个字节对齐

#pragma pack()//恢复默认

17.6 结构体成员地址偏移量

int main()
{
	struct G//32个字节
	{
		char a;//1+1
		short b;//2
		int c;//4
		float d;//4+4
		double e;//8
		long long f;//8
	}G;
	printf("%d\n", sizeof(G));

    //使用成员d的地址减去结构体G的开始地址(按1个字节大小),得到相对偏移量
	int dist = ((char*)&(G.d)) - ((char*)&G);
	printf("%d\n", dist);//8
	
	
	//假定存在一个指向0地址的结构体变量G,直接强转成员d的地址,即为其偏移量
	int dist = (int)&(((struct G*)0)->d);
	printf("%d\n", dist);//8
    //将其转换为,宏函数
    #define OFFSET(type, arg) (int)&(((type*)0)->arg)
    printf("%d\n", OFFSET(struct G,d));//8
    
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值