IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++笔记】 函数形式参数的三种传递方式 C语言数组、结构体、结构体数组作为函数参数 typedef关键字与结构体、结构体指针的定义 附C语言常见运算符优先级 -> 正文阅读

[C++知识库]【C++笔记】 函数形式参数的三种传递方式 C语言数组、结构体、结构体数组作为函数参数 typedef关键字与结构体、结构体指针的定义 附C语言常见运算符优先级

一、数组作为函数参数

传值与传址

《C和指针》函数的参数一节(7.3节)指出,C函数的所有参数均以“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝。这样函数可以放心地修改这个拷贝值,而不必担心会修改调用程序实际传递给它的参数。

如果被传递的参数是一个数组名,由于数组名的值是一个指向数组第一个元素的指针,因此实际传递给函数的是指向数组起始位置的指针的一份拷贝,该指针同样指向数组起始位置。在函数内部对指针形参进行间接访问操作,实际访问的是原数组的元素。

对于传值和传址:

1. 传递给函数的标量参数是传值调用的。

2. 传递给函数的数组参数在行为上就像它们是通过传址调用的那样。


如果想把一个数组名参数传递给函数,正确的函数形参应该是怎样的?它是应该声明为一个指针还是一个数组?

调用函数时实际传递的是一个指针,所以函数的形参实际上是一个指针,但为了使程序员新手更容易上手一些,编译器也接受数组形式的函数形参。因此,下面这两个函数原型是相等的:
?

void InitStudent2(int *arrayStu, int Num)
void InitStudent2(int arrayStu[], int Num)

由于数组名作为参数传递给函数时,函数实际接收到的是一个指针,因此第一种声明是更为准确的。在函数内部sizeof(str)的值将会是数组指针的长度,而不是数组的长度。

编译器同样接受第二种声明形式。数组形参无需写明它的元素数目,是因为函数并不为数组参数分配内存空间,形参只是一个指针。因此数组形参可以与任何长度的数组匹配。如果函数需要知道数组的长度,它必须作为一个显式的参数传递给函数。
?


二、结构体作为函数参数

1、定义结构体

struct student
{
	string name;  //姓名
	int age;      //年龄
	string hobby; //爱好
};

有typedef关键字的? ?typedef struct student Stu;

? ? ? ?使用typedef定义结构体??。?????typedef用来定义新的数据类型,通常typedef与结构体的定义配合使用。使用typedef的目的使结构体的表达更加简练(所以说typedef语句并不是必须使用的)。

定义一个名字为? ?student 的结构体类型(现在并没有定义结构体变量,并不占用内存空间)

为结构体起一个别名 Stu,这时? ?Stu? ?等价于? ? struct student

下面两种定义方式效果相同

struct student
{
	string name;  //姓名
	int age;      //年龄
	string hobby; //爱好

};
typedef struct student Stu;
typedef struct student
{
	string name;  //姓名
	int age;      //年龄
	string hobby; //爱好

}Stu;

在这里我们要区别一下结构体名和变量名,结构体名是一种类型,不能被当成变量名来使用

变量名声明方法:
1)struct +结构体名+结构体变量名;
2)直接在定义结构体的时候添加变量名的声明

2、打印函数?三种传递方式

函数中的参数列表本质上都是原来实参的副本,由于是指针,所以副本和实参指向的都是同一个内存单元,如若只是改变副本所指内存单元的数据,那么实参内存所指的数据也同样被改变;

但是由于值传递(2.1)在子函数内部,改变了副本的内存单元,实参的内存单元并没有发生改变,所以实参的数据并没有跟着副本一起改变。


如果想改变实参的数据,那么应该传递结构体指针变量的指针(2.3)或者其引用(2.2)

1.第一种方式,结构体指针变量的指针本质上就是这个变量的地址,通过改变这个指针指向的内存单元的内容从而达到修改结构体指针的内容;

2.第二种方式,结构体指针变量的引用其本质就是这个结构体变量的别名,对其引用所进行的操作本质上都是对其自身的操作。

2.1、值传递

在主函数中单独调用 printStudent1(stu1, stu2);

void printStudent1(Stu stu1, Stu stu2)  //值传递
{

	cout << "在printStudent1子函数中" << endl;
	// 打印前修改年龄
	stu2.age = 1000;
	cout << stu1.name << "\t" << stu1.age <<"\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age <<"\t" << stu2.hobby << endl;
}

2.2、引用传递

在主函数中单独调用 printStudent1_1(stu1, stu2);
?? ?

void printStudent1_1(Stu &stu1, Stu &stu2)    //引用传递
{
	cout << "在printStudent1_1子函数中" << endl;
	// 打印前修改年龄
	stu1.age = 1000;

	cout << stu1.name << "\t" << stu1.age << "\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age << "\t" << stu2.hobby << endl;
}

2.3、结构体指针传递

在主函数中单独调用? printStudent1_2(&stu1, &stu2);

结构体指针的访问变量方法
1)p->结构体成员;
2)(*p).结构体成员;

void printStudent1_2(Stu *stu1, Stu *stu2)  //结构体指针传递函数形参
{

	cout << "在printStudent1_2子函数中" << endl;
	// 打印前修改年龄
	stu1->age = 2000;
	//cout << (*stu1).name << "\t" << (*stu1).age << "\t" << (*stu1).hobby << endl;
	//cout << (*stu2).name << "\t" << (*stu2).age << "\t" << (*stu2).hobby << endl;

	cout << stu1->name << "\t" << stu1->age << "\t" << stu1->hobby << endl;
	cout << stu2->name << "\t" << stu2->age << "\t" << stu2->hobby << endl;

}

3、主函数

int main()
{
	cout << "姓名" << "\t" << "年龄" << "  " <<"  爱好" << endl;

	cout << endl;
	Stu stu1 = { "张三" ,18 ,"打篮球" };
	Stu stu2 = { "李四" ,28 ,"rap" };
	


	InitStudent1(stu1, stu2);

	//printStudent1(stu1, stu2);

	printStudent1_1(stu1, stu2);
	
	//printStudent1_2(&stu1, &stu2);

	cout << endl;
	cout << "在主函数中" << endl;
	cout << stu1.name << "\t" << stu1.age << "\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age << "\t" << stu2.hobby << endl;
	

	return 0;

}


三、结构体数组作为函数参数

1、初始化结构体数组

//方式一   结构体数组作为函数参数  下标引用1
void InitStudent2(Stu arrayStu[], int Num)
{
	// 第一种赋值方式
	//Stu arrayStu[4];//结构体数组

	//arrayStu[0].name = "大头";
	//arrayStu[0].age = 20;
	//arrayStu[0].hobby = "唱歌";

	//arrayStu[1].name = "王五";
	//arrayStu[1].age = 28;
	//arrayStu[1].hobby = "跳舞";


	// 第二种赋值方式
	arrayStu[0] = { "大头" ,20,"唱歌" };
	arrayStu[1] = { "王五" ,28,"跳舞" };
}

//方式一    结构体数组作为函数参数  下标引用2
void InitStudent2(Stu *arrayStu, int Num)
{
    //第一种赋值方式
	//Stu arrayStu[4];//结构体数组

	//arrayStu[0].name = "大头";
	//arrayStu[0].age = 20;
	//arrayStu[0].hobby = "唱歌";

	//arrayStu[1].name = "王五";
	//arrayStu[1].age = 28;
	//arrayStu[1].hobby = "跳舞";


	 //第二种赋值方式
	arrayStu[0] = { "大头" ,20,"唱歌" };
	arrayStu[1] = { "王五" ,28,"跳舞" };

}

2、打印函数??访问结构体数组

?我们知道数组作为函数参数的使用方法,那结构体数组本质上也是数组,所以结构体数组作为函数参数的使用方法应该与数组作为函数参数的方法一样。同时我们也知道,下标引用与间接访问完全相同?。下图中函数访问结构体数组是使用下标引用的方式。

//方式一    结构体数组作为函数参数  下标引用2
void printStudent2(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		cout << arrayStu[i].name << "\t" << arrayStu[i].age << "\t" << arrayStu[i].hobby << endl;
	}

}

?即然下标引用与间接访问相同,那间接访问应该如何实现?见下图:

//方式二 结构体数组作为函数参数 间接访问
void printStudent2_1(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		// 方法一
		//cout << (arrayStu + i)->name << "\t" << (arrayStu + i)->age << "\t" << (arrayStu + i)->hobby << endl;

		// 方法二
		// 由于 " * "取值运算符优先级小于 " . "成员选择运算符,所以需要将 *arrayStu 用括号括起来。
		cout << (*(arrayStu + i)).name << "\t" << (*(arrayStu + i)).age << "\t" << (*(arrayStu + i)).hobby << endl;
	}

}

?打印函数部分代码

//方式一    结构体数组作为函数参数  下标引用2
void printStudent2(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		cout << arrayStu[i].name << "\t" << arrayStu[i].age << "\t" << arrayStu[i].hobby << endl;
	}

}


//方式二 结构体数组作为函数参数 间接访问
void printStudent2_1(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		//cout << (arrayStu + i)->name << "\t" << (arrayStu + i)->age << "\t" << (arrayStu + i)->hobby << endl;

		// 方法二
		// 由于 " * "取值运算符优先级小于 " . "成员选择运算符,所以需要将 *arrayStu 用括号括起来。
		cout << (*(arrayStu + i)).name << "\t" << (*(arrayStu + i)).age << "\t" << (*(arrayStu + i)).hobby << endl;
	}

}


//  这种写法实际处理函数只针对 一个结构体 (传进来的那个结构体)操作
void printStudent2_2(Stu *arrayStu)
{

	cout << arrayStu->name << "\t" << arrayStu->age << "\t" << arrayStu->hobby << endl;

}

3、主函数

int main()
{
	cout << "姓名" << "\t" << "年龄" << "  " <<"  爱好" << endl;

	cout << endl;
	
	

	//结构体数组作为函数参数
	Stu stu[4];
	InitStudent2(stu, 2);

	printStudent2(stu, 2);
	printStudent2_1(stu, 2);

	printStudent2_2(&stu[0]);
	printStudent2_2(&stu[1]);
	return 0;

}

四、总代码

/* 2022 08 02 */

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


//struct student
//{
//	string name;  //姓名
//	int age;      //年龄
//	string hobby; //爱好
//};



typedef struct student
{
	string name;  //姓名
	int age;      //年龄
	string hobby; //爱好

}Stu;


//struct student
//{
//	string name;  //姓名
//	int age;      //年龄
//	string hobby; //爱好
//
//};
//typedef struct student Stu;



// 结构体作为函数参数
void InitStudent1(Stu &stu1, Stu &stu2)
{



	// 第一种赋值方式
	//stu1.name = "张三";
	//stu1.age = 18;
	//stu1.hobby = "打篮球";

	//stu2.name = "李四";
	//stu2.age = 25;
	//stu2.hobby = "rap";



	// 第二种赋值方式
	 stu1 = { "张三" ,18 ,"打篮球" };
	 stu2 = { "李四" ,28 ,"rap" };

}

void printStudent1(Stu stu1, Stu stu2)  //值传递
{

	cout << "在printStudent1子函数中" << endl;
	// 打印前修改年龄
	stu2.age = 1000;
	cout << stu1.name << "\t" << stu1.age <<"\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age <<"\t" << stu2.hobby << endl;
}



void printStudent1_1(Stu &stu1, Stu &stu2)    //引用传递
{
	cout << "在printStudent1_1子函数中" << endl;
	// 打印前修改年龄
	stu1.age = 1000;

	cout << stu1.name << "\t" << stu1.age << "\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age << "\t" << stu2.hobby << endl;
}



void printStudent1_2(Stu *stu1, Stu *stu2)  //结构体指针传递函数形参
{

	cout << "在printStudent1_2子函数中" << endl;
	// 打印前修改年龄
	stu1->age = 2000;
	cout << (*stu1).name << "\t" << (*stu1).age << "\t" << (*stu1).hobby << endl;
	cout << (*stu2).name << "\t" << (*stu2).age << "\t" << (*stu2).hobby << endl;
}









//结构体数组作为函数参数





方式一   结构体数组作为函数参数  下标引用1
//void InitStudent2(Stu arrayStu[], int Num)
//{
//	// 第一种赋值方式
//	//Stu arrayStu[4];//结构体数组
//
//	//arrayStu[0].name = "大头";
//	//arrayStu[0].age = 20;
//	//arrayStu[0].hobby = "唱歌";
//
//	//arrayStu[1].name = "王五";
//	//arrayStu[1].age = 28;
//	//arrayStu[1].hobby = "跳舞";
//
//
//	// 第二种赋值方式
//	arrayStu[0] = { "大头" ,20,"唱歌" };
//	arrayStu[1] = { "王五" ,28,"跳舞" };
//}

//方式一    结构体数组作为函数参数  下标引用2
void InitStudent2(Stu *arrayStu, int Num)
{
    //第一种赋值方式
	//Stu arrayStu[4];//结构体数组

	//arrayStu[0].name = "大头";
	//arrayStu[0].age = 20;
	//arrayStu[0].hobby = "唱歌";

	//arrayStu[1].name = "王五";
	//arrayStu[1].age = 28;
	//arrayStu[1].hobby = "跳舞";


	 //第二种赋值方式
	arrayStu[0] = { "大头" ,20,"唱歌" };
	arrayStu[1] = { "王五" ,28,"跳舞" };

}

//方式一    结构体数组作为函数参数  下标引用2
void printStudent2(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		cout << arrayStu[i].name << "\t" << arrayStu[i].age << "\t" << arrayStu[i].hobby << endl;
	}

}


//方式二 结构体数组作为函数参数 间接访问
void printStudent2_1(Stu *arrayStu, int Num)
{
	for (int i = 0; i < Num; i++)
	{
		//cout << (arrayStu + i)->name << "\t" << (arrayStu + i)->age << "\t" << (arrayStu + i)->hobby << endl;

		// 方法二
		// 由于 " * "取值运算符优先级小于 " . "成员选择运算符,所以需要将 *arrayStu 用括号括起来。
		cout << (*(arrayStu + i)).name << "\t" << (*(arrayStu + i)).age << "\t" << (*(arrayStu + i)).hobby << endl;
	}

}


//  这种写法实际处理函数只针对 一个结构体 (传进来的那个结构体)操作
void printStudent2_2(Stu *arrayStu)
{

	cout << arrayStu->name << "\t" << arrayStu->age << "\t" << arrayStu->hobby << endl;

}


int main()
{
	cout << "姓名" << "\t" << "年龄" << "  " <<"  爱好" << endl;

	cout << endl;
	Stu stu1 = { "张三" ,18 ,"打篮球" };
	Stu stu2 = { "李四" ,28 ,"rap" };
	


	InitStudent1(stu1, stu2);

	//printStudent1(stu1, stu2);

	printStudent1_1(stu1, stu2);
	
	//printStudent1_2(&stu1, &stu2);

	cout << endl;
	cout << "在主函数中" << endl;
	cout << stu1.name << "\t" << stu1.age << "\t" << stu1.hobby << endl;
	cout << stu2.name << "\t" << stu2.age << "\t" << stu2.hobby << endl;
	



	//结构体数组作为函数参数
	//Stu stu[4];
	//InitStudent2(stu, 2);

	//printStudent2(stu, 2);
	//printStudent2_1(stu, 2);

	//printStudent2_2(&stu[0]);
	//printStudent2_2(&stu[1]);
	return 0;

}












附:C语言常见运算符优先级

优先级运算符含义结合方向
1[]数组下标从左向右
()圆括号
.成员选择(对象)
->成员选择(指针)
2-负号从右向左
~按位取反
++自增
--自减
*取值
&取地址
!逻辑非
sizeof数据类型长度
(类型)强制类型转换强制类型转换
3/从左向右
*
%取模
4+从左向右
-
5<<左移从左向右
>>右移
6>大于从左向右
>=大于等于
<小于
<=小于等于
7==等于从左向右
!=不等于

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:25:04  更:2022-08-06 10:25:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 12:24:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码