C语言细节 - 指针与结构体 -待完成

本文是读完《c和指针》后记录的一些关于结构体和指针中值得注意的细节,如有错误,还望指正;你还可以阅读指针指针与数组指针与函数了解更多关于指针的内容

结构体中的标签

首先我们来看一下不使用标签的一个示例:

struct {
    int a;
    float b;
    char c;
}x1;

struct {
    int a;
    float b;
    char c;
}x2, *x3;

int main(void)
{
    x3 = &x1;
    printf("%c\n",x3->c);
    
    return 0;
}

编译结果:显示指针类型赋值错误
在这里插入图片描述
将主函数修改为:

int main(void)
{
    x3 = &x2;
    printf("%c\n",x3->c);
}

编译结果:
在这里插入图片描述

  • 原因 : 变量 x1 和 x2 被编译器当成了两个不同类型的结构体,即使成员列表完全相同

然后我们将上面的结构体加上标签:

struct test{
    int a;
    float b;
    char c;
};

struct test x1={1,1.0,'c'};
struct test x2={2,2.0,'b'},*x3;

int main(void)
{
    x3 = &x1;
    printf("%c\n",x3->c);
}

编译结果:
在这里插入图片描述
以上说明标签字段允许为成员列表提供一个名字,他允许多个声明使用同一个成员列表,并创建同一种类型的结构



结构体类型定义

以上结构体的定义和变量的定义方法还有以下几种:

typedef struct test{
    int a;
    float b;
    char c;
}tmp;

tmp x1={1,1.0,'c'};
tmp x2={2,2.0,'b'},*x3;
typedef struct {
    int a;
    float b;
    char c;
}tmp;

tmp x1={1,1.0,'c'};
tmp x2={2,2.0,'b'},*x3;

这里要强调的一点是:在使用typedef为结构创建类型名时,该类型名在结构体成员变量之后创建;如下陷阱:

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

这里创建了一个成员变量b,指向结构体tmp,但是在声明b时,tmp还未定义,故表述非法
利用标签可解决上述问题:

typedef struct test{
	int a;
	struct test *b;
}tmp;

在一个结构体内部不能包含类型为该结构体本身的成员,如下:

struct test1{
	int a;
	struct test1 b;
	struct test1 *c;
};
  • 因 b 的类型与它所处结构体类型一致,故这种表述是错误的
  • c为指针类型,故这种表述是合法的 b

在结构体类型定义前,可以先进行不完整定义,如下示例:

struct B;

struct A{
	struct B *p;
};

struct B{
	struct A *p;
};


优先级说明

在结构体中 ->符 享有优先权
(->操作符) > (点操作符 . ) > (间接访问操作符 * )
(->操作符) > (取地址符 & )

  • void func(struct test *p);内你需要这个括号:(*p).a,这等价于 p->a
  • *p->a.b 相当于 *((p->a).b)
  • &p->a 相当于 &(p->a)


结构体的指针运算

参考这篇文章



结构体作为函数参数

结构体传参时一般都使用指针传参

  • 原因: 普通传参(传递结构)需要对数据进行拷贝,当结构体成员很多时,需要拷贝的量非常大,效率低,占用堆栈空间
  • 改进:
    - 为提高速度:可声明为 register
    - 为防止修改:可声明为 const


结构体位段的使用

  • 位段成员必须声明为int型 (int, unsigned int, signed int),最好显式声明为unsigned int 或 signed int
  • 因在不同系统中位段的结果可能不同,故应尽量不免使用位段,提升代码可移植性
struct test{
    int a:7;
    int b:6;
    int c:19;
}x;

int main(void)
{
    printf("%d\n",sizeof(x));
}

结果为:
在这里插入图片描述
该结构可处理128个字符,64种字体,0-524287个单位长度



通过指针常量访问结构体

struct test{
    int a:7;
    int b:6;
    int c:19;
};

#define A ((struct test *)0x0060fefc)

int main(void)
{
    A->a = 42;
    printf("%d\n",A->a);
}

输出为:
在这里插入图片描述



联合

  • 使用情况:不同时刻,将不同的东西存放在同一内存位置
  • 联合的所有成员引用内存种的相同位置
  • 若联合体内各成员的长度不一致,分配给联合的内存数量取决于最长成员的长度
  • 对于第三点会有一个问题:当成员大小相差悬殊,当存储较小成员时,则浪费空间,解决办法是存储指向不同成员的指针
  • 联合变量被初始化时,初始化值必须是联合第一个成员的类型,位于花括号中
union{
    float i;
    int j;

}test={3.14};


int main(void)
{
    float reference = 3.14f;

    printf("%d\n",(int)reference);
    printf("%d\n",test.j);
}

结果为:
在这里插入图片描述



字节对齐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

|清风|

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值