C语言——结构体指针

结构体指针

定义:

结构体类型的指针变量指向结构体变量或者数组的起始地址。

语法:

struct 结构体名*指针变量列表;

举例:

struct Dog

{
        char name[20];
        int age;
};
struct Dog dog;
struct Dog *p = &dog;

结构体成员访问

格式:

结构体数组名->成员名;

结构体成员访问符

.    :左侧是结构体变量(结构体对象/实例),也可以叫做结构体对象访问成员符;右侧是结构体成员。

->:左侧是一个指针,可也以叫结构体指针访问成员符;右侧是结构体成员。

访问结构体成员有两种类型,三种方式:

类型1:通过结构体对象访问成员

struct Stu

{
        int id;
        char name[20];
} stu;
//访问成员
stu.name;

类型2:通过结构体指针访问成员

1.指针引用访问成员
struct Stu
{

        int id;
        char name[20];
}stu;

struct Stu *p = &stu;
p -> name;

2.指针解引用间接访问成员
struct Stu
{

        int id;        

        char name[20];
}stu;
struct Stu *p = &stu;

//指针解引用间接访问成员
(*p)-> name;

结构体数组中元素的访问

struct Stu
{
        int id;
        char name[20];
        float scores[3];
}  stus[3]={
        {1,"张三",{86,88,56}},
        {2,"李四",{75,66,78}},
        {3,"王五",{70,99,90}}
                };
//取数据        下标法
printf("%s,%2f\n",stus[1].name,stus[1].scores[2]);//李四,78
//结构体成员引用符号:->指针法
printf("%s,%2f\n",stus->name,stus ->scores[2]);// 张三,56

printf("%s,%2f\n",(stus +1)->name,(stus +1)->scores[2]);// 李四,78

printf("%s,%2f\n",(*(stus + 1))->name,(*(stus + 1))-> scores[2]);// 李四,78

小贴士:

1)结构体是自定义数据类型,它是数据类型,用法类似于基本类型的int;

2)结构体数组它是存放结构体对象的数组,类似于int数组存放int数据;

3)基本类型数组怎么用,结构体数组就怎么用--->可以遍历,可以作为形式参数,也可以作为指针等。

eg:

#include <stdio.h>

// 定义结构体
struct Cat
{
    char *name;// 姓名
    int age;// 年龄
    char color[20];// 颜色
}
// 1.结构体类型作为形式参数
void test1(struct Cat c);

// 2.结构体类型作为形式参数,结构体类型作为返回值类型
struct Cat test2(struct Cat c);
// 3.结构体数组作为形式参数
void test3(struct Cat cats[],int len);
// 4.结构体数组作为形式参数,结构体指针作为返回值数据类型21struct Cat *test4(struct Cat cats[],int len);

测试:

int main()
{
    // 定义结构体对象
    struct Cat cat = {"小黑",8,"baise"};
    // 结构体对象作为实际参数
    test1(cat);
    
    // 定义结构体类型对象
    struct Cat cat1 = {"小白",8,"heise"};
    // 调用函数并接收返回值
    struct Cat c1 = test2(cat1);
    // 通过返回值访问结构体对象的成员

    printf("%s==%d==%s\n",c1.name,c1.age,c1.color);
    
    // 定义结构体数组
    struct Cat cats[3] = {
        {"汤姆",16,"蓝色"},
        {"杰瑞",18,"褐色"},
        {"唐老鸭",19,"白色"}
    };
    // 结构体数组名作为实际参数
    test3(cats,3);
    
    // 定义结构体数组并初始化
    struct Cat cats1[3] = {
        {"汤姆",16,"蓝色"},
        {"杰瑞",18,"褐色"},
        {"唐老鸭",19,"白色"}
    };
    // 调用函数
    struct Cat *p = test4(cats1,3);
    struct Cat *w;
    // 通过指针运算遍历数组
    for(w = p; w < p + 3; w ++)
    {
        // p[i][j] = *(p[i]+j) = *(*(p+i)+j) 三者等价
        // 通过结构体指针访问符访问结构体的成员
        printf("%s----%d----%s\n",w -> name,w -> age,w -> color);39    }
}

结构体类型求大小

规则:字节对齐(数据在内存中存储在其类型大小的整数倍上)

1.首先保证结构体中的成员存储在自身的对齐边界(类型大小的整数倍);

2.在满足1的条件下,最终大小要满足最大成员所占存储单元的整数倍;

为什么要使用字节对齐:

节省内存,提高访问效率

在GNU标准中,可以在定义结构体时,指定对齐规则:

1__attribute__((packed)); 结构体所占内存大小是所有成员所占内存大小之和

2__attribute__((aligned(n))); 设置结构体占n个字节,如果n比默认值小,n不起作用;n必须是2的次方

柔性数组:

struct st

{

       ...

       char a[0]

}

柔性数组不占有结构体的大小。

eg:

/**
 * 求结构体数据类型的大小
 */
#include <stdio.h>

// 定义测试结构体
struct TEST1
{
    char a;// 1
    int b; // 4
};

struct TEST1_1
{
    char a;// 1
    int b;//  4
}__attribute__((packed));// 取消字节对齐,取消之后,结构体数据类型大小就等于其所有成员的数据类型之和

struct TEST1_2
{
    char a __attribute__((aligned(2)));
    int b;
};

struct TEST2
{
    char a;// 1
    short c; // 2
    int b; // 4
};

struct TEST3
{
    int num;// 4
    char name[10];// 10
    char sex;// 1
    int age;// 4
    double score;// 8
};

struct TEST4
{
    int num;// 4
    short name[5];// 10
    char sex;// 1
    int age;// 4
    int scores[2];// 8
};

int main()
{
    // 创建结构体变量
    struct TEST1 test1;
    struct TEST2 test2;
    struct TEST3 test3;
    struct TEST4 test4;  
    struct TEST1_1 test1_1;
    struct TEST1_2 test1_2;

    // 计算大小
    printf("%lu\n",sizeof(test1));

    printf("%lu\n",sizeof(test2));
    
    printf("%lu\n",sizeof(test3));

    printf("%lu\n",sizeof(test4));
    
    printf("%lu\n",sizeof(test1_1));

    
    printf("%lu\n",sizeof(test1_2));
}

共用体/联合体类型

定义:

使几个不同的变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来分配存储单元,其他成员也是用该空间,他们的首地址是相同。

定义格式:

union 共用体名称
{
    数据类型 变量名;
    数据类型 变量名;
    ...
};

共用体的定义和结构体类型类似:

1.可以有名字,也可以匿名;

2.共用体在定义时也可以定义共用体变量;

3.共用体在定义时也可以初始化成员;

4.共用体也可以作为形参和返回值类型使用;

5.共用体也可以定义共用体数组

...

也就是说,结构体的语法,共用体都支持。

注意:

1.共用体弊大于利,尽量少用,一般很少用;

2.共用体变量在某一时刻只能存一个数据,并且也只能取出一个数

3.共用体和结构体都是自定义数据类型,用法类似于基本数据类型

共用体可以是共用体的成员,也可以是结构体的成员。

结构体可以是结构体的成员,也可以是共用体的成员。

枚举

定义:

我们一般情况下,定义常量使用宏定义(#defne 宏名称 值),宏定义非常适合没有关联关系的常量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,比如 周一~周日1月~12月 等,那么使用宏定义,就不是很清晰在,这个时候就需要使用到枚举。

枚举的存在就是将多个拥有关联关系的常量组合到一起,提高代码的可读性。

说明:

枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)

当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)

枚举常量有默认值,从0开始依次加1;我们可以在定义时指定它的值,如果个别没有赋值,可以根据赋值依次加1推导

特点:

定义了一组常量,类似于定义了多个自定义常量(宏定义)

提供了代码的可读性(避免了魔术数字)

定义语法:

定义枚举类型名以后就可以定义该枚举类型的变量

enum        枚举类型名        变量表;

在定义枚举类型的同时定义该枚举类型的变量。

enum        枚举类型名{ 枚举元素列表 }        变量表;

直接定义枚举类型变量。

enum        { 枚举元素列表 }          变量表;

typedef

说明:给类型重命名,不会影响到类型本身

作用:给已有的类型起别名

格式:
typedef 已有类型名 新别名;
使用:
 

// 定义结构体
struct Student
{
    int id;
    char*name;
    charseXj
    int age;
};
// 类型重命名
typedef struct student stu;
// 定义变量
struct Stu stu = {1,"张甜”,'M',21};

//定义结构体的同时类型重命名
typedef struct PersonInfo
{
    int a;
    double b;
}Per;

// 定义变量
struct Per per = {2,5};

应用场景

1. 数据类型复杂(结构体,共用体,枚举,结构体指针)时使用

2. 为了跨平台兼容性,例如:

        1. size_t:类型重命名后的数据类型,typedef unsigned long size_t;

        2. unit_16:类型重命名后数据类型

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值