C语言结构体原来并不难(下篇)

150 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

前言 

接着上次讲的结构体内容,下篇主要讲解结构体指针、结构体中const的使用,结构体和函数组合(做函数参数)、以及案例来巩固知识。


一、结构体指针

1、创建结构体

示例:

struct student 
{
string name;//姓名
int age;//年龄
int score;//分数
};

2、使用指针赋值

示例://1、创建学生结构体变量
student s = { "韩信",18,99 };
//2、通过指针指向结构体变量
student* p = &s; 

 这里有两点需要注意:1、指针变量前面的struct省略了  2、引用学生结构体属性的时候不是用” .“而是用” ->“有时候编译器不提醒,家人们要注意。

二、结构体中const的使用

1、const 关键字的作用

  1. 可以定义const常量,具有不可变性。
    例如:const int Max=100; Max++会产生错误; 

  2. 便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。
    例如: void fun(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; 

  3. 可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!
    如 1 中,如果想修改Max的内容,只需要它修改成:const int Max=what you want;即可!

  4. 可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错,也叫只读性;

    例如: void f(const int i) { i=10;//error! }

  5. 可以节省空间,避免不必要的内存分配。和#dedine M 8 类似,我们可以直接写成 const  int  M =8;而且 #define 在内存中有多份拷贝, const 定义常量仅有一份拷贝,无疑可以提高运行效率。

2、具体使用

struct student
{
	string name;
	int age; 
	int score;
};
void printStudent(const student  *s) {
	//s->age = 150; 加入const后程序会报错,此时函数只能读取而不能修改,防止出现误操作
	cout << "姓名:" << s->name << " 年龄:" << s->age << endl;
}
int main()
{
	student s1 = { "张三",18,88 };
	printStudent(&s1);
}

这里简单的定义了学生结构体和打印信息 printfStudent(const student *s) 方法,主函数传入结构体变量的地址,对应形参的结构体指针类型,如果修改name 属性,编译器会告诉你错误::“表达式必须是可修改的左值”,意思我们无法修改s1的所有属性,只能读取,从而防止出现误操作。

三、结构体做函数参数

1、说明

顾名思义,我们需要创建结构体变量,然后将结构体变量传入函数里面,我准备了值传递和地址传递两种,顺便比较二者的区别,代码如下:

struct student
{
	string name;
	int age, score;
};
void printStudent1(student s) {
	s.name = "李白";
	cout<< "printfStudent1中  姓名:" << s.name << "年龄:" << s.age 
		<< "分数:" << s.score << endl;
}
void printStudent2(student* p)
{
	p->name = "韩信"; p->age = 38;
	cout << "printfStudent2中 姓名:" << p->name << "年龄:" << p->age 
		 << "分数:" << p->score<< endl;
}
int main()
{
	student s = { "张三",21,99 };
	cout << "在main函数中打印学生信息:" << "姓名:" << s.name 
		 << "年龄:" << s.age << "分数:" << s.score << endl;
	printStudent1(s);//pS1为值传递,不改变实参的值
	cout << "值传递后姓名为:" << s.name << endl;
	printStudent2(&s);
	cout << "地址传递后姓名:" << s.name << endl;//pS2为地址传递,改变实参的值
}

这里创建结构体变量的时候就给s 赋值,经过printfStudent1()方法后姓名仍然不变,想必大家看过我上次的文章“详解函数的三种传参方式”后,可以很好理解其中的原因。经过printfStudent2()方法后姓名就会改变,因为传参传的是地址,不会像值传递那样拷贝副本。

2、输出结果

 四、结构体案例

最后来个小案例巩固技能:按年龄大小输出一个人物数组的所有信息,提示:冒泡排序加结构体即可。代码如下:

#include<iostream>
using namespace std;
#define N 5
struct DInfo
{
	string Name;
	string Sex="男";
	float Age;
	DInfo(string name = "0", float age = 0)
	{
		Name = name; Age = age;
	}
};
DInfo D[N] = {DInfo("张飞",20.8),DInfo("赵云",22.3),DInfo("韩信",20.1)
             ,DInfo("树叶",23),DInfo("耀杨",20.0) };
void StructArray(DInfo *D, int len)
{
	for (int i = 0; i < N - 1; i++)
		for (int j = 0; j < N - i - 1; j++)
		{
			if (D[j].Age > D[j + 1].Age)
			{
				DInfo temp;
				temp = D[j + 1]; D[j + 1] = D[j]; D[j] = temp;
			}
		}
}
int main()
{
	int len = sizeof(D) / sizeof(D[0]);
	StructArray(D, len);
	cout << "按年龄从小到大输出所有成员信息:\n";
	for (int i = 0; i < N; i++) {
		cout << "姓名\t" << D[i].Name << "\t性别\t" 
			 << D[i].Sex << " 年龄\t" << D[i].Age << endl;
	}
	system("pause");
}

总结

到这里结构体相关知识就暂时告一段落了,但是我们的脚步永远都不会停下,后面我会更Visual Stdio 的函数分文件编写和用结构体实现一个通讯录管理系统,我们不见不散