C语言结构体,你学会了吗?

大家好,上一篇文章给大家分享了有关指针的内容,今天,我主要想给大家讲一讲有关结构体之间的知识

1. 结构体的声明

1.1 结构体的相关知识

结构体,我们可以把它理解为一些值的集合。

在此之前,我们学习了很多数据类型,包括整型,浮点型,字符型等等,但是,如果我们想有一个新的数据类型,并包含所有的这些特征,应该怎么做呢?

很简单,把它们打包到一起,定义一个新的数据类型。

拿学生举例,学生不仅有身高,还有性别的区分,年龄,名字等等,所以我们可以把它们都放在一起,方便之后的使用和修改,于是C语言中就有了结构体的这个概念。

1.2 结构体的声明

struct Student
{
    // 成员变量
    int age;
    char name[20];
    char sex[5];
    ....
};

如上图所示,我们实现了一个结构体变量,这个变量的名字叫做Student,我们把其内部包含的所有变量称作成员变量,所以,学生的结构体类型中包含三个成员变量,分别是年龄,姓名以及性别。

切记,结构体后面的分号不能省略。

1.3 结构体成员的类型

既然是结构体了,其内部成员变量的数据类型就可以是任意的,包括整数,指针,字符,数组等等

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

有了结构体类型,那么如何进行定义并进行初始化呢,其实很简单。

1.4.1 定义

struct Point
{
    int x;
    int y
};

以一个点为例,他其中包含横坐标以及纵坐标,那我们在抵不过一变量的时候可以直接定义,就像这样:

struct Point
{
    int x;
    int y;

}p1; // 声明类型的同时定义变量

我们可以在声明类型的同时进行对变量的定义,但是要注意,这个时候的 p1 变量就是一个全局变量。

我们也可以声明的时候先不定义,在主函数中定义变量,就像这样:

struct Point
{
    int x;
    int y
};

int main()
{
    struct Point p2;
}

我们同时也定义了一个结构体变量 p2,不同的是,p2就是一个局部变量,开辟在栈空间。

注意:struct关键字千万不可省略。

1.4.2 结构体变量的初始化

其实结构体变量的初始化也很简单,就是在定义的同时对成员变量进行一些赋值就可以了,例如:

struct Point
{
    int x;
    int y
};

int main()
{
    struct Point p2 = {3, 4};

    return 0;
}

为了偷懒,我就直接引用了上文的例子,将p2的横坐标赋值为3,纵坐标赋值为4。

当然了,结构体也可以嵌套初始化,我们以链表为例。

struct Node
{
    int data;
    struct Node* next;
}p = {2, NULL};


这就是典型的结构体嵌套的例子,并创建了一个局部变量p,对它进行了初始化。

那有同学就会问了,就有没有简单一点的方法吗,每次都写struct感觉好麻烦啊。

答案当然是肯定的,那么代码应该怎么改呢?

这就不得不提到我们C语言的关键字typedef了,他可以减少代码的复用,举个例子。

我们知道C语言的长整型是long long,为了简洁,我们可以这样做

typedef long long LL;

这么做的好处是,以后我们可以用LL来代替long long,从而简化代码,让人看起来更舒服。

那么,typedef用在结构体上也是同理

typedef struct Point
{
    int x;
    int y;
}P;

在加上typedef关键词后,以后我们可以用P来代表整个结构体变量,就像这样:


int main()
{
    P p1 = {1, 2};
}

怎么样,是不是感觉很简单呢?

但是要注意的是,加上typedef之后,P就代表这个结构体变量,而非是我们之前创建的一个全局变量,这点一定不要弄混,千万要看清楚struct结构体定义的时候是否加上了typedef关键字,防止出现错误。

2. 结构体成员的访问

我们创建了结构体之后,那么如何对结构体内部的成员变量进行访问呢?

结构体成员的变量是通过(.)操作符来实现的,它支持两个操作数,前面的操作数是结构体变量的名称,后面的变量是你想要访问的成员变量

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

int main()
{
    struct Student s;
}

我们可以看到,结构体变量s中包含两个成员变量,分别是学生的姓名以及学生的年龄,于是我们可以通过(.)操作符来访问,就像这样:


s.age = 18;
s.name = "张三";

s中的年龄因为是一个整型变量,所以我们直接用(.)访问之后,并把它初始化为18。

但是s中的姓名是一个字符数组,如果我们也直接这么赋值的话,会出现什么问题呢?

我们会收到编译器的提示,意思就是说赋值号的左边必须为可修改的变量,那么这种错误出现的根源是什么呢?

我们可以看到,姓名是由一个字符数组来代替,如果我们直接访问name的话,由于name是一个数组,所以name(数组名)代表的就是数组首元素的地址,他是一个指针常量,是不可以被改变的, 那么我们应该怎么做呢?

这就不得不提到一个库函数了,它就是strcpy,作用是复制字符串,他有两个参数,第一个参数是字符串第一个字符的地址,第二个参数是字符串的内容,具体实现如下:

struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员

这样,编译器就不会报错了,但是要注意,使用strcpy函数之前要加上对应的<string.h> 头文件哦

3. 结构体传参

我们先回顾一下之前学过有关函数的知识,我们知道,形参是实参的一份临时拷贝,形参的改变不会影响实参,当我们想要通过形参来改变实参的时候,我们需要传的是实参的指针,并且形参用一个指针变量来接受,以此达到改变实参的结果,比如:

我们想交换两个数 a 和 b。

#include <stdio.h>

void Swap(int* pa, int* pb) // 用两个指针变量来接收
{
	int temp = *pa;
	*pa = *pb;
	*pb = temp;
}

int main()
{
	int a = 3;
	int b = 4;
	// 交换 a 和 b
	Swap(&a, &b); // 传的是 a 和 b 的地址

	printf("a = %d, b = %d", a, b);
}

打印结果如下:

 结构体传参也是同理,如果我们想对实际的结构体变量中的内容进行修改,我们也需要传递结构体变量的指针,代码如下:

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

void print(struct Stu* ps)
{
     printf("name = %s   age = %d\n", (*ps).name, (*ps).age);

    //使用结构体指针访问指向对象的成员

     printf("name = %s   age = %d\n", ps->name, ps->age);
}

int main()
{
    struct Stu s = {"zhangsan", 20};

    print(&s);//结构体地址传参

    return 0;
}

这里我们就不得不提到一个新的操作符(->),他可以通过结构体变量的指针来访问成员变量,如上代码所示,我们将结构体变量的指针传递过去,用一个结构体指针变量来接收,并通过解引用的方式来找到所对应的成员变量,我们可以通过 (*ps).name 来对姓名这个成员变量来进行赋值,但是,为了语法的简单,我们也可以直接使用(->)操作符,通过 ps ->name 来访问成员变量,所以本质上  (*ps).name == ps->name,但还是推荐大家写第二种。

下面,我给出一段代码:

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;
}

大家感觉,print1函数好还是print2函数好呢?

这里的好指的就是程序使用的空间最少,代码执行效率最高。

毫无疑问,print2函数是更好的,原因如下:

函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
总结:结构体传参的时候,要传结构体的地址。
好了,今天有关结构体的知识到这里就结束了,你学会了吗?
我们下期再见,拜拜~
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值