C++指针(三)

个人主页:PingdiGuo_guo

收录专栏:C++干货专栏

文章目录

前言

1.字符指针

1.1字符指针的概念

1.2字符指针的用处

1.3字符指针的操作

1.3.1定义

1.3.2初始化

1.4字符指针使用注意事项

2.数组参数,指针参数

2.1数组参数

2.1.1数组参数的概念

2.1.2数组参数的作用

2.1.3一维数组的传参

2.1.4二维数组的传参

2.2指针参数

2.2.1指针参数的概念

2.2.2指针参数的作用

2.2.3一级指针与二级指针

2.2.3一级指针的传参

2.2.4二级指针的传参

2.3练习

2.3.1数组参数的练习题目

2.3.2指针参数的练习题目

总结


前言

相关文章:C++指针(二)、C++指针(一)

本篇博客是介绍字符指针,数组参数与指针参数的。

点赞破五十,更新下一期。

1.字符指针

1.1字符指针的概念

字符指针是指向字符数组或字符串的指针。在C语言中,字符数组和字符串都是以字符指针的形式来操作和访问的。字符指针指向字符数组或字符串的第一个字符的地址,通过指针可以访问数组或字符串中的各个字符。

1.2字符指针的用处

字符指针有很多用途,以下是一些常见的用途:

1. C字符串操作:字符指针可以用来处理C字符串,包括字符串的拷贝、连接、比较等操作。由于C字符串以null字符结尾,我们可以使用字符指针来访问和操作字符串的每个字符。

2. 字符串数组访问:字符指针可以用于访问字符串数组中的每个字符串。通过递增指针的方式,可以依次访问字符串数组中的每个元素。

3. 动态内存分配:字符指针可以用于动态分配内存,即在程序运行时根据需要分配内存空间。通过使用`new`运算符,可以分配一段连续的内存,并返回第一个元素的指针。

4. 字符指针数组:字符指针可以用于创建指向字符的指针数组。这在处理多个字符串时非常有用,每个指针可以指向一个独立的字符串。

5. 文件操作:字符指针可以用于进行文件的读取和写入操作。通过指针的方式,我们可以逐字符或逐行读取文件内容,并将指针移动到文件的特定位置。

这些只是字符指针的一些常见用途,实际上,字符指针在C和C++中有广泛的应用,可以用于字符串处理、动态内存管理、文件操作等多种场景。

1.3字符指针的操作

1.3.1定义

字符指针需要关键字char*来定义,其他部分与普通指针的定义相同。如下:

char* ptr;

这样,我们就定义了一个字符指针。

1.3.2初始化

字符指针初始化有两种方式:

1.定义一个字符并为其赋值,然后用&来获取这个字符变量的地址。代码如下:


#include <bits/stdc++.h>
using namespace std;
int main()
{char ch = 'w';char* pc = &ch;cout<<*pc<<endl;return 0;
}

到这里,可能有些同学会疑惑:*pc里不是存储了变量ch的地址了么,为啥输出的是ch里的呢?

这里我们要注意,在代码中,*pc是一个解引用操作符,它用于获取指针pc所指向的内存地址上存储的值。在这种情况下,*pc表示获取指针pc所指向的内存地址上存储的字符。所以,cout<<*pc输出的是ch里的值,即字符w

那可能有些同学又要问了:PingdiGuo_guo,那啥情况输出的是地址呢?

注意:当我们直接输出指针变量本身时,会输出该指针变量所存储的地址而不是地址上的值。如果要输出指针变量所指向的地址上的值,需要使用解引用操作符*。

以下是一个例子:

#include <iostream>
using namespace std;int main() {int x = 10;int* ptr = &x;cout << ptr << endl;   // 输出指针变量ptr的值,即x的地址cout << *ptr << endl;  // 输出指针ptr所指向的地址上存储的值,即x的值return 0;
}

上述代码输出结果:

第一行输出的是指针变量ptr存储的地址,第二行输出的是指针ptr所指向的地址上存储的值。

2.我们直接把一个字符串赋值给指针变量。如下:

​#include <iostream>
using namespace std;
int main()
{const char* ps = "hello.";cout<<ps<<endl;return 0;
}​

大家看一看,运行上述代码,*ps里储存的是什么呢?

有同学觉得储存的的应该是字符串"hello."的地址,实际上储存的是字符串"hello."的首字符,也就是字符'h'的地址。

1.4字符指针使用注意事项

字符指针使用注意事项:


1. 注意字符串的结束符:C语言中的字符串以'\0'作为结束符,因此在使用字符指针操作字符串时,需要确保字符串末尾有一个'\0'字符,否则可能导致未定义的行为。

2. 避免修改字符串常量:字符串常量是只读的,因此尝试修改字符串常量的内容会导致编译错误或者运行时错误。如果需要修改字符串,应该使用可修改的字符数组或者动态分配内存的字符指针。

3. 空指针检查:在使用字符指针之前,应该进行空指针检查,以避免对空指针进行操作,导致程序崩溃或者出现未定义的行为。

4. 确保指针指向有效的内存区域:在使用字符指针操作字符串时,应确保指针指向的内存区域包含了足够的空间,以存储字符串的内容,并且字符串的结束符'\0'也需要在指针指向的内存区域内。

5. 避免指针越界访问:在使用字符指针操作字符串时,应避免指针越界访问,即超过了字符串的有效范围进行访问,这可能导致程序崩溃或者出现未定义的行为。

6. 避免指针悬挂:在使用字符指针时,需要确保指针指向的内存区域有效,并且在指针不再使用时及时释放或者置为NULL,以避免产生悬挂指针或者内存泄漏的问题。

7. 注意指针运算的规则:字符指针支持指针运算,例如指针加法和指针减法,但要注意指针运算时遵循指针的类型大小,以避免指针运算越界或者计算错误。

8. 使用函数库提供的字符串操作函数:C语言提供了一系列函数库来操作字符串,例如strcpy、strlen、strcat等,使用这些函数能够更方便、安全地操作字符串,同时避免常见的错误。

2.数组参数,指针参数

2.1数组参数

2.1.1数组参数的概念

数组参数是指在函数的参数列表中声明一个数组作为参数。当函数被调用时,实际传递给该参数的是数组的地址,而不是整个数组本身。通过使用数组参数,可以将数组的内容传递给函数,并在函数中对数组进行操作或者返回相应的结果。

2.1.2数组参数的作用

数组参数在函数中的作用主要包括以下几点:

1. 传递数组数据:通过数组参数,可以将数组的数据传递给函数进行处理。函数可以读取、修改数组的元素,执行各种操作。

2. 减少内存开销:使用数组参数可以避免将整个数组的副本传递给函数,而是只传递数组的地址或首元素地址。这样可以减少内存开销和数据复制次数。

3. 返回数组数据:函数也可以通过数组参数返回数据。在函数内部修改数组元素后,函数外部的数组也会被修改。

4. 可变长度数组:在函数参数中使用可变长度数组,可以根据需要传递不同大小的数组。这样可以编写更加灵活的函数,适应不同规模的数据。

5. 简化代码:通过使用数组参数,可以将对数组的一系列操作封装在函数中,提高代码的可读性和可维护性。

总的来说,数组参数可以使函数更加灵活、高效地处理数组数据,提高代码的可复用性和可维护性。它是C语言中非常重要的函数参数类型之一。

2.1.3一维数组的传参

void is(int a[])
{
}
void id(int a[100])
{
}
void ih(int* a[10])
{
}
​
void ij(int* a)
{
}​
void ig(int** a)
{
}

注:上述这些格式都可以运行。

2.1.4二维数组的传参

二维数组的传参基本形式与一维数组类似,只是在声明参数时需要指明数组的行数和列数。

// 形参为二维数组,指定列数的方式
void functionName(dataType arrayName[][columns], int rows) {// 函数体// 可以通过双重循环访问和修改数组元素
}
// 形参为二维数组,指定指针的方式
void functionName(dataType *arrayName[], int rows, int columns) {// 函数体// 可以通过双重循环访问和修改数组元素
}
// 形参为二维数组,指定指向指针的指针的方式
void functionName(dataType **arrayName, int rows, int columns) {// 函数体// 可以通过双重循环访问和修改数组元素
}

在上述代码中,dataType是数组中元素的数据类型,arrayName是二维数组的名称,rows是数组的行数,columns是数组的列数。

在函数参数列表中,我们可以使用dataType arrayName[][columns]或者dataType *arrayName[]或dataType **arrayName来声明一个二维数组作为参数。

在函数体内部,可以使用双重循环来访问和修改二维数组的元素。

2.2指针参数

2.2.1指针参数的概念

指针参数是指函数中的参数被声明为指针类型的参数。指针参数允许函数通过引用传递内存地址,从而能够修改原始数据的值。

2.2.2指针参数的作用

指针参数的作用有以下几个方面:

1. 传递大型数据结构:通过将指针作为参数传递给函数,可以避免复制整个数据结构。这对于大型结构体或数组来说尤为重要,可以提高程序性能。

2. 在函数内部修改变量的值:通过传递指向变量的指针作为参数,函数可以直接修改变量的值。这对于需要在函数中修改全局变量或者需要通过函数返回多个值的情况非常有用。

3. 动态内存分配:通过指针参数,可以在函数内部对动态分配的内存进行操作。例如,在函数中动态创建一个数组,并通过指针参数返回数组的地址。

4. 传递数组:通过将数组的首地址作为指针参数传递给函数,可以在函数内部操作数组中的元素。

需要注意的是,使用指针参数需要谨慎,避免出现空指针或者越界访问等问题。在使用指针参数时,需要确保传递正确的地址,并在函数内部对指针进行适当的处理和保护。

总之,指针参数在函数传参中具有重要作用,可以通过引用传递内存地址,实现对变量和数据的修改和操作。

2.2.3一级指针与二级指针

一级指针和二级指针是指针的不同级别。

一级指针(Level 1 Pointer)是指一个指针变量(如int*)指向一个存储地址,该地址保存了一个值或者另一个指针。通过一级指针可以直接访问到被指向的内存地址中的值。

二级指针(Level 2 Pointer),也被称为指向指针的指针,是指一个指针变量(如int**)存储了一个指针的地址。通过二级指针可以间接地访问到被指向的内存地址中的值。

二级指针常用于需要对一级指针进行修改的情况,例如在函数中传入一个指针的指针,以便修改指针的值。同时,你也可以定义三级指针、四级指针以及更高级别的指针,但在实际开发中很少用到。

2.2.3一级指针的传参

一级指针的传参是通过将指针作为函数的参数传递给函数

在函数中,可以通过一级指针来访问和修改指针所指向的值。

下面是一级指针传参的基本形式:

void func(int* ptr) {// 使用指针访问和修改指针所指向的值*ptr = 10;// ...
}int main() {int x = 0;int* p = &x;// 将指针p作为参数传递给函数funcfunc(p);// x的值已经被修改为10return 0;
}


 

在上面的例子中,通过将指针p作为参数传递给函数func,函数内部可以通过指针ptr来访问和修改p所指向的值。在函数中,通过解引用操作符*来访问指针所指向的值。

需要注意的是,传递一级指针作为参数时,函数内部对指针所指向的值的修改是有效的,因为传递的是指针变量本身的地址,而不是指针变量的副本。

问:在这种情况下,函数能接受什么参数?

答:在这种情况下,函数func可以接受一个指向整型变量的指针作为参数。在main函数中,通过将指针p作为参数传递给func函数,函数func可以使用指针访问和修改指针所指向的值。

2.2.4二级指针的传参

二级指针的传参是通过将指向指针的指针作为函数的参数传递给函数

二级指针在某些情况下用于传递指针数组或二维数组的地址,或者用于动态分配内存等场景。

下面是二级指针传参的基本形式:


 

void func(int** ptr) {// 使用二级指针访问和修改指针所指向的值**ptr = 20;// ...
}int main() {int x = 0;int* p = &x;int** pp = &p;// 将二级指针pp作为参数传递给函数funcfunc(pp);// x的值已经被修改为20return 0;
}

在上面的例子中,通过将二级指针pp作为参数传递给函数func,函数内部可以通过二级指针ptr来访问和修改pp所指向的值。在函数中,通过解引用操作符*两次来访问指针所指向的值。

需要注意的是,传递二级指针作为参数时,需要对指针进行两次解引用才能访问到最终的值。在函数内部修改指针所指向的值也是有效的。

此外,还要注意对于二维数组的传参,可以使用一级指针或二级指针来传递二维数组的地址。

问:在这种情况下,函数能接受什么参数?

答:在这种情况下,函数func可以接受一个指向指向整型变量的一级指针的二级指针作为参数。

2.3练习

2.3.1数组参数的练习题目

题目:

编写一个函数,接收一个整型数组和数组长度作为参数,并返回数组中的最大值。

步骤:
1. 在main函数中声明一个整型数组并初始化。
2. 定义一个函数findMax,接收一个整型数组和数组长度作为参数,并返回一个整型值。
3. 在findMax函数中,定义一个变量max,初始化为数组的首个元素。
4. 使用循环遍历数组,比较数组中的每个元素与max的值,并更新它。
5. 返回最大值。
6. 在main函数中调用findMax函数,并将返回值打印出来。

流程图:
 

开始
声明和初始化数组以及定义数组长度
定义函数findMax,接收数组和长度作为参数,并返回最大值
定义变量max,并初始化为数组的首个元素
循环遍历数组比较当前元素和max的值,若大于max,则更新max的值
返回max
调用findMax函数并打印返回值
结束


 

代码:
 

#include <iostream>int findMax(int arr[], int size) {int max = arr[0];for (int i = 1; i < size; i++) {if (arr[i] > max) {max = arr[i];}}return max;
}int main() {int arr[] = {3, 5, 1, 4, 2};int size = sizeof(arr) / sizeof(arr[0]);int max = findMax(arr, size);std::cout << "Max: " << max << std::endl;return 0;
}

在这个例子中,findMax函数接收一个整型数组和数组长度作为参数,并返回最大值。函数内部使用循环遍历数组,比较每个元素与max的值,并根据情况更新它。在main函数中声明数组arr并初始化,然后调用findMax函数并传递相应的参数,将返回值存储在max变量中,并使用std::cout 打印出来。

运行结果:

2.3.2指针参数的练习题目

题目:

编写一个函数,接收一个整型数组的指针和数组长度作为参数,并将数组中的所有元素翻转。

步骤:
1. 在main函数中声明一个整型数组并初始化。
2. 定义一个函数reverseArray,接收一个指向整型数组的指针和数组长度作为参数,并将数组中的所有元素翻转。
3. 在reverseArray函数中,使用两个指针start和end,分别指向数组的起始和末尾位置。
4. 使用循环,交换`start`和`end`指针所指向的元素,并同时将`start`往后移动一位,`end`往前移动一位。
5. 循环继续,直到start指针超过或等于end指针。
6. 在main函数中调用reverseArray函数,并将修改后的数组打印出来。

流程图:
 

开始
声明和初始化数组以及定义数组长度
定义函数reverseArray,接收整型数组指针和长度作为参数
定义指针start,指向数组起始位置
定义指针end,指向数组末尾位置
循环,交换start和end指针所指向的元素,并同时移动start和end指针若start指针超过或等于end指针,则跳出循环
在main函数中调用reverseArray函数,并打印修改后的数组
结束


 

代码:

 

#include <iostream>void reverseArray(int* arr, int size) {int* start = arr;int* end = arr + size - 1;while (start < end) {int temp = *start;*start = *end;*end = temp;start++;end--;}
}int main() {int arr[] = {1, 2, 3, 4, 5};int size = sizeof(arr) / sizeof(arr[0]);std::cout << "Original array: ";for (int i = 0; i < size; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;reverseArray(arr, size);std::cout << "Reversed array: ";for (int i = 0; i < size; i++) {std::cout << arr[i] << " ";}std::cout << std::endl;return 0;
}

在这个例子中,reverseArray函数接收一个指向整型数组的指针和数组长度作为参数,并将数组中的所有元素翻转。函数内部使用两个指针start和end分别指向数组的起始和末尾位置,通过循环交换指针所指向的元素,并同时移动指针,直到start指针超过或等于`end`指针。在main函数中声明数组arr并初始化,然后调用reverseArray函数并传递相应的参数,将数组的元素翻转。最后使用std::cout打印出原始数组和翻转后的数组。

运行结果:

总结

本篇博客到这里就结束了,感谢大家的支持与观看,如果有好的建议欢迎留言,谢谢大家啦!

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

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

相关文章

生命篇---心肺复苏、AED除颤仪使用、海姆立克急救法、常见情况急救简介

生命篇—心肺复苏、AED除颤仪使用、海姆立克急救法、常见情况急救简介 文章目录 生命篇---心肺复苏、AED除颤仪使用、海姆立克急救法、常见情况急救简介一、前言二、急救1、心肺复苏&#xff08;CPR&#xff09;&#xff08;1&#xff09;适用情况&#xff08;2&#xff09;操作…

基于神经环路的神经调控可增强遗忘型轻度认知障碍患者的延迟回忆能力

简要总结 这篇文章提出了一种名为CcSi-MHAHGEL的框架&#xff0c;用于基于多站点、多图谱fMRI的功能连接网络&#xff08;FCN&#xff09;分析&#xff0c;以辅助自闭症谱系障碍&#xff08;ASD&#xff09;的识别。该框架通过多视图超边感知的超图嵌入学习方法&#xff0c;整合…

[WUSTCTF2020]level1

关键知识点&#xff1a;for汇编 ida64打开&#xff1a; 00400666 55 push rbp .text:0000000000400667 48 89 E5 mov rbp, rsp .text:000000000040066A 48 83 EC 30 sub rsp, 30h .text:000000…

cpp自学 day20(文件操作)

基本概念 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行结束都会被释放 通过文件可以将数据持久化 C中对文件操作需要包含头文件 <fstream> 文件类型分为两种&#xff1a; 文本文件 - 文件以文本的ASCII码形式存储在计算机中二进制文件 - 文件以文本的…

Gartner发布软件供应链安全市场指南:软件供应链安全工具的8个强制功能、9个通用功能及全球29家供应商

攻击者的目标是由开源和商业软件依赖项、第三方 API 和 DevOps 工具链组成的软件供应链。软件工程领导者可以使用软件供应链安全工具来保护他们的软件免受这些攻击的连锁影响。 主要发现 越来越多的软件工程团队现在负责解决软件供应链安全 (SSCS) 需求。 软件工件、开发人员身…

备赛蓝桥杯-Python-考前突击

额&#xff0c;&#xff0c;离蓝桥杯开赛还有十个小时&#xff0c;最近因为考研复习节奏的问题&#xff0c;把蓝桥杯的优先级后置了&#xff0c;突然才想起来还有一个蓝桥杯呢。。 到目前为止python基本语法熟练了&#xff0c;再补充一些常用函数供明天考前再背背&#xff0c;算…

榕壹云外卖跑腿系统:基于Spring Boot+MySQL+UniApp的智慧生活服务平台

项目背景与需求分析 随着本地生活服务需求的爆发式增长&#xff0c;外卖、跑腿等即时配送服务成为现代都市的刚性需求。传统平台存在开发成本高、功能定制受限等问题&#xff0c;中小企业及创业团队极需一款轻量级、可快速部署且支持二次开发的外卖跑腿系统。榕壹云外卖跑腿系统…

使用Docker安装Gogs

1、拉取镜像 docker pull gogs/gogs 2、运行容器 # 创建/var/gogs目录 mkdir -p /var/gogs# 运行容器 # -d&#xff0c;后台运行 # -p&#xff0c;端口映射&#xff1a;(宿主机端口:容器端口)->(10022:22)和(10880:3000) # -v&#xff0c;数据卷映射&#xff1a;(宿主机目…

【antd + vue】Modal 对话框:修改弹窗标题样式、Modal.confirm自定义使用

一、标题样式 1、目标样式&#xff1a;修改弹窗标题样式 2、问题&#xff1a; 直接在对应css文件中修改样式不生效。 3、原因分析&#xff1a; 可能原因&#xff1a; 选择器权重不够&#xff0c;把在控制台找到的选择器直接复制下来&#xff0c;如果还不够就再加&#xff…

Streamlit在测试领域中的应用:构建自动化测试报告生成器

引言 Streamlit 在开发大模型AI测试工具方面具有显著的重要性&#xff0c;尤其是在简化开发流程、增强交互性以及促进快速迭代等方面。以下是几个关键点&#xff0c;说明了 Streamlit 对于构建大模型AI测试工具的重要性&#xff1a; 1. 快速原型设计和迭代 对于大模型AI测试…

docker 运行自定义化的服务-后端

docker 运行自定义化的服务-前端-CSDN博客 运行自定义化的后端服务 具体如下&#xff1a; ①打包后端项目&#xff0c;形成jar包 ②编写dockerfile文件&#xff0c;文件内容如下&#xff1a; # 使用官方 OpenJDK 镜像 FROM jdk8:1.8LABEL maintainer"ATB" version&…

解决java使用easyexcel填充模版后,高度不一致问题

自定义工具&#xff0c;可以通过获取上一行行高设置后面所以行的高度 package org.springblade.modules.api.utils;import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.wr…

repo仓库文件清理

1. repo 仓库内文件清理 # 清理所有Git仓库中的项目 repo forall -c git clean -dfx # 重置所有Git 仓库中的项目 repo forall -c git reset --hard 解释&#xff1a; repo forall -c git clean -dfx&#xff1a; repo forall 是一个用于在所有项目中执行命令的工具。-c 后…

结合大语言模型整理叙述并生成思维导图的思路

楔子 我比较喜欢长篇大论。这在代理律师界被视为一种禁忌。 我高中一年级的时候因为入学成绩好&#xff08;所在县榜眼名次&#xff09;&#xff0c;直接被所在班的班主任任命为班长。我其实不喜欢这个岗位。因为老师一来就要提前注意到&#xff0c;要及时喊“起立”、英语课…

spark-core编程2

Key-Value类型&#xff1a; foldByKey 当分区内计算规则和分区间计算规则相同时&#xff0c;aggregateByKey 就可以简化为 foldByKey combineByKey 最通用的对 key-value 型 rdd 进行聚集操作的聚集函数&#xff08;aggregation function&#xff09;。类似于aggregate()&…

原理图设计准备:页面栅格模板应用设置

一、页面大小的设置 &#xff08;1&#xff09;单页原理图页面设置 首先&#xff0c;选中需要更改页面尺寸的那一页原理图&#xff0c;鼠标右键&#xff0c;选择“Schmatic Page Properties”选项&#xff0c;进行页面大小设置。 &#xff08;2&#xff09;对整个原理图页面设…

关于异步消息队列的详细解析,涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结

以下是关于异步消息队列的详细解析&#xff0c;涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结&#xff1a; 一、异步消息核心概念与JMS模式对比 1. 异步消息核心组件 组件作用生产者发送消息到消息代理&#xff08;如RabbitMQ、Kafka&#xff09;。消息代理中间…

【深度洞察】解码饮料行业破局点:场景革命

当东鹏特饮以 “大瓶装 防尘盖” 精准解决货车司机的场景化需求&#xff0c;当农夫山泉通过 “冷藏版东方树叶” 打开年轻白领的早餐场景 —— 这些现象级案例背后&#xff0c;是饮料行业底层逻辑的深刻变革&#xff1a;真正的市场增量&#xff0c;藏在对消费场景的极致拆解中…

二、TorchRec中的分片

TorchRec中的分片 文章目录 TorchRec中的分片前言一、Planner二、EmbeddingTable 的分片TorchRec 中所有可用的分片类型列表 三、使用 TorchRec 分片模块进行分布式训练TorchRec 在三个主要阶段处理此问题 四、DistributedModelParallel&#xff08;分布式模型并行&#xff09;…

如何在 Spring Boot 项目中使用 MyBatis 进行批量操作以提升性能?

MyBatis 提供了 ExecutorType.BATCH 类型&#xff0c;允许将多个 SQL 语句进行组合&#xff0c;最后统一执行&#xff0c;从而减少数据库的访问频率&#xff0c;提升性能。 以下是如何在 Spring Boot 项目中使用 MyBatis 进行批量操作的关键点&#xff1a; 1. 配置 MyBatis 使…