【Amazing! C】初识结构体(一)

目录

前言  

 一、结构体类型的声明

1.1 结构体类型的声明

1.2 typedef关键字

1.3 结构体成员的类型

1.4 结构体变量的定义和初始化

二、结构体成员的访问

2.1 结构体变量访问成员

2.2 结构体指针访问成员

三、结构体传参


前言  

        我们之前了解了数组,知道数组是一组相同类型元素的组合,元素类型是char,int,float,double等中的一种。单一的类型可以描述事物的部分特征,但并不能表述清楚一个复杂对象,例如,人:姓名+性别+年龄+电话+地址+.....。

        因此,C语言提供了一种自定义数据类型,可以包含若干个“成员”,其类型可以相同也可以不同,这种数据结构成为结构体

 一、结构体类型的声明

1.1 结构体类型的声明

struct tag
{
    member - list;
}variable - list;

首先,声明结构体,必须声明(创建)结构的类型,关键字:struct

其中,tag:结构体标签,根据实际情况命名;member - list:成员变量的列表,需要列举了结构体包含的所有变量的类型;variable - list:变量列表,可写可不写,其作用在于创建了一个结构体变量,变量的类型是创建的结构体的类型,如果不写,就是表明创建了结构体变量。

例如,描述一个学生的相关属性:

struct Stu
{
    char name[10];
    int age;
    char sex[5];
    char tele[12]
}s1, s2;

        上述代码表示声明了一个结构体类型,结构体类型名为Stu,s1和s2是结构体类型变量。也可以在main函数中创建结构体变量:

int main()
{
    struct Stu s3;
    struct Stu s4;

    return 0;
}

        区别在于,s1和s2是全局变量,s3和s4是局部变量。

1.2 typedef关键字

        当结构体类型名过程时,可以采用typedef进行简化重定义。例如:

struct student Stu    //使用typedef,可以在下边省略struct
{
    char name[10];
    int age;
    char sex[5];
    char tele[12];
}Stu;                 //Stu是重命名产生的新的类型

int main()
{
    Stu s5;           //在使用Stu的时候其实就是struct Stu
    Stu s6;

    return 0;
}

1.3 结构体成员的类型

        结构体的成员可以是标量、数组、指针,甚至是其他结构体。例如:

struct T
{
    char c;
    int i;
};

struct S
{
    char c;
    int num;
    int arr[10];
    double* pd;
    struct T st;
    struct T* pt;
}s1;                //s1是全局变量

struct S s2;        //s2是全局变量

int main()
{
    struct S s3;    //s3是局部变量
    return 0;
}

1.4 结构体变量的定义和初始化

        以1.3结构体成员类型为例:

int main()
{
    double d = 3.14;
    //严格按照顺序初始化
    struct S s3 = {'q', 100, {1, 2, 3}, &d, {'a', 99}, NULL};

    //指定成员来初始化
    struct S s4 = {.num = 1000, .arr = {1, 2, 3, 4, 5} };

    return 0;
}

二、结构体成员的访问

        结构体变量和结构体指针都可以对结构体中的成员进行访问。首先我们创建一个结构体变量:

struct S
{
    char name[20];
    int age;
}

2.1 结构体变量访问成员

        结构体变量中的成员是通过点操作符(.)直接访问的。

        使用方式:结构体变量.成员名

#include<string.h>

void set_s(struct S t)
{
    t.age = 18;
    //t.name = "zhangsan";    //t.name确实能够找到结构体中的name,但这样写是错误的,name是这块空间的起始地址
                            //因为name是数组名,相当于地址。应该把“zhangsan”放在name的空间中
    strcpy(t.name, "zhangsan");//字符串拷贝,把后边的字符串拷贝到一块空间中
}

void print_s(struct S t)
{
	printf("%s %d\n", t.name, t.age);
}

int main()
{
    struct S s = { 0 };
    //写一个函数给s中存放数据
    set_s(s);

    //写一个函数打印s中的数据
    print_s(s);
    
    return 0;
}

        但此时打印出的结果并不是我们所需要设置的,经过调试后发现其原理如图:

        把数据放在 中并不会影响 。实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参。

2.2 结构体指针访问成员

        其实,set_s的目的在于设置结构体中的数据,所以我们应该传地址过去。        

        因此,我们把ps解引用,找到s

#include<string.h>

void set_s(struct S* ps)
{
    (*ps).age = 18;            
    strcpy((*ps).name, "zhangsan");
}

int main()
{
    struct S s = { 0 };
    set_s(&s);
    print_s(s);
    
    return 0;
}

        通过调试,我们发现,ps确实远程遥控了s

        但上述有些繁琐,我们知道:结构体指针通过箭头操作符(->)访问成员。

        使⽤⽅式:结构体指针->成员名

        所以有:

#include<string.h>

void set_s(struct S* ps)
{
    ps->age = 18;                      //ps指向的对象成员age                  
    strcpy(ps->name, "zhangsan");
}

int main()
{
    struct S s = { 0 };
    set_s(&s);
    print_s(s);
    
    return 0;
}

三、结构体传参

        由2.1可知,结构体传参可以传地址,也可以传结构体变量。所以当我们涉及到结构体传参的时候,结构体变量和地址,传哪个比较合适呢?

        结构体传参,尽量传址,因为函数传参的时候,参数是需要压栈的。

        如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值