前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于结构体的问题

关于结构体的问题

作者头像
薛定谔方程难
发布2024-01-23 16:18:56
840
发布2024-01-23 16:18:56
举报
文章被收录于专栏:我的C语言我的C语言

知之愈明,则行之愈笃;行之愈笃,则知之益明。——朱熹(宋)

1、结构体定义问题

代码语言:javascript
复制
struct student
{
	int age;
	int height;
	char name[100];
};

这一段,就是定义结构体类型,也就是相当于是,别的类型一样,就比如int,float之类,但是此时只是类型,还没有变量,只有定义了变量才能使结构体类型有存在。也只有创建变量之后,结构体类型才是在内存中创建了空间,在空间中存放age,height,name。 要想怎么创建变量,有两种方法分别是 代码1

代码语言:javascript
复制
struct student
{
	int age;
	int height;
	char name[100];
}n1,n2;

但是这段代码,算的上是匿名的结构体,不能够使用多次,也就是说,在结构体变量命名的时候也就确定了,只能是n1和n2,这两个,也不会有别的变量能够使用了。并且此时的n1和n2都是全局变量。 代码2

代码语言:javascript
复制
struct student
{
	int age;
	int height;
	char name[100];
};
int main()
{
	struct student n3, n4;
	return 0;
}

这都是可以的。 ==再次说明:==在代码1中,struct student中student是定义的结构体的类型名,而其中的n1,n2是定义的结构体类型变量,不是名称,如果想要让stu为结构体类型名称时,必须在结构体定义时添加typedef关键字

代码语言:javascript
复制
struct student
{
	int age;
	int height;
	char name[100];
}*ps;
struct student
{
	int age;
	int height;
	char name[100];
}*s;
int main()
{
    ps=&s;
}

那这里,关于ps和s的能不能成功的相等呢?就算是两个的结构体里面的成员是一模一样的呢? 结果其实是不可以的,关于编译器来说,就算是一模一样的内容,那也是不一样的结构体

2、结构体访问成员的操作符

关于结构体访问成员的操作符,在定义的时候,就是可以用到两个,这两个也是在初始化结构体变量的时候起到重大作用的。(因为结构体里面的存放的不止一个数据,那么说明肯定不能只定义一下,所以要像数组一样用大括号进行初始化)

代码语言:javascript
复制
int main()
{
	struct student n3 = {20,120,"wangwu"};
	return 0;
}

那其实这段是没有什么操作符使用的,而且初始化的时候还必须要按照顺序,那么要是想不按照顺序,那么还可以怎么初始化呢?

代码语言:javascript
复制
int main()
{
	struct student n4 = { .height = 244,.age = 12,.name = "wangwu" };
	return 0;
}

这样的初始化,就用到了,一个重要的操作符==.,并且还能根据自己想要的顺序进行初始化。那么其实关于这个操作符,还有一个->==,关于这个操作符来说,这个就是相当于在打印的时候使用的

代码语言:javascript
复制
int main()
{
    struct student n4 = { .height = 244,.age = 12,.name = "wangwu" };
    printf("%d",n4->height);//printf("%d",n4.height)
	return 0;
}

就是大概这么使用的,当然也还可以用之前的操作符。 当然还有一个操作符也是可以用到的。

代码语言:javascript
复制
int main()
{
	struct student n4 = { 10,230,"zhangsan" };
	struct student* pst = &n4;
	printf("%d\n", (*(pst)).height);
	printf("%d\n", pst->height);
	return 0;
}

那就是解引用操作符。关于打印的那两句话,效果是一样的,而且在第一段的打印的时候,必须要是加上括号,不然的话.的优先级是高于解引用的。 就比如下面这段题目。

代码语言:javascript
复制
#include < stdio.h >
struct S
{ 
  int a;
  int b; 
};
int main( )
{ 
  struct S a, *p=&a;
  a.a = 99;
  printf( "%d\n", __________);
  return 0;
}

如果想打印关于结构体中成员a的数据,在printf中,我们应该写什么呢? 其实这样的话答案是有三种的 *1、a.a 2、p->a 3、(p).a 那么就还有一种典型的错误,那就是 *p.a,这是完全不对的。

3、结构体的所占内存空间

在这里插入图片描述
在这里插入图片描述

当然要是想要修改对齐数的话也是可以的,就要使用

代码语言:javascript
复制
#pragma pack(x)

其中x就是修改后的对齐数。 那么为什么要用到对其呢?为什么就是这样呢?

  1. 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定 类型的数据,否则抛出硬件异常。
  2. 性能原因: 数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要 作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以 ⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两 个8字节内存块中。 总体来说:结构体的内存对⻬是拿空间来换取时间的做法。 大抵上就是这样子的。

4、和之前的联系

代码语言:javascript
复制
struct S
{
	int data[1000];
	int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{
		printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s); //传结构体
	print2(&s); //传地址
	return 0;
}

那么关于结构体传参的时候到底是使用什么更好呢?是传址,还是传值? 其实,问这问题的时候,就是要看传值和传址的根本本质是什么了。其实传址就是把地址给过去,通过首地址,来一个个的访问。传值可就不一样了,还会创建形参,临时拷贝,那么拷贝的量就是相当的大了,这样就会消耗大量的时间和空间,会导致代码的不好,所以,还是传址是更好的选择。

5、结构体实现位段

代码语言:javascript
复制
struct A
{
   int a:2;
   int b:4;
   int c:10;
}

这是位段的代码形式。 虽然位段是可以节省空间的,但是关于位段,有很多不确定的因素使得位段是不能跨平台使用的,在注重可移植的程序应该避免使用位段。 1、当开辟了内存的时候,内存中的每个比特位从左向右,还是从右到左都是不确定的。 2、当之前剩余的空间不足的时候,下一个成员使用的时候,剩余空间是否使用是不确定的。

5、1位段的应用

在这里插入图片描述
在这里插入图片描述

5、2位段使用的注意

由于位段,使得每一个元素其实并不是独立占用一个字节,每一个字节可能都不是一个变量的初始地址,所以不能用scanf直接给位段的成员输入值,只能先输入放在一个变量中,然后在赋值给位段的成员。

代码语言:javascript
复制
struct A
{
	int a : 2;
	int b : 10;
	int c : 23;
};
int main()
{
	int b = 0;
	scanf("%d", &b);
	struct A sa = { 0 };
	sa.b = b;
	//scanf("%d",&sa.b);这是错误的。
	return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、结构体定义问题
  • 2、结构体访问成员的操作符
  • 3、结构体的所占内存空间
  • 4、和之前的联系
  • 5、结构体实现位段
    • 5、1位段的应用
      • 5、2位段使用的注意
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档