0
点赞
收藏
分享

微信扫一扫

【C++_04】结构体(结构体的概念,结构与指针,结构与数组,结构与函数参数传递,返回结构体)

霸姨 2022-03-16 阅读 104

结构概述

结构体类型将一些分量聚合成一个整体,用一个变量表示。

一个结构体的各个分量都有名字,这些分量称为成员(member)。

由于结构体的成员可以是各种类型的(相当于数据打包),程序员能创建适合于问题的数据聚合。

其实,后面将要学习的也可以实现数据打包,但相比结构体,类还实现了操作打包。

结构体的使用

  • 定义一个结构体类型
  • 定义结构体类型的变量
  • 访问结构体变量

结构体变量

我们先来看一个例子:

定义学生结构体,包含姓名、学号、出生日期、英语成绩、数学成绩。
定义结构体变量,输入学生信息,输出所有信息及平均成绩。

#include <iostream>
#include <cstring>
using namespace std;

// 定义学生结构体,包含姓名、学号、出生日期、英语成绩、数学成绩。
// 定义结构体变量,输入学生信息,输出所有信息及平均成绩。

struct date
{
    int year,month,day;
};

struct student
{ //记住结构体的定义方式
    int     no;
    string  name;   //string类型
    date    birthday;  //结构体里面还可以嵌套结构体date
    int     eng,math;
};

int main()
{
    //输入:202115 小明 2000 08 25 90 100
    
    /*——————————————————————————————————————————————————————————————————————————————————
    //方式一:使用cin、cout输入输出
    student s;    //定义结构体变量s
    
    cin >> s.no >> s.name 
        >> s.birthday.year >> s.birthday.month >> s.birthday.day
        >> s.eng >> s.math;

    cout << s.no << " " << s.name << " " 
         << s.birthday.year << " " << s.birthday.month << " " << s.birthday.day << " "
         << s.eng << " " << s.math << endl;         // 输出:202115 小明 2000 08 25 90 100
    
    *///——————————————————————————————————————————————————————————————————————————————————
    //方式二:定义的同时赋值初始化
    
    student s = { 202115,"lisi", {2002,1,1},90, 100 };  //注意:必须加上=
    
    cout << sizeof(s) << endl;      //输出:56(是所有字段的字节数之和)
    cout << sizeof(string) << endl; //输出:24

    cout << s.no << " " << s.name << " " 
         << s.birthday.year << " " << s.birthday.month << " " << s.birthday.day << " "
         << s.eng << " " << s.math << endl;             //输出:202115 lisi 2002 1 1 90 100

    return 0;
}

这个例子包含了以下知识点:

(1)结构体变量的定义

结构体变量的定义和普通的变量定义一样。
格式:结构体类型名 变量

一旦定义了一个结构体类型的变量,系统在分配内存时就会分配一块连续的空间,依次存放它的每一个分量。这块空间总的名字就是结构体变量的名字。内部还有各自的名字。

如上述例子使用sizeof可以看出结构体是所有字段的字节数之和。
在这里插入图片描述
(2)结构体变量的初始化

student  s = { "2021","lisi",2002,1,1,90,100 };
student  s = { "2021","lisi",{2002,1,1},90,100 };

(3)变量的访问

对结构体类型变量的引用一般为引用它的成员

格式:变量名.成员名s.name

若成员中还包含结构体,可逐级展开,例如:s.birthday.year

(4) 结构体变量的赋值

结构体变量的赋值通常是通过对它的每一个成员的赋值而实现。如上述的cin格式。

结构体变量的输出通常是通过输出它的每一个成员而实现。如上述的cout格式。

注意:同类型的结构变量之间可以相互赋值。例如:假设两个学生结构体变量s1,s2。s1 = s2;表示将s2的成员对应赋给s1的成员。

结构与指针(结构体指针)

指向结构的指针

直接定义指针变量并给结构体指针赋值:student *sp = & s1;

结构体指针变量的引用

  • (*指针).成员。 例如:(*sp).name
  • 指针->成员。 例如:sp->name ( ->是所有运算符中优先级最高的,通常使用这种方法)

通过指针动态分配结构体空间

和申请普通的动态变量一样。

student  *sp;
sp = new student;      // 分配一个空间
sp = new student[n];  // 分配n个空间

接下来看一个详细的例子:

#include <iostream>
#include <cstring>
using namespace std;

struct date
{
    int year,month,day;
};

struct student
{ 
    int     no;
    string  name;      
    date    birthday;  
    int     eng,math;
};

int main()
{
    //结构体变量
	student s = { 202115,"lisi", {2002,1,1},90, 100 };
	student* ps = &s;   //通过指针访问结构体

	//直接访问方式
    cout << s.no << " " << s.name << " " << s.birthday.year
		<< " " << s.birthday.month << " " << s.birthday.day
		<< " " << s.eng << " " << s.math;                               //输出:202115 lisi 2002 1 1 90 100
    cout<<endl;

	//通过指针进行访问
    cout << (*ps).no << " " << (*ps).name << " " << ps->birthday.year   //第一种访问方式:ps是指针,*ps是值进行访问
		<< " " << ps->birthday.month << " " << ps->birthday.day         //第二种访问方式:直接通过ps指针访问,使用ps->
		<< " " << ps->eng << " " << ps->math;                           //输出:202115 lisi 2002 1 1 90 100

    return 0;
}

结构与数组(结构体数组)

引用数组的某一成员的成员

studentArray[3].name

数组成员之间相互赋值

studentArray[4] = studentArray[2]

结构数组的初始化

student studentArray[5] = { {“00001”, “lisi”, 2002,1,1,90,98 }, {…}, {…}, {…}};

结构体数组的输入输出:先定义,后循环输入输出

#include <iostream>
#include <cstring>
using namespace std;

struct date
{
    int year,month,day;
};

struct student
{ 
    int     no;
    string  name;      
    date    birthday;  
    int     eng,math;
};

int main()
{
  
    //方式一:定义结构体数组并初始化
    student s[3] = { 20211501,"lisi", {2002,1,1},90, 100 ,
					 20211502,"wangwu", {2002,1,1},89, 96,
					 20211503,"zhaoliu", {2002,1,1},90, 95 };
    int i;

    //方式二:使用cin循环输入结构体数组
    for (i = 0; i < 3; i++)
	{
	    cin >> s[i].no >> s[i].name >> s[i].birthday.year
		    >> s[i].birthday.month >> s[i].birthday.day >> s[i].eng >> s[i].math;
	}

    //循环输出结构体数组
	for (i = 0; i < 3; i++)
	{
		cout << s[i].no << " " << s[i].name << " " << s[i].birthday.year
			<< " " << s[i].birthday.month << " " << s[i].birthday.day
			<< " " << s[i].eng << " " << s[i].math << endl;
	}

    return 0;
}

结构与参数传递,返回结构体

结构体类型是数据类型,作为参数传递,无论传值、传指针、传引用和数组,和传递基本类型参数语法相同。

返回结构体,同返回基本数据类型语法相同,可以返回结构体值、返回结构体引用、返回结构体指针。

需要注意的是:返回引用、指针,需要静态(static)局部变量或者动态内存分配空间,确保函数执行完空间仍在。

单变量

#include <iostream>
#include <cstring>
using namespace std;

struct date
{
    int year,month,day;
};

struct student
{ 
    int     no;
    string  name;      
    date    birthday;  
    int     eng,math;
};

//void output11(student s);             //一般不用。传结构体的值,值传递是备份,耗费空间,所以一般很少用值传递,所以一般传引用

void input1(student& s);            //传结构体的引用(单变量)
void output1(const student& s);     

student input2();                   //返回结构体值

int main()
{
    student s;
    
    //函数传结构体 引用,值,指针
    input1(s);
    output1(s);     //输出成功:202115 lisi 2002 1 1 90 100
    
    //返回结构体
    s = input2();
	output1(s);     //输出成功:202115 lisi 2002 1 1 90 100

    return 0;
}

//——————————————————————————————————————————————————————————————————————————————
//input1 (单变量)传结构体引用。因为要改变参数的值,所以传引用
void input1(student& s)         
{
	cin >> s.no >> s.name >> s.birthday.year
		>> s.birthday.month >> s.birthday.day >> s.eng >> s.math;
}

//void output11(student s) 因为输出不改变参数的值,所以直接传值即可,但由于传值是备份,增加空间,所以使用const引用,表示不改变参数值的引用
//output1 (单变量)传结构体引用。输出不改变参数值
void output1(const student& s)
{
	cout << s.no << " " << s.name << " " << s.birthday.year
		<< " " << s.birthday.month << " " << s.birthday.day
		<< " " << s.eng << " " << s.math;
}
//——————————————————————————————————————————————————————————————————————————————
//intput2 返回结构体值
student input2()
{
	student s;
	cin >> s.no >> s.name >> s.birthday.year
		>> s.birthday.month >> s.birthday.day >> s.eng >> s.math;
	return s;
}
//——————————————————————————————————————————————————————————————————————————————
//单变量输入示例: 202115  lisi 2002 1 1 90 100

数组

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

struct date
{
    int year,month,day;
};

struct student
{ 
    int     no;
    string  name;      
    date    birthday;  
    int     eng,math;
};

void input3(student* s, int n);     //传结构体数组(多变量数组)
void output3(student* s, int n);    
void sort1(student* s, int n);      //方式一:自己写的sort函数;也可以使用方式二:调用系统sort函数

int main()
{
    student s[3];
    
    //传结构体数组
    input3(s, 3);
	sort1(s, 3);              //方式一:自己写的冒泡排序函数
	//sort(s, s + 3, cmp);    //方式二:调用系统sort函数。s表示起始元素;s+3表示最后一个元素,由于是半开区间,[s,s+3);cmp是自己写的比较函数,表示排序规则;
	output3(s, 3);

    return 0;
}

//——————————————————————————————————————————————————————————————————————————————
//函数传指针,也改变参数的值
void input3(student* s, int n)
{
	int i;
	for (i = 0; i < 3; i++)
	{
		cin >> s[i].no >> s[i].name >> s[i].birthday.year
			>> s[i].birthday.month >> s[i].birthday.day >> s[i].eng >> s[i].math;
	}
}

void output3(student* s, int n)
{
	int i;
	for (i = 0; i < 3; i++)
	{
		cout << s[i].no << " " << s[i].name << " " << s[i].birthday.year
			<< " " << s[i].birthday.month << " " << s[i].birthday.day
			<< " " << s[i].eng << " " << s[i].math << endl;
	}
}
//——————————————————————————————————————————————————————————————————————————————
//方式一:自己写的冒泡排序函数
void sort1(student* s, int n)
{
	for (int i = 1; i < n; i++)
		for (int j = 0; j < n - i; j++)
		{
			//以英语和数学成绩的平均值进行升序排序
            if ((s[j].eng + s[j].math) / 2 > (s[j + 1].eng + s[j + 1].math) / 2)    
			{
				/*student temp;         //结构体可以当作变量使用,所以不用写交换语句,可以使用swap进行整体交换,
				temp = s[j];
				s[j] = s[j + 1];
				s[j + 1] = temp;*/
				swap(s[j], s[j + 1]);   //swap交换函数对结构体也是适用的,记得头文件algorithm
			}
		}
}
//——————————————————————————————————————————————————————————————————————————————
//方式二:调用系统sort函数,但由于系统不知道排序规则是什么,所以需要自己写一个排序规则的比较函数。
bool cmp(const student& lhs, const student& rhs)  // lhs rhs 两个变量表示前后两个操作数;如果顺序不对,就要进行交换
{
	//英语和数学成绩的平均升序
    // return (lhs.eng + lhs.math) / 2 < (rhs.eng + rhs.math) / 2;

    //按照出生年月日进行排序
    /*return lhs.birthday.year * 1000 + lhs.birthday.month * 100 + lhs.birthday.day
		< rhs.birthday.year * 1000 + rhs.birthday.month * 100 + rhs.birthday.day;
	*/

	//英语成绩升序,若英语相同,数学成绩降序。
	if (lhs.eng == rhs.eng)
		return lhs.math > rhs.math;
	return lhs.eng < rhs.eng;
}

/*  多变量数组输入示例:
20211501 lisi 2002 12 31 100 100
20211502 wangwu 2001 3 4 100  96
20211503 zhaoliu 2002 1 1 90 95
*/
举报

相关推荐

0 条评论