C语言自定义数据类型(三)结构体指针

这篇具有很好参考价值的文章主要介绍了C语言自定义数据类型(三)结构体指针。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。

目录

一、指向结构体变量的指针

1.1举例说明

二、指向结构体数组的指针

2.1举例说明

2.2注意

三、用结构体变量和结构体变量的指针作函数参数

3.1引入

3.2举例说明


一、指向结构体变量的指针

1.1举例说明

指向结构体对象的指针变量既可指向结构体变量,也可指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同。例如:

struct Student* pt;        //pt可以指向struct Student类型的变量或数组元素

先通过一个例子了解什么是指向结构体变量的指针变量以及怎样使用它。

举例:通过指向结构体变量的指针变量输出结构体变量中成员的信息。

解题思路:在已有的基础上,本题要解决两个问题:(1)怎样对结构体变量成员赋值;(2)怎样通过指向结构体变量的指针访问结构体变量中成员。

#include <stdio.h>
#include <string.h>
int main()
{
	struct Student					//声明结构体类型struct Student
	{
		long num;
		char name[20]; char sex;
		float score;
	};
	struct Student stu_1;			//定义struct Student类型的变量stu_1
	struct Student* p;				//定义指向struct Student 类型数据的指针变量p
	p = &stu_1;						//p指向stu_1
	stu_1.num = 1001;				//对结构体变量的成员赋值
	strcpy_s(stu_1.name, "Li Ming");//用字符串复制函数给stu_1.name赋值
	stu_1.sex = 'M';
	stu_1.score = 95;
	printf("No.:%ld\nname :%s\nsex :%c\nscore :%5.1f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score);
	printf("\nNo.:%ld\nname :%s\nsex :%c\nscore :%5.1f\n", (*p).num, (*p).name, (*p).sex, (*p).score);
	return 0;
}

运行结果:

结构体指针,c语言,c++,数据结构,算法,结构体

程序分析:

两个 printf 函数输出的结果是相同的。在主函数中声明了 struct Student 类型,然后定义一个 struct Student 类型的变量 stu_1。又定义一个指针变量 p,它指向一个 struct Student 类型的对象。将结构体变量 stu_1 的起始地址赋给指针变量 p,也就是使 p 指向 stu_1。然后对 stu_1 的各成员赋值。

第 1 个 printf 函数是通过结构体变量名 stu_1 访问它的成员,输出 stu_1 的各个成员的值。stu_1.num 表示 stu_1 中的成员 num,依此类推。第 2 个 printf 函数是通过指向结构体变量的指针变量访问它的成员,输出 stu_1 各成员的值,使用的是 (*p).num 这样的形式。(*p) 表示 p 指向的结构体变量,(*p).num 是 p 所指向的结构体变量中的成员 num。注意 *p 两侧的括号不可省,因为成员运算符 “.” 优先于 “ * ” 运算符,*p.num 就等价于 *(p.num) 了。

说明:

为了使用方便和直观,C 语言允许把 (*p).num 用 p->num 代替,“->”代表一个箭头,p->num 表示 p 所指向的结构体变量中的 num 成员。同样,(*p).name 等价于 p->name。“->” 称为指向运算符。

如果 p 指向一个结构体变量 stu,以下 3 种用法等价:

①stu.成员名        (如stu.num);
②(*p).成员名       (如(*p).num);

③p->成员名        (如p->num)。

二、指向结构体数组的指针

2.1举例说明

可以用指针变量指向结构体数组的元素。请分析下面的例子。

举例:有 3 个学生的信息,放在结构体数组中,要求输出全部学生的信息。

解题思路:用指向结构体变量的指针来处理:

(1)声明结构体类型 struct Student,并定义结构体数组,同时使之初始化;

(2)定义一个指向 struct Student 类型数据的指针变量p;

(3)使p指向结构体数组的首元素,输出它指向的元素中的有关信息;

(4)使p指向结构体数组的下一个元素,输出它指向的元素中的有关信息;

(5)再使p指向结构体数组的下一个元素,输出它指向的元素中的有关信息。

#include<stdio.h>
struct Student					//声明结构体类型struct Student
{
	int num;
	char name[20];
	char sex;
	int age;
};
struct Student stu[3] = { {1001,"Li Ming" , 'M',18},{1002,"Zhang San" ,'M',19},{1003,"Wang Wu",'F',20} }; //定义结构体数组并初始化
int main()
{
	struct Student* p;			//定义指向struct Student结构体变量的指针变量
	printf(" No.Name                    sex age\n");
	for (p = stu; p < stu + 3; p++)
		printf("%5d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age);//输出结果
	return 0;
}

运行结果:

结构体指针,c语言,c++,数据结构,算法,结构体

程序分析:

p 是指向 struct Student 结构体类型数据的指针变量。在 for 语句中先使 p 的初值为 stu,也就是数组 stu 中序号为 0 的元素(即 stu[0] )的起始地址。在第 1 次循环中输出 stu[0] 的各个成员值。然后执行 p++,使 p 自加 1。p 加 1 意味着 p 所增加的值为结构体数组 stu 的一个元素所占的字节数(在 Visual C++ 环境下,本例中一个元素所占的字节数理论上为 4+20+1+4 = 29 字节,实际分配 32 字节)。执行 p++ 后 p 的值等于 stu+1,p 指向stu[1]。在第 2 次循环中输出 stu[1] 的各成员值。在执行 p++ 后,p 的值等于 stu+2,再输出 stu[2] 的各成员值。在执行 p++ 后,p 的值变为 stu+3,已不再小于 stu+3 了,不再执行循环。

2.2注意

(1)如果 p 的初值为 stu,即指向 stu 的序号为 0 的元素,p 加 1 后,p 就指向下一个元素。

例如:

(++p)->num        先使p自加1,然后得到 p 指向的元素中的 num 成员值(即1002)
(p++)->num        先求得 p->num的值(即1001),然后再使 p 自加 1,指向 stu[1] 请注意以上二者的不同。

(2)程序定义了 p 是一个指向 struct Student 类型对象的指针变量,它用来指向一个 struct Student 类型的对象,不应用来指向 stu 数组元素中的某一成员。

例如,下面的用法是不对的:

p = stu[1].name;    // stu[1].name是stu[1]元素中的成员name的首字符的地址

编译时将给出 “ 警告 ” 信息,表示地址的类型不匹配。不要认为反正 p 是存放地址的,可以将任何地址赋给它。如果一定要将某一成员的地址赋给 p,可以用强制类型转换,先将成员的地址转换成 p 的类型。例如:

p = (struct Student*)stu[0].name;

此时,p 的值是 stu[0] 元素的 name 成员的起始地址。可以用 “ printf ("%s", p); ” 输出 stu[0] 中成员 name 的值。但是,p 仍保持原来的类型。如果执行 “ printf( "%s",p+1); ”,则会输出 stu[1] 中 name 的值。执行 p++ 时,p 的值的增量是结构体 struct Student 的长度。

三、用结构体变量和结构体变量的指针作函数参数

3.1引入

将一个结构体变量的值传递给另一个函数,有 3个方法:

(1)用结构体变量的成员作参数。例如,用 stu[1].num 或 stu[2].name 作函数实参,将实参值传给形参。用法和用普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。

(2)用结构体变量作实参。用结构体变量作实参时,采取的也是 “ 值传递 ” 的方式,将结构体变量所占的内存单元的内容全部按顺序传递给形参,形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元。这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的。此外,由于采用值传递方式,如果在执行被调用函数期间改变了形参(也是结构体变量)的值,该值不能返回主调函数,这往往造成使用上的不便。因此一般较少用这种方法。

(3)用指向结构体变量(或数组元素)的指针作实参,将结构体变量(或数组元素)的地址传给形参。

3.2举例说明

举例:有 n 个结构体变量,内含学生学号,姓名和 3 门课程的成绩。要求输出平均成绩最高的学生的信息(包括学号、姓名、3 门课程成绩和平均成绩)。

解题思路:将 n 个学生的数据表示为结构体数组(有 n 个元素)。按照功能函数化的思想,分别用 3 个函数来实现不同的功能:(1)用input函数来输入数据和求各学生平均成绩。(2)用max函数来找平均成绩最高的学生。(3)用print函数来输出成绩最高学生的信息。在主函数中先后调用这3个函数,用指向结构体变量的指针作实参。最后得到结果。

#include<stdio.h>
#define N 3				//学生数为3
struct Student			//定义结构体类型
{
	int num;
	char name[20];
	float score[3];
	float aver;
};

int main()
{
	void input(struct Student stu[]);			//函数声明
	struct Student max(struct Student stu[]);	//函数声明
	void print(struct Student stu);				//函数声明
	struct Student stu[N];						//定义结构体数组
	struct Student* p = stu;					//定义结构体指针
	input(stu);									//调用input函数
	print(max(stu));							//调用print函数,以max函数的返回值作为实参
	return 0;
}

void input(struct Student stu[])				//input函数
{
	printf("请输入各学生的信息:学号,姓名,3门课成绩\n");
	for (int i = 0; i < N; i++)
	{
		scanf_s("%d %s %f %f %f", &stu[i].num, stu[i].name, 20, &stu[i].score[0], &stu[i].score[1], &stu[i].score[2]);
		stu[i].aver = (stu[i].score[0] + stu[i].score[1] + stu[i].score[2]) / 3.0;
	}
}

struct Student max(struct Student stu[])		//max函数
{
	int k = 0;
	for (int i = 1; i < N; i++)					//找出平均值最大的学生
	{
		if (stu[i].aver > stu[k].aver)
			k = i;
	}
	return stu[k];
}

void print(struct Student stu)					//print函数
{
	printf("\n成绩最高的学生是:\n");
	printf("学号:%d\n姓名:%s\n三门课成绩:%5.1f,%5.1f,%5.1f\n平均成绩:%6.2f\n",
		stu.num, stu.name, stu.score[0], stu.score[1], stu.score[2], stu.aver);
}

运行结果:

结构体指针,c语言,c++,数据结构,算法,结构体

程序分析:

(1)结构体类型 struct Student 中包括 num(学号),name(姓名),数组score( 3 门课成绩)和 aver (平均成绩)。在输入数据时只输入学号,姓名和 3 门课成绩,未给 aver 赋值。aver 的值是在 input 函数中计算出来的。

(2)在主函数中定义了结构体 struct Student 类型的数组 stu 和指向 struct Student 类型数据的指针变量 p,使 p 指向 stu 数组的首元素 stu[0]。在调用 input 函数时,用指针变量 p 作为函数实参, input 函数的形参是 struct Student 类型的数组 stu (注意形参数组 stu 和主函数中的数组 stu 都是局部数据,虽然同名,但在调用函数进行虚实结合前二者代表不同的对象,互相间没有关系)。在调用 input 函数时,将主函数中的 stu 数组的首元素的起始地址传给形参数组 stu,使形参数组 stu 与主函数中的 stu 数组具有相同的地址。因此在 input 函数中向形参数组 stu 输入数据就等于向主函数中的 stu 数组输入数据。

在用 scanf_s 函数输入数据后,立即计算出该学生的平均成绩,stu[i].ave r代表序号为 i 的学生的平均成绩。input 函数无返回值,它的作用是给 stu 数组各元素赋予确定的值。

(3)在主函数中调用 print 函数,实参是 max(p)。其调用过程是先调用 max 函数(以 p 为实参),得到 max(p) 的值(此值是一个 strct Student 类型的数据)。然后用它调用print函数。

现在先分析调用 max 函数的过程:与前相同,指针变量 p 将主函数中的 stu 数组的首元素的起始地址传给形参数组 stu,使形参数组 stu 与主函数中的 stu 数组具有相同的地址。在 max 函数中对形参数组的操作就是对主函数中的 stu 数组的操作。在 max 函数中,将各人平均成绩与当前的 “最高平均成绩” 比较,将平均成绩最高的学生在数组 stu 中的序号存放在变量 m 中,通过 return 语句将 stu[m] 的值返回主函数。请注意:stu[m] 是一个结构体数组的元素。max 函数的类型为 struct Student 类型。

(4)用 max(p) 的值(是结构体数组的元素)作为实参调用 print 函数。print 函数的形参 stu 是  struct Student 类型的变量(而不是 struct Student 类型的数组)。在调用时进行虚实结合,把 stu[m] 的值(是结构体元素)传递给形参 stu ,这时传递的不是地址,而是结构体变量中的信息。在 print 函数中输出结构体变量中各成员的值。

(5)以上 3 个函数的调用,情况各不相同:

①调用 input 函数时,实参是指针变量 p,形参是结构体数组,传递的是结构体元素的起始地址,函数无返回值。

②调用 max 函数时,实参是指针变量 p,形参是结构体数组,传递的是结构体元素的起始地址,函数的返回值是结构体类型数据。

③调用 print 函数时,实参是结构体变量(结构体数组元素),形参是结构体变量,传递的是结构体变量中各成员的值,函数无返回值。文章来源地址https://www.toymoban.com/news/detail-735248.html

到了这里,关于C语言自定义数据类型(三)结构体指针的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构和算法初阶(C语言)】复杂链表(随机指针,随机链表的复制)题目详解+链表顺序表结尾

    目录  1.随机链表的复制 1.2题目描述  1.3题目分析 1.4解题: 2.顺序表和链表对比 2.1cpu高速缓存利用率 3.结语 一个长度为  n  的链表,每个节点包含一个额外增加的随机指针  random   该指针可以指向链表中的任何节点或空节点。        构造这个链表的  深拷贝 。 深拷贝

    2024年03月10日
    浏览(83)
  • 结构体和数据结构--从基本数据类型到抽象数据类型、结构体的定义

            在冯-诺依曼体系结构中,程序代码和数据都是以二进制存储的,因此对计算机系统和硬件本身而言,数据类型的概念其实是不存在的。         在高级语言中,为了有效的组织数据,规范数据的使用,提高程序的可读性,方便用户使用,引入了整型、实型等基本数

    2024年02月11日
    浏览(45)
  • 【c语言指针详解】复杂数据结构的指针用法

    目录 一、动态内存分配 1.1 使用malloc和free函数进行内存的动态分配和释放 1.2 内存泄漏和野指针的概念和解决方法 二、复杂数据结构的指针用法 2.1 结构体指针和成员访问操作符 2.2 指针数组和指向指针的指针 2.2.1 指针数组 2.2.2 指向指针的指针 2.3 动态内存分配与结构体

    2024年02月04日
    浏览(47)
  • 【数据结构与算法】之多指针算法经典问题

    本文为 【数据结构与算法】多指针算法经典问题 相关介绍,下边将对 链表反转 (包含 迭代反转链表 、 递归反转 、 头插法反转 ), 双指针-快慢指针 (包含 寻找单向无环链表的中点 、 判断单向链表是否有环及找环入口 ), 双指针-左右指针 (包含 两数之和 、 二分查

    2024年02月03日
    浏览(53)
  • 算法 数据结构分类 数据结构类型介绍 数据结构线性非线性结构 算法合集 (一)

     数据结构分为:                            a.线性结构                            b.非线性结构  a.线性结构:                       数据与结构存在一对一的线性关系; a . 线性结构 存储 分为:                                   顺序存储

    2024年02月10日
    浏览(49)
  • 数据结构与算法----复习Part 8 (链表双指针)

    本系列是算法通关手册LeeCode的学习笔记 算法通关手册(LeetCode) | 算法通关手册(LeetCode) (itcharge.cn) 本系列为自用笔记,如有版权问题,请私聊我删除。 目录 一,双指针简介(Two Pointers) 二,起点不一致的快慢指针 三,步长不一致的快慢指针 判断链表中是否含有环: 四

    2024年02月19日
    浏览(52)
  • 手撕数据结构与算法——树(三指针描述一棵树)

    📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段, 因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力 ——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的 📖作者主页:king南星 📖

    2024年01月17日
    浏览(53)
  • python常见的数据类型与数据结构(一)数字类型 字符串类型 布尔类型 列表 集合 字典 的定义与常规操作方法

    数字类型有int(整数),float(浮点数)和complex(复数型),其中int与float被大家所常用并且可以使用int()和float()函数相互转换。如果字符串只包含数字和小数点也可以被这两种函数强制转换。复数型,则少被人们使用,大都是用在数学公式和物理公式的计算上。 字符串类型较为简单

    2024年02月21日
    浏览(47)
  • 【数据结构】二叉树算法讲解(定义+算法原理+源码)

    博主介绍:✌全网粉丝喜爱+、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦! 🍅附上相关C语言版源码讲解🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找

    2024年01月23日
    浏览(50)
  • R语言的数据类型与数据结构:向量、列表、矩阵、数据框及操作方法

    R语言拥有丰富的数据类型和数据结构,以满足各类数据处理和分析的需求。本文将分享R语言中的数据类型,包括向量、列表、矩阵、数据框等,以及它们的特点、用途和操作方法。 向量是R语言中最基本的数据结构,它可以存储单个数据类型的元素序列。向量具有固定的长度

    2024年03月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包