C++学习-入门到精通-【6】指针

C++学习-入门到精通-【6】指针


指针


一、指针的初始化

指针在声明或赋值时,应该被初始化为nullptr(C++11的新特性),或是一个相应类型的地址。当一个指针变量的值为nullptr时就称其为空指针。

注意所有使用的指针都应该进行初始化,以防止其指向一个未知的或未被初始化的内存空间

在早期的C++ 版本中,为空指针指定的值为0或者是NULL。NULL在多个标准库头文件中被定义,用来表示值0。

注意:声明中的*不是运算符,它只是表明正在被声明的变量是一个指针

二、指针运算符

地址运算符&

地址运算符是一个一元运算符,它获得操作数的内存地址。例如:

cpp 复制代码
int y = 5; // 声明一个int类型的变量
int *yPtr = nullptr; // 声明一个指向int类型的指针变量,并初始化为nullptr

yPtr = &y; // 将y的地址赋值给yPtr

此时可以说变量yPtr指向y,yPtr间接引用变量y的值。

注意区分地址运算符&和引用变量声明中的&

间接引用运算符*

一元的*运算符通常称为间接运算符或间接引用运算符,它返回一个左值,表示其指针操作数所指向的对象。例如:

cpp 复制代码
cout << *yPtr << endl;

该语句输出变量y的值,即5,与下面的语句等价;

cpp 复制代码
cout << y << endl;

提示

间接引用一个空指针或未初始化的指针会导致不确定的行为,而且通常是一个致命的运行时错误,因此,在间接引用之前程序员应该明确知晓这个指针是指向哪里。

使用地址运算符&和间接引用运算符

cpp 复制代码
#include <iostream>

using namespace std;

int main()
{
	int a = 7;
	int *aPtr = &a;

	cout << "The address of a is " << &a
		<< "\nThe value of aPtr is " << aPtr << endl;
	cout << "\nThe value of a is " << a 
		<< "\nThe value of *aPtr is " << *aPtr << endl;
}

运行结果:

三、使用指针的按引用传递方式

cpp 复制代码
#include <iostream>

using namespace std;

void cubeByReference(int* x)
{
	*x = (*x) * (*x) * (*x);
}

int main()
{
	int i = 3;

	
	cout << "Cube of " << i << " is ";
	cubeByReference(&i); 
	cout << i << endl;
}

运行结果:

在C++中,所有的参数其实都是按值传递的。以使用指针变量的按引用传递方式传递一个变量实质上并没有按引用传递任何东西,传递的其实是这个变量的指针(这个变量的地址),将该地址复制到函数对应的指针形参中。然后被调函数可以通过间接引用这个指针来访问调用者中的这个变量,从而完成按引用传递。

四、内置数组

标准库函数的begin和end

在之前的章节中我们使用sort函数对一个元素类型为string的array对象进行排序,使用语句如下:

cpp 复制代码
sort(colors.begin(), colors.end());

array类中的begin和end函数指定了排序的范围------整个array对象。对于内置数组而言,我们也可以使用sort对它进行排序,例如:

cpp 复制代码
int n[5] = {5,3,4,2,1};
sort(begin(n), end(n));

注意之前介绍过的基于范围的for语句,它其实也是使用了循环对象的begin和end函数来确定循环的范围。

内置数组的局限性

  • 无法使用关系和相等运算符进行比较。如果要比较两个数组,需要使用循环,一个一个的进行比较;
  • 不能相互赋值;
  • 它们不知道自己的大小。处理一个内置数组的函数通常接收两个参数,一个是这个数组的名字,另一个是这个数组的大小;
  • 它们不提供边界检查功能,需要程序员手动检查是否越界;

五、使用const修饰指针

一个好的程序应该是遵循最小特权原则的,也就是一个函数是有足够的权限访问函数参数中的数据来完成指定的任务的,但是权限不能过大。

在之前写过的代码中我们也遵循着这样的原则,还记得之前使用过的const关键字吗。我们就更通过这个关键字实施最小特权原则的。

例如要打印一个array对象中的元素,但是不需要修改它:

cpp 复制代码
array <int, 5> arr = { 1,2,3,4,5 };

for(const int& item : arr)
{
	cout << item << " ";
}
cout << endl;

上面的例子中使用一个引用变量来访问array对象中的元素,前面加上了一个const表明,在这个作用域中,item这个别名不应该修改它引用的值。这就保证在这个输出函数中,不会出现不合法的修改行为,导致出错。

将指针传递给函数有4种方式:指向非const数据的非const指针、指向const数据的非const指针、指向非const数据的constant指针、指向const数据的const指针;

看上去好像比较复杂,但是通过下图可以很容易的分辨它们:

cpp 复制代码
int * i;
相关推荐
一隅论数智3 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
weilx12343 天前
C++笔记-文件IO-<fcntl.h>
c++
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
爱吃苹果的日记本3 天前
离散数学第六课
学习·离散数学
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
Smileyqp沛沛3 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++