【C++ 四】函数、指针

news2024/11/13 15:53:47

函数、指针


文章目录

  • 函数、指针
  • 前言
    • 1 函数
      • 1.1 概述
      • 1.2 函数定义
      • 1.3 函数调用
      • 1.4 值传递
      • 1.5 函数常见样式
      • 1.6 函数声明
      • 1.7 函数分文件编写
    • 2 指针
      • 2.1 指针基本概念
      • 2.2 指针变量定义和使用
      • 2.3 指针所占内存空间
      • 2.4 空指针和野指针
      • 2.5 const 修饰指针
      • 2.6 指针和数组
      • 2.7 指针和函数
      • 2.8 指针、数组、函数
  • 总结


前言

本文包含函数概述、函数定义、函数调用、值传递、函数常见样式、函数声明、函数份文件编写、指针基本概念、指针变量定义和使用、指针所占内存空间、空指针和野指针、const修饰指针、指针和数组、指针和函数、指针数组函数。


1 函数

1.1 概述

作用: 将一段经常使用的代码封装起来,减少重复代码

一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能

1.2 函数定义

函数的定义一般主要有5个步骤:

(1)、返回值类型

(2)、函数名

(3)、参数表列

(4)、函数体语句

(5)、return 表达式

语法:

返回值类型 函数名 (参数列表)
{

       函数体语句

       return表达式

}

(1)、返回值类型 :一个函数可以返回一个值。在函数定义中

(2)、函数名:给函数起个名称

(3)、参数列表:使用该函数时,传入的数据

(4)、函数体语句:花括号内的代码,函数内需要执行的语句

(5)、return 表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据

示例: 定义一个加法函数,实现两个数相加

// 返回值类型:int
// 函数名:add
// 参数列表:(int num1, int num2)
// 函数体语句:int sum = num1 + num2;
// return 表达式:return sum;
int add(int num1, int num2)
{
	int sum = num1 + num2;
	return sum;
}

1.3 函数调用

功能: 使用定义好的函数

语法: 函数名(参数)

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 函数定义
int add(int num1, int num2)  // 定义中的num1,num2称为形式参数,简称形参
{
	int sum = num1 + num2;
	return sum;
}

int main() {
 
	int a = 10;
	int b = 10;

	// 调用add函数
	int sum = add(a, b);  // 调用时的a,b称为实际参数,简称实参

	cout << "sum = " << sum << endl;  // 20

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

1.4 值传递

(1)、所谓值传递,就是函数调用时实参将数值传入给形参

(2)、值传递时,如果形参发生,并不会影响实参

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 定义函数,实现两个数字进行交换
void swap(int num1, int num2)  // 如果函数不需要返回值,声明的时候可以写void
{
	cout << "交换前:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;

	int temp = num1;
	num1 = num2;
	num2 = temp;

	cout << endl;

	cout << "交换后:" << endl;
	cout << "num1 = " << num1 << endl;
	cout << "num2 = " << num2 << endl;

	//return ;  // 当函数声明时候,不需要返回值,可以不写return
}

int main() {
 
	int a = 10;
	int b = 20;

	cout << "mian中的 a = " << a << endl;  // 10
	cout << "mian中的 b = " << b << endl;  // 20

	swap(a, b);  // 当我们做值传递的时候,函数的形参发生改变,并不会影响实参

	cout << endl;

	cout << "mian中的 a = " << a << endl;  // 10
	cout << "mian中的 b = " << b << endl;  // 20

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

1.5 函数常见样式

常见的函数样式有4种:

(1)、无参无返

(2)、有参无返

(3)、无参有返

(4)、有参有返

// 函数常见样式

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 1、无参无返
void test01()
{
	//void a = 10; //无类型不可以创建变量,原因无法分配内存
	cout << "this is test01" << endl;
	//test01(); 函数调用
}

// 2、有参无返
void test02(int a)
{
	cout << "this is test02" << endl;
	cout << "a = " << a << endl;
}

// 3、无参有返
int test03()
{
	cout << "this is test03 " << endl;
	return 10;
}

// 4、有参有返
int test04(int a, int b)
{
	cout << "this is test04 " << endl;
	int sum = a + b;
	return sum;
}

int main() {
 
	test01();

	cout << endl;

	test02(10);

	cout << endl;

	cout << test03() << endl;

	cout << endl;

	cout << test04(20, 30) << endl;

	cout << endl;

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

1.6 函数声明

作用: 告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义

函数的声明可以多次,但是函数的定义只能有一次

// 函数常见样式

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 声明
int max(int a, int b);  // 提前告诉编译器函数的存在,可以利用函数的声明;声明后,函数的定义可以写在main函数之后

// 定义
int max(int a, int b)
{
	return a > b ? a : b;  // 比较函数,实现两个整型数字进行比较,返回较大的值
}

int main() {
 
	int a = 100;
	int b = 200;

	cout << max(a, b) << endl;  // 调用函数

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

1.7 函数分文件编写

作用: 让代码结构更加清晰

函数分文件编写一般有4个步骤:

(1)、创建后缀名为.h的头文件

(2)、创建后缀名为.cpp的源文件

(3)、在头文件中写函数的声明

(4)、在源文件中写函数的定义

swap.h

#include <iostream>  // 包含输入输出流;不写引用cout时会提示:未定义
using namespace std;  // 框架;命名空间;域

// 实现两个数字交换的函数声明
void swap(int a, int b);

swap.cpp

#include "swap.h"  // ""代表自定义的头文件

void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

main.cpp

#include <iostream>
using namespace std;

#include "swap.h"

int main() {

	int a = 100;
	int b = 200;
	swap(a, b);

	system("pause");

	return 0;
}

在这里插入图片描述

2 指针

2.1 指针基本概念

指针的作用: 可以通过指针间接访问内存

(1)、内存编号是从0开始记录的,一般用十六进制数字表示

(2)、可以利用指针变量保存地址

2.2 指针变量定义和使用

指针变量定义语法: 数据类型 * 变量名;

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	// 1、指针的定义
	int a = 10; // 定义整型变量a

	// 指针定义语法: 数据类型 * 变量名 ;
	int* p;

	// 指针变量赋值
	p = &a;  // 指针指向变量a的地址
	cout << &a << endl;  // 打印数据a的地址 ; 00FFA5C
	cout << p << endl;  // 打印指针变量p ; 00FFA5C

	// 2、指针的使用
	// 通过*操作指针变量指向的内存
	cout << "*p = " << *p << endl;  // 10 ; 通过解引用的方式来找到指针指向的内存中的数据

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

指针变量和普通变量的区别:

(1)、普通变量存放的是数据,指针变量存放的是地址

(2)指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用

2.3 指针所占内存空间

提问: 指针也是种数据类型,那么这种数据类型占用多少内存空间?

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	int a = 10;

	int* p = &a;  // 指针指向数据a的地址

	cout << *p << endl;  // * 解引用 ; 10

	// 在32位操作系统下,指针是占4个字节空间大小,不管是什么数据类型
	// 在64位操作系统下,指针是占8个字节空间打下
	cout << sizeof(p) << endl;  // 8
	cout << sizeof(char*) << endl;  // 8
	cout << sizeof(float*) << endl;  // 8
	cout << sizeof(double*) << endl;  // 8

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

2.4 空指针和野指针

空指针: 指针变量指向内存中编号为0的空间

用途: 初始化指针变量

注意: 空指针指向的内存是不可以访问的

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	// 指针变量p指向内存地址编号为0的空间
	int* p = NULL;

	// 访问空指针报错 
	// 内存编号0 ~255为系统占用内存,不允许用户访问
	cout << *p << endl;

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

野指针: 指针变量指向非法的内存空间

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	// 指针变量p指向内存地址编号为0x1100的空间
	int* p = (int*)0x1100;  // 0x1100十六进制;(int *)强转为指针类型;没有权利操作编号为0x1100的内存空间

	// 访问野指针报错 
	cout << *p << endl;  // 引发异常:读取访问权限冲突

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

2.5 const 修饰指针

const 修饰指针有三种情况:

(1)、const 修饰指针 — 常量指针

在这里插入图片描述

(2)、const 修饰常量 — 指针常量
在这里插入图片描述

(3)、const 即修饰指针,又修饰常量
在这里插入图片描述

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	int a = 10;
	int b = 10;

	// 1、常量指针
	// const 修饰的是指针,指针指向可以改,指针指向的值不可以更改
	const int* p1 = &a;
	p1 = &b;  // 正确
	// *p1 = 100;  报错

	// 2、指针常量
	// const 修饰的是常量,指针指向不可以改,指针指向的值可以更改
	int* const p2 = &a;
	//p2 = &b;  // 错误
	*p2 = 100;  // 正确

	// 3、const 既修饰指针又修饰常量
	const int* const p3 = &a;
	// p3 = &b;  // 错误
	// *p3 = 100;  // 错误

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

2.6 指针和数组

作用: 利用指针访问数组中元素

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

int main() {
 
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	int* p = arr;  // 指向数组的指针;arr就是数组首地址

	cout << "第一个元素: " << arr[0] << endl;  // 1
	cout << "指针访问第一个元素: " << *p << endl;  // 1

	p++;  // 让指针向后偏移4/8个字节(看不同操作系统)
	cout << "指针访问第二个元素: " << *p << endl;  // 2

	cout << endl;
	p--;

	for (int i = 0; i < 10; i++)
	{
		//利用指针遍历数组
		cout << *p << endl;
		p++;
	}

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

2.7 指针和函数

作用: 利用指针作函数参数,可以修改实参的值

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 值传递
void swap1(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}

// 地址传递
void swap2(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

int main() {
 
	int a = 10;
	int b = 20;
	swap1(a, b);  // 值传递不会改变实参

	swap2(&a, &b);  // 地址传递会改变实参

	cout << "a = " << a << endl;  // 20

	cout << "b = " << b << endl;  // 10

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述

2.8 指针、数组、函数

案例描述: 封装一个函数,利用冒泡排序,实现对整型数组的升序排序

例如数组:int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };

#include <iostream>  // 包含标准输入输出流文件
using namespace std;  // 使用标准命名空间

// 冒泡排序函数
void bubbleSort(int* arr, int len)  // int * arr 也可以写为int arr[];数组首地址;数组长度
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

// 打印数组函数
void printArray(int arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}

	cout << endl;
}

int main() {
 
	int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
	int len = sizeof(arr) / sizeof(int);  // 数组长度

	bubbleSort(arr, len);

	printArray(arr, len);  // 1,2,3,4,5,6,7,8,9,10

	system("pause");  // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果

	return 0;  // 程序正常退出
}

在这里插入图片描述


总结

(1)、函数定义里小括号内称为形参,函数调用时传入的参数称为实参;

(2)、值传递时,形参是修饰不了实参的;

(3)、我们可以通过 & 符号 获取变量的地址;

(4)、利用指针可以记录地址;

(5)、对指针变量解引用,可以操作指针指向的内存;

(6)、所有指针类型在32位操作系统下是4个字节;

(7)、空指针和野指针都不是我们申请的空间,因此不要访问;

(8)、技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量;

(9)、如果不想修改实参,就用值传递,如果想修改实参,就用地址传递;

(10)、当数组名传入到函数作为参数时,被退化为指向首元素的指针。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/431954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cross compiling Windows binaries from Linux

IntroductionWhy? SpeedCostContainers k8sRejected Strategies Using x86_64-pc-windows-gnuUsing wine to run the MSVC toolchainHow? Prerequisites1. Setup toolchain(s)2. Acquire Rust std lib3. Acquire CRT and Windows 10 SDK4. Override cc defaults5. ProfitBon…

机器学习 探索性数据分析

文章目录1. 数据总览1.1 查看数据的维度1.2 查看列的数据类型1.3 查看索引1.4 获取数据值1.5 数据集相关信息概览1.6 查看数据的统计信息1.7 查看前3行数据2. 缺失值查看与处理2.1 缺失值查看2.2 缺失值处理3. 异常值检测与处理3.1 异常值检测3.2 异常值处理4. 特征分析4.1 查看…

计算机网络考试复习——第4章 4.6

理想的路由算法&#xff1a;几个特点 1.算法必须是正确和完善的 2.算法在计算上应该简单 3.算法能适应通信量和网络拓扑的变化具有自适应性也称为稳健性 4.算法应该具有稳定性 5。算法应该是公平的 6.算法应该是最佳的 关于“最佳路由”——不存在一种绝对的最佳路由算法…

第二章 法的内容与形式

目录 第一节 法的内容与形式的概念 一、法的内容与形式的含义 二、法的内容和形式的关系 第二节 法律权利与法律义务 一、权利和义务的概念 二、权利和义务的分类 三、权利与义务的联系 第三节 法的成文形式与不成文形式 一、历史上各种法的表现形式 二、成文法与不成文…

defaultdict 默认值

文章目录 前言语法setdefault()和defaultdict()的区别setdefault()defaultdict() 前言 在字典中查找某一个值的时候&#xff0c;若key不存在就会返回一个keyerror错误而不是一个默认值&#xff0c;如果想要返回一个默认值可以使用defaultdict函数。 defaultdict是python内建dic…

从0搭建Vue3组件库(三): 组件库的环境配置

本篇文章将在项目中引入 typescript,以及手动搭建一个用于测试组件库组件 Vue3 项目 因为我们是使用 ViteTs 开发的是 Vue3 组件库,所以我们需要安装 typescript、vue3,同时项目将采用 Less 进行组件库样式的管理 pnpm add vuenext typescript less -D -w 使用pnpm如果要安装在…

【C语言】void 和 void* 类型

一. void 类型 1. 为何不能定义 void 类型的变量 为什么不能定义 void 类型的变量&#xff1f;因为它是空类型&#xff0c;不能够为变量提供空间吗&#xff1f; 定义变量的本质是开辟空间&#xff0c;我们用 sizeof 来计算 void 类型的大小&#xff1a; 在vs2017下&#xf…

Direct3D 12——模板——平面阴影效果

平行光阴影 图展示了由平行光源经物体所投射岀的阴影。给定方向为L的平行光源&#xff0c;并用r&#xff08;t&#xff09;p tL来表 示途经顶点p的光线。光线r &#xff08;t&#xff09;与阴影平面(n,d&#xff09;的交点为S。以此光源射出的光线照射到物体的各个顶点&#x…

Stable Diffusion本地搭建windows and linux(附搭建环境)

linux搭建过程以centos为例 1.使用git工具下载项目文件到本地文件夹&#xff0c;命令如下&#xff1a; git clone https://github.com/IDEA-CCNL/stable-diffusion-webui.git然后进入该文件夹&#xff1a; cd stable-diffusion-webui2.运行自动化脚本 运行webui.sh安装一些p…

2023最新接口自动化测试面试真题详解,看完轻松拿捏HR

目录 一.有接口测试工具为什么还需要开发自动化框架或自动化平台。 二.接口自动化中如果一个接口请求不通该如何排查 三.你平常做接口自动化的过程中发现过哪些bug?多吗&#xff1f; 四.你在接口自动化中是怎么校验接口返回结果是否正确&#xff1f; 五、接口自动化回归过程中…

【C生万物】 操作符篇

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; 前言&#xff1a; 我觉得学习语言&#xff0c;最直接的就是懂不懂符号&#xff0c;而符号中最突出的就是操作符&#xff0c;这期带大家认识认识C语言中的操作符及其使用。 目录 Part1:算数操作符 Part2:移…

直方图均衡化(调节图像亮度、对比度)

直方图均衡化&#xff08;调节图像亮度、对比度&#xff09; 本篇目录 &#x1f984; 一、前言 &#x1f984; 二、直方图均衡化概念 &#x1f984; 三、直方图均衡化实例 &#xff08;1&#xff09;、灰度图像的均衡处理实例 ①、卡通人物灰度图像均衡处理 ②、卡通猫头…

音频编辑开发SDK Audio DJ Studio for .NET Crack

11.7版本--Audio DJ Studio for .NET是 MultiMedia Soft 开发的 .NET Windows Forms 自定义控件&#xff0c;可以轻松地向使用Microsoft Visual Studio编写的Winform和WPF 应用程序添加声音播放和混音功能&#xff1b;由于与 DirectShow 编解码器和 BASS 库的集成&#xff0c;两…

【UITableView和UITableViewCell的常见属性 Objective-C语言】

一、UITableView和UITableViewCell的常见属性, 1.我们说,这些属性里面, 2.这些是不是都是单元格的属性, 1)这个imageView:是单元格里面的图片框,是不是指的是这个啊, 2)这个textLabel:是指的这个标题上面这个Label吧, 3)这个detailTextLabel:是指的标题下面这…

安装tomcat8,配置服务启动脚本,部署jpress应用

1. 简述静态网页和动态网页的区别。 静态网站顾名思义就是不能动的网站&#xff0c;其中的内容一旦做好就固定了。而动态网站是一种网页编程技术&#xff0c;它可以使得浏览器和服务器可以交互&#xff0c;根据服务器的不同请求动态的生成网页内容。 3. 简述 Webl.0 和 Web2.…

基于STM32的倒车雷达系统设计

目录 前言 一、绪论 1.1 设计背景 1.2 设计内容 二、系统硬件设计 2.1 硬件系统框图 2.2 主控制电路 2.3 超声波电路 2.4 OLED显示电路 2.5 键盘输入电路 2.6 声光报警模块电路 三、系统软件设计 3.1 系统主程序设计 3.2 OLED显示程序设计 3.3 键盘设定程序设计…

设计模式-结构型模式之外观模式

4. 外观模式4.1. 模式定义外观模式(Facade Pattern)&#xff1a;外部与一个子系统的通信必须通过一个统一的外观对象进行&#xff0c;为子系统中的一组接口提供一个一致的界面&#xff0c;外观模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。外观模式…

C++11 make_shared函数和std::make_unique详解

make_shared的使用: shared_ptr<string> p1 make_shared<string>(10, 9); shared_ptr<string> p2 make_shared<string>("hello"); shared_ptr<string> p3 make_shared<string>(); 好处&#xff1a;减少分配次数 std::s…

大厂面试内幕:阿里内部整理出的5000页Java面试复盘指南,起飞!!!

互联网的技术岗一直是高薪的代名词&#xff0c;特别是大厂&#xff0c;应届生的年薪基本都20W起&#xff0c;比一般的公司高多了。 看下面这张网上热传的大厂应届生薪酬表就知道了&#xff0c;SP offer甚至能拿到30W以上。 技术社区也有晒出高薪offer的同学&#xff1a; 除了薪…

Unity LOD 技术

Unity LOD 技术 LOD(Level of detail) 多层次细节&#xff0c;常用的Unity 优化技术 它是根据物体在游戏画面中所占视图百分比来调用显示不同精度的模型 说白了就是 当物体距离摄像机距离较近时显示高精度模型 当物体距离摄像机距离较远时显示低精度模型 优点&#xff1a;优化…