本章主要内容:
一,关于指针
1.指针的基础概念
2.指针的定义和使用
3.地址运算符&
4.解引用运算符*
5.char类型与指针
6.数组与指针
7.const与指针
二,关于引用
1.引用的基础概念
2.引用和指针的不同点
3.引用的初始化
4.函数的引用传参
5.函数的const引用传参
三,参考阅读
一,关于指针
1.指针的基础概念
指针是可存储地址的变量,存储在指针中的地址可以是变量或者其他数据的地址。
指针不仅仅是指向某地址,指针还关注指向该地址的数据类型。
例如:long* num_ptr {};
这里的num_ptr指针今后只能存储long类型的变量地址,尝试用它存储非long类型的变量地址将会产生编译报错。
注意,无论指针变量指向什么类型或者大小的数据,指针变量本身的大小是相同的,指针变量的大小仅仅取决于目标平台的可寻址内存的大小。例如,对于64位的计算机架构,指针变量的大小一般是8个字节。
2.指针的定义和使用
未初始化的指针使用起来风险很大,因此,定义指针的同时必须初始化,如果不知道指定什么样的初始值,可以先初始化为nullptr。
long* num_ptr {};
应该改为:
long* num_ptr {nullptr};
也可以使用自定义类型来初始化指针:
char16_t* char_ptr {nullptr};
对指针变量使用操作符”=”会改变指针的指向,所以,对指针采取赋值操作可以理解为指针方向的重定向。
例如,如果p1和p2是两个指针变量,”p2=p1″操作会让p2去指向p1当前正在指向的内存地址。
算术运算的本质是让指针沿着一定的方向去移动指定大小的单位。
拿指针的加法运算举例,整数会先和指针所指向的类型大小(单位是字节)相乘,得到偏移量,然后指针的初始地址按照这个偏移量往前移动一定的单位。
3.地址运算符&
int num=10;
int* p_num=#
auto p_num=# //也可以让编译器判断类型
auto* p_num=# //auto*,让代码更清晰
4.解引用运算符*
ptr = &data_1;
data_2 = *ptr;
5.char类型与指针
char* char_ptr {"Hello"};
const char* char_ptr {"Hello"};
注意,指向数值类型的指针必须解引用,才能拿到指针所指向的元素值。但是指向char类型的指针,可以不经过解引用,直接利用指针名获得元素的值。有时候,为了让代码更清晰,也会对char类型的指针做解引用操作。
完整C++代码实现:
#include <iostream>
using namespace std;
int main()
{
const char* char_ptr{ "Hello" };
std::cout << char_ptr[0] << std::endl;
std::cout << *char_ptr << std::endl;
std::cout << char_ptr[1] << std::endl;
std::cout << *(char_ptr + 1) << std::endl;
return 0;
}
运行结果:
H
H
e
e
6.数组与指针
该指针指向数组中的第一个元素。
当程序使用new分配一段内存块时,应使用delete来释放。但是当使用new创建数组时,应该使用”delete []”来释放数组。
int* p_array = new int [10];
delete [] p_array;
此时,访问该数组也很简单,可以把指针变量名当作数组名来使用。
完整C++代码实现:
#include <random>
#include <iostream>
#include <memory>
#include <functional>
int main()
{
int* p_array = new int[10];
p_array[0] = 11;
p_array[1] = 22;
std::cout << &p_array << std::endl;
std::cout << p_array << std::endl;
std::cout << p_array+1 << std::endl;
//指针变量当数组来用
std::cout << p_array[0] << std::endl;
std::cout << p_array[1] << std::endl;
//对数组指针解引用
std::cout << *p_array << std::endl;
std::cout << *(p_array+1) << std::endl;
delete [] p_array;
}
运行结果:
006CFCC4
00BEC170
00BEC174
11
22
11
22
指针与数组还可以形成另一种结构,被称为指针数组,数组的元素都是指针类型。指针数组的使用可以节省操作时间,如果要交换数组中的元素,只需要交换彼此的指针就可以实现,避免了很多复制操作。
如图,基于指针数组实现的二维数组:
#include <iostream>
using namespace std;
int main()
{
int N = 3;
int** p = new int* [N];
int x = 1;
for (int i = 0; i < N; i++) {
p[i] = new int[N];
for (int j = 0; j < N; j++, x++) {
p[i][j] = 10 * x;
}
}
cout << *p << endl;
cout << **p << endl;
cout << *p + 1 << endl;
cout << **p + 1 << endl;
cout << *(*(p + 1) + 0) << endl;
cout << p[2][2] << endl;
return 0;
}
015420A8
10
015420AC
11
40
90
7.const与指针
(1)指向常量的指针——存储的值为常量,指针为变量。
此时的指针常用来指向const类型的常量。
const int value {20};
const int* p_value=&value; //const类型的常量value
此时value是一个常量,它的大小不能被修改,但是可以修改p_value指向的地址,例如:
const int value_2 {30};
p_value=&value_2;
如果要禁止修改p_value指向的地址,可以在p_value前面再加一个const修饰符。
const int* const p_value=&value;
常量指针只能指向初始化时指定的固定地址,此时虽然指针指向的地址不可以被修改,但是地址存放的变量值可以被修改。
此时的指针常用来指向非const类型的变量。
int data {20}; //此时不能用const
int* const p_data=&data;
*p_data = 30; //data的值被修改为30
(3)指向常量的常量指针——存储的值为常量,指针为常量
const float value {3.1415f};
const float* const p_value=&value;
完整C++代码实现:
Demo1:
#include <iostream>
int main()
{
int x{ 5 };
int y{ 6 };
int* const ptr{ &x };
ptr = &y;
return 0;
}
运行结果:
编译报错:
“ptr”: 不能给常量赋值
Demo2:
#include <iostream>
int main()
{
int x{ 5 };
int* const ptr{ &x };
std::cout << x << std::endl;
std::cout << &x << std::endl;
*ptr = 6; //x的地址不变,值被改为6
std::cout << x << std::endl;
std::cout << &x << std::endl;
return 0;
}
运行结果:
5
004FFA60
6
004FFA60
二,关于引用
1.引用的基础概念
引用的用法和指针类似,引用可以看作是某变量的别名,变量的引用在用法上和变量完全对等。
2.引用和指针的不同点
3.引用的初始化
int value_1 {20};
int value_2 {20};
int* p_value=&value_1; //指针的初始化
int& r_value=value_2; //引用的初始化
*p_value += 10; //解引用
r_value += 10; //没有解引用
#include <random>
#include <iostream>
#include <memory>
#include <functional>
int main()
{
int value_1{ 20 };
int value_2{ 20 };
int* p_value = &value_1; //指针的定义
int& r_value = value_2; //引用的定义
*p_value += 10; //解引用
r_value += 10; //没有解引用
std::cout <<"value_1: " << value_1 << std::endl;
std::cout <<"value_2: " << value_2 << std::endl;
std::cout <<"data of value_1: " << *p_value << std::endl;
std::cout <<"address of value_1: " << p_value << std::endl;
std::cout <<"data of value_2: " << r_value << std::endl;
std::cout <<"address of value_2: " << &r_value << std::endl;
}
运行结果:
value_1: 30
value_2: 30
data of value_1: 30
address of value_1: 0048FAE8
data of value_2: 30
address of value_2: 0048FADC
4.函数的引用传参
5.函数的const引用传参
完整C++代码实现:
#include <iostream>
using namespace std;
void swap_1(int& x, int& y);
void swap_2(const int& x, const int& y);
int main() {
int a = 100;
int b = 200;
cout << "Before swap_1, value of a :" << a << endl;
cout << "Before swap_1, value of b :" << b << endl;
swap_1(a, b);
cout << "After swap_1, value of a :" << a << endl;
cout << "After swap_1, value of b :" << b << endl;
swap_2(a, b);
cout << "After swap_2, value of a :" << a << endl;
cout << "After swap_2, value of b :" << b << endl;
return 0;
}
void swap_1(int& x, int& y) {
int temp;
temp = x;
x = y;
y = temp;
return;
}
void swap_2(const int& x, const int& y) {
int temp;
temp = x;
/*
这样操作会产生编译报错
x = y;
y = temp;
*/
return;
}
Before swap_1, value of a :100
Before swap_1, value of b :200
After swap_1, value of a :200
After swap_1, value of b :100
After swap_2, value of a :200
After swap_2, value of b :100
三,参考阅读
《Beginning C++17, 5th Edition》
《C++ Primer Plus》
《C++高级编程》
https://en.cppreference.com/w/cpp/language/pointer
https://cplusplus.com/doc/tutorial/pointers/
https://www.programiz.com/cpp-programming/pointers-arrays
https://www.geeksforgeeks.org/creating-array-of-pointers-in-cpp/
原文始发于微信公众号(程序员与背包客):C/C++开发基础——指针与引用
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/128570.html