【Cpp】指针与引用

前言

在C语言中,我们对指针的规范并不严谨------我们常常会用void*来传入一个不知道其变量类型的指针,为了兼容CCpp允许这样的语法存在,但是,由于这样的指针不具有安全性,我们无法通过*来解引用void*,这就需要用到我们的显式转换 。为了方便看指针的引用而不是由一堆*组成了参数和参数类型,我们采用引用来让这种写法变得更加简洁;

文章目录

指针

什么是指针?指针是一个数字,是一个存储内存地址的数值。 指针是用来给我们取址用的操作,方便我们对数据的读取和写入,因为我们在代码中所做的每一件事,都是从内存中读取或写入内存------类型只是我们虚构出来的东西,好让我们这群写程序的知道这个指针到底有多少个字节组。

cpp 复制代码
//The Example is from the Cherno
#include<iostream>

int main(){
    void* ptr=0;//我们就这样创造出来了第一个指针变量
    //std::cin.get();
    return 0;
}

内存地址不会是00是无效的一个数值,我们也用NULL来表达其值为空,对于指针来说,无效是一个完全可以接受的状态 ,++人家接受得了许多失败++ ,但是,很遗憾的是,0既然意味着没有,那么就是说该数值无法读取或写入。

当然,#defined NULL 0说明了在预处理器上NULL就被处理成了0,我们在C++11引入了一个新的概念,称之为nullptr

请避免将 NULL 或零 (0) 用作 null 指针常量;nullptr 不仅不易被误用,并且在大多数情况下效果更好。

例如,给定 func(std::pair<const char *, double>),那么调用func(std::make_pair(NULL, 3.14)) 会导致编译器错误。 宏 NULL 将扩展到 0,以便调用std::make_pair(0, 3.14)将返回 std::pair<int, double>,此结果不可转换为 funcstd::pair<const char *, double> 参数类型。

调用 func(std::make_pair(nullptr, 3.14)) 将会成功编译,因为 std::make_pair(nullptr, 3.14) 返回 std::pair<std::nullptr_t, double>,此结果可转换为 std::pair<const char *, double>

------From nullptr, the pointer literal (since C++11) - cppreference.com

类型完全不会影响指针

我们有:

cpp 复制代码
#include<iostream>

int main(){
    int var=23;
    void* ptr=&var;
    return 0;
}

这个时候void*可以接收到varint类型变换,

cpp 复制代码
#include<iostream>

int main(){
    int var=23;
    double var=(double)&var;
    return 0;
}

我们会发现在指针中获得的地址还是跟先前从void*中读取到的int的数值一样,这就证明了指针类型只是一种辅助工具,帮助我们和编译器去理解这个变量的类型。

cpp的强制转换类型是比c语言灵活一点 double(var)也可以。

我们解引用 告诉编译器,这是一个intshortlonglong的变量,这样我们好确定我们的如何从内存中读取计算出我们的数值。

当然,我们可以利用char*new关键字来确定一个内存大小。

cpp 复制代码
#include<iostream>

int main(){
    char* buffer=new char[8];
    memset(buffer,0,sizeof buffer);
    
    char** ptr=&buffer;
    
    delete[] buffer;//用完后删除
    return 0;
}

引用

引用(Reference)实际上是指针(Pointer)的一个扩展,我们如何写他们,和应用他们都有所不同,但是,本质上他们并无二异义,并且引用只能算一种语法糖

cpp 复制代码
#include<iostream>

int main(){
    int a=5;
    int& ref=a;//ref这个'变量'其实是引用。
    ref=2;//实际上就是'变量'a这个主体变成了2.
    return 0;
}

就好比说,我叫MongXin,但是我身份证不叫MongXin,在警察局里找不到MongXin,却不能说明这个引用不存在------同样的,申明完一个引用后,其并不真实存在,但是其就是那个变量的别名 ;我可以注册一个电话号码,注册完之后它即属于我身份证上的名字,也属于MongXin ,同样的,ref就是有这样的作用,我们可以把它当a使用。

&不可更改

就像你有好几个好朋友,但是你能把好朋友A的别名冠给好朋友B吗?这本身算是一种不礼貌的行为,我们的Cpp是一位绅士,拒绝这种情况的发生。

cpp 复制代码
#include<iostream>

int main(){
    int a=5;
    int b=8;
    int& ref=a;//ref这个'变量'其实是引用。
    int& ref=b;//ERROR
    return 0;
}

这点跟指针的const void*一样,我们无法更改我们指向的内存空间,但是不妨碍我们把我们的家具挪一挪变成一个新的数值。

pass-by-value和pass-by-reference

如果我们有:

cpp 复制代码
#include<iostream>

void Increment(int val){
    val++;
}

void log(int val){
    std::cout<<val<<endl;
}

int main(){
    int a=5;
    Increment(a);
    log(a);
    return 0;
}

我们会发现打印出来的数值是5,并没有增加,而我们稍微动脑筋就知道,这个时候val是一个局部变量,它是copy出来的一份数据,局部变量传不出去,我们将这种引用数值的方式称之为Pass-by-valuePass-by-value 在不需要更改数值的时候可以使用,但是在我们对数值需要更改的情况下就显得笨拙,这时候我们采用------一种引用地址的方式,Pass-by-reference

cpp 复制代码
#include<iostream>

void Increment(int* val){
    (*val)++;
}

void log(int val){
    std::cout<<val<<endl;
}

int main(){
    int a=5;
    Increment(&a);
    log(a);
    return 0;
}

我们也存在利用引用的情况:

cpp 复制代码
#include<iostream>

void Increment(int& val){
    val++;
}

void log(int val){
    std::cout<<val<<endl;
}

int main(){
    int a=5;
    Increment(a);
    log(a);
    return 0;
}

通过引用,我们会发现我们重写了这段代码,但是在编译后,我们得到的代码是一样的,只不过我们的源码现在看起来很容易懂。

二者差异

唯二的区别就是,写法不一样,以及引用名并不真实存在。

如果通过指针:

cpp 复制代码
void log(*val){}//这里是解引用

int val=3;
int* ptr=&val;
log(ptr);//相当于log(&val);

如果通过引用:

cpp 复制代码
void log(&val){}//这里是&

int val=3;
log(val);

写在后面

我们发现CppC本质上还是有差别的,一些C里面麻烦的东西在Cpp中得到了优化,而且Cpp还可以兼容运行C,这就说明了Cpp的兼容性高,这也是我们下一篇章的的重点。

相关推荐
Brookty28 分钟前
【算法】归并排序
数据结构·算法·排序算法
·醉挽清风·30 分钟前
学习笔记—C++—模板初阶
开发语言·c++·笔记·学习
虾球xz2 小时前
游戏引擎学习第216天
服务器·c++·学习·游戏引擎
星星火柴9363 小时前
数据结构:哈希表 | C++中的set与map
数据结构·c++·笔记·算法·链表·哈希算法·散列表
没有啥的昵称5 小时前
从源码安装ROS的serial包(替换github的方案)
c++
CS创新实验室5 小时前
数据结构:最小生成树的普里姆算法和克鲁斯卡尔算法
数据结构·算法·图论·计算机考研
夏天的阳光吖6 小时前
C++蓝桥杯实训篇(四)
开发语言·c++·蓝桥杯
小乐xiaole7 小时前
蓝桥杯 2025 C++组 省 B 题解
c++·蓝桥杯·深度优先
晓纪同学7 小时前
C++ Primer (第五版)-第十三章 拷贝控制
java·开发语言·c++
独家回忆3648 小时前
每日算法-250415
算法