返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++扫盲篇之指针详解
  • 513
分享到

C++扫盲篇之指针详解

2024-04-02 19:04:59 513人浏览 泡泡鱼
摘要

目录前言指针为什么要有类型指针和数组二级指针指针与多态绑定函数指针类成员指针补充:用指针的指针指向指针数组总结前言 指针对于学习C/C++的人来说是一道必须迈过去的坎,就像学习九阳神

前言

指针对于学习C/C++的人来说是一道必须迈过去的坎,就像学习九阳神功必须要打通任督二脉一样的道理。虽然说随着智能指针的普及,很少需要程序员再手动操作原始指针, 但是如果你连原始指针的都没学好,那你怎么可能用好智能指针呢?

无论是原始指针还是智能指针,要想用好它就一定要做到知其然,知其所以然。

因为本文阅读对象是有了一定指针基础的童鞋,所以如果你对指针如果是处于一无所知的状态的话,建议先去温习下指针的基础知识,不然可能读起来会打击你求知的欲望。

指针为什么要有类型

是为了指针运算和取值。

当使用指针取值的时候需要知道怎么取值,比如按照多少个字节去取值,这是需要确定才能取到正确的值的,要知道用多少个字节去取就得知道指针的类型是什么。

我们知道指针的运算增加或者减少1意味着需要偏移指针所表示的类型的大小个字节数,比如说一个int字节的指针增加1,表示偏移4个字节(一般情况下int都是4个字节),所以这也是需要知道指针的类型。

指针和数组

本来从字面上来说指针和数组是八竿子打不着的,它们理应是井水不犯河水的,怎么就扯上了呢?我们经常听说数组指针、指针数组,这些都是什么意思呢?他们到底是指针还是数组呢?下面将一一为你解答。

指针数组,首先它是一个数组,数组里面的每个元素都是一个指针,例如比如int *p[4] 就是一个指针数组,因为运算符[]的优先级运算符*的优先级高,所以p优先和[]组成数组,然后*和类型int组合成数组元素的类型。 例如以下程序就是一个指针数组的示例:

main.c
#include <stdio.h>
int main(){
    char *str[3] = {
        "我是数组1",
        "我是数组2",
        "我是数组3"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}

数组指针,首先它是一个指针,这个指针所指向的对象是数组,比如这个指针是p,那么通过解引用*p获得内容就是一个数组,例如int (*p)[4],主意带上括号, 通常数组指针也作为一个二维数组来使用。

二级指针

所谓的二级指针其实就是一个指向指针的指针,例如int **p就是一个二级指针,它内部存放的对象是一个指针,通过一次解引用获得的是内存存放的指针的地址,需要再次对这个内部的指针进行解引用才能获取到 这个真是内容的值。

理解起来有点绕,那么这个拗口的二级指针有什么作用呢?二级指针在c++中可能用的不多,但是在C中是经常使用的一把利器,它通常作为一个函数的参数,起到在函数内部对一个指针进行初始化的作用, 比如经典的音视频处理工具FFmpeg中就大量使用了二级指针。 以下例子展示如何通过二级指针对指针形式赋值:

main.cpp
void initP(int **p){
    *p = new int(10);
}

int main() {
    int *p = nullptr; // 一个空的指针
    initP(&p); // 通过二级指针初始化指针p
    std::cout << "*p的值:" << *p << endl;
    delete p;
    return 0;
}

可能在这里就有人和当初笔者刚接触C语言一样迷惑了,难道不能通过给函数传递一级指针给指针初始化吗?这是不行的,这是因为值传递的缘故,像深入探讨的童鞋们可以写个例子打印下实参的具体地址对比下研究下其背后的原理。

指针与多态绑定

我们都知道C++是一门面向对象的设计语言,支持多态就是它的一个重要特性之一,在学习C++类的相关知识的时候老师就告诉我们:*在C++语言中,当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定。*也就是 说使用通过父类的指针或引用就能按照实参的实际类型是父类还是子类调用不同的虚函数。

例如如以下代码:

main.cpp
class Base{
public:
    virtual void print() const{
        std::cout << "base print" << endl;
    }
    virtual ~Base(){
    }
};

class Child:public Base{
public:
    void print() const override{
        std::cout << "Child print" << endl;
    }
};

void testPrint(const Base &base){
    base.print();
}

int main() {
    Base a = Child();
    testPrint(a);// 打印Base print
    Child b = Child(); // 注意,不能写成Base b = Child(),否则打印的是Base的print
    testPrint(b); // 打印Child print
    Base *c = new Child(); // 指针,动态类型与静态类型不一致
    testPrint(*c); // 打印Child print

    Base &&r = Child(); // 表达式是右值引用,动态类型与静态类型不一致
    testPrint(r); // 打印Child print
    return 0;
}

为什么在上面的程序中变量a的实际类型是Child,但是函数testPrint内部调用的却是父类的打印方法呢?不是说引用会触发多态吗?函数testPrint也是通过引用传递的呀, 真是百思不得其jie呀。

要解开这个疑惑就得了解下静态类型和动态类型的知识了。静态类型在编译时总是已知的,首先静态类型是变量声明时的类型或表达式生成的类型;动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才可知。 如果变量在定义时表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致的,也就是声明时所指的类型,否则的话静态类型可能与动态类型不一致。

那么有了静态类型与动态类型的概念之后再结合注释看上面的示例代码是不是就有一种拨开云雾见青天的感觉了呢?

函数指针

函数指针顾名思义就是指向函数的指针,它的定义:函数指针是指向函数的指针变量。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。

其声明方式是:

返回值类型 (*函数名) (参数)  

函数指针的一个重要用途就是作为函数的参数,用于在函数内部进行指针函数的调用,一般用作回调函数,比如在创建一个POSIX线程的就需要传递一个函数指针用于指明该线程做点什么事情。

以下代码展示了一个简单的函数指针的使用方法:

void testFunc(int a,int b,void (*func)(int c,int d) ){
    // do something
    func(a,b);
}

void callback(int a,int b){
}

int main() {
    testFunc(1,2,callback);
    return 0;
}

类成员指针

这里类成员指针表示的是指向类的某个对象的非静态成员的指针,而不是表示类成员变量的指针,首先需要区分好这是两个不同的概念,如果不能好好区分这两个概念的童鞋,需要再好好思考一下。

成员指针的类型囊括了类的类型以及成员的类型。当初始化一个这样的指针时,我们令其指向类的某个成员,但是不指定该成员所属的对象;直到使用成员指针时,才提供成员所属的对象。

和其他指针一样,在声明成员指针时我们也使用*来表示当前声明的名字是一个指针。与普通指针不同的是,成员指针还必须包含成员所属的类。下面是一个使用的示例:

class Person{
public:
    virtual void print() const{
        std::cout << "base print" << endl;
    }

    virtual ~Person(){
    }

public:
    string lastName;
    string firstName;
};

int main() {
    string Person::*p; // 声明了一个类成员指针
    p = &Person::firstName; // 成员变量的指针指向了Peron的name
    Person person;
    person.*p = "hello"; // 使用成员指针
    p = &Person::lastName; // 成员变量的指针指向了Peron的lastName
    person.*p = "world"; // 使用成员指针
    std::cout << person.firstName << " " << person.lastName << std::endl;
    return 0;
}

至于这个成员指针有什么用处,给笔者的感觉就是重新命了一个别名的感觉,甚至有点脱裤子放屁?但是存在即合理,不是没有用处,只是笔者见过那种场景而已吧。。。

除了有指向类成员变量的指针外还有指向类成员函数的指针,这里就不多展开探讨了!!!

补充:用指针的指针指向指针数组

#include<stdio.h> 
int change(char **p)
{
	int i, j;
	for (i = 0; i < 5; i++)
	{
		for (j = 0; *(*(p + i) + j) != '\0'; j++)//利用指针的指针取二维数组的元素
		{
			*(*(p + i) + j) = 'c';
			printf("%c", *(*(p + i) + j));
		}
		printf("\n");
	}
	return 0;
}
 
int main(void)
{
	char *a[5] = { "hello", "zhuyu", "jiajia", "linux","ubuntu" };//如果想使用 需使用指针数组即*a[5] 声明一个有五个字符串指针的数组。
	                                                              //但是由于每个元素都是指针字符串,所以只能够读取,而不能够写入。
	change(a);
	return 0;
}

总结

到此这篇关于C++扫盲篇之指针的文章就介绍到这了,更多相关C++指针扫盲内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++扫盲篇之指针详解

本文链接: https://lsjlt.com/news/143960.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++扫盲篇之指针详解
    目录前言指针为什么要有类型指针和数组二级指针指针与多态绑定函数指针类成员指针补充:用指针的指针指向指针数组总结前言 指针对于学习C/C++的人来说是一道必须迈过去的坎,就像学习九阳神...
    99+
    2024-04-02
  • C语言指针详解之野指针
    目录指针是什么?怎么表示?什么是指针变量?指针类型又是什么?指针类型存在的意义野指针是什么?野指针产生的原因一、 指针未初始化二、 指针越界访问如何避免野指针(野狗)的出现呢?指针运...
    99+
    2024-04-02
  • C++智能指针之shared_ptr详解
    目录共享指针的初始化方式常用成员函数shared_ptr内存模型make_shared的优缺点优点缺点引用计数比较运算符总结共享指针的初始化方式 1.裸指针直接初始化,但不能通过隐式...
    99+
    2024-04-02
  • C语言指针超详细讲解上篇
    目录前言1、指针是什么1.1 指针变量1.2 指针是内存中一个最小单元的编号2、指针和指针类型2.1 指针±类型2.2 指针的解引用2.2.1 int* 类型的解引用2...
    99+
    2024-04-02
  • C语言指针超详细讲解下篇
    目录前言指针运算指针±整数指针-指针指针的关系运算指针和数组二级指针指针数组举例 1举例 2总结前言 本文接着上一篇内容,继续学习指针相关知识点。 指针运算 指针&pl...
    99+
    2024-04-02
  • C语言 野指针与空指针专篇解读
    一:野指针 概念:野指针就是指向的内存地址是未知的(随机的,不正确的,没有明确限制的)。 说明:指针变量也是变量,是变量就可以任意赋值。但是,任意数值赋值给指针变量没有意义,因为这样...
    99+
    2024-04-02
  • C++指针与数组:指针详解
    目录一. What(什么是指针)1. 地址初了解2. 指针概念3. 指针与指针变量二. Why(为什么要有指针)三. How(如何使用指针)1. 基本定义2. 取地址操作符 &...
    99+
    2024-04-02
  • C++学习之指针的使用详解
    C++中指针储存一个地址 声明: datatype* p;  datatype表示指针指向的数据类型。 int num=0; int* pnum=&num; //&...
    99+
    2023-03-02
    C++指针使用 C++指针
  • C++特性之智能指针shared_ptr详解
    目录1.创建指针对象2.分离关联的原始指针3.与普通指针比较4.NULL检测shared_ptr 是C++11提供的一种智能指针类,它足够智能,可以在任何地方都不使用时自动删除相关指...
    99+
    2022-12-08
    C++智能指针shared_ptr C++智能指针 C++ shared_ptr
  • 一篇文章带你了解C++智能指针详解
    目录为什么要有智能指针?智能指针的使用及原理RALLshared_ptr的使用注意事项创建多个 shared_ptr 不能拥有同一个对象shared_ptr 的销毁shared_pt...
    99+
    2024-04-02
  • C语言指针详解
    目录前言:复杂类型说明一、细说指针1.指针的类型2.指针所指向的类型3.指针的值----或者叫指针所指向的内存区或地址4 指针本身所占据的内存区二、指针的算术运算三、运算符&...
    99+
    2024-04-02
  • C++函数指针详解
    函数指针基础: 1. 获取函数的地址 2. 声明一个函数指针 3.使用函数指针来调用函数 获取函数指针: 函...
    99+
    2024-04-02
  • C++指针学习详解
    目录指针的基本概念一、指针变量的定义和使用二、指针所占的空间内存1.空指针 野指针2. const修饰指针利用指针访问数组中的每个元素.总结指针的基本概念 指针的作用:可以通过指针间...
    99+
    2024-04-02
  • 详解C语言学习记录之指针
    目录1指针是什么2指针和指针类型3野指针(1)三种情况(2)如何规避野指针4指针运算5指针和数组6字符指针7数组指针8指针数组9其他总结1指针是什么 指针是汇编语言中的一个对象,利用...
    99+
    2024-04-02
  • C语言的空类型指针,空指针,野指针详解
    目录空类型指针-void*空指针-NULL野指针造成野指针的原因1.指针未初始化2.指针越界访问3.指针指向的空间已经释放避免野指针总结空类型指针-void* void是空类型,vo...
    99+
    2024-04-02
  • C++常量指针,指针常量,指向常量的常指针详解
    目录什么是指针内存地址指针所占内存const 变量指针常量,常量指针和指向常量的指针指针常量常量指针指向常量的常指针空指针、野指针总结什么是指针 指针就是指向变量在内存中的地址 数据...
    99+
    2024-04-02
  • C语言学习之指针的使用详解
    目录一、指针概念1.指针变量2.指针类型3.二级指针二、野指针1.野指针成因2.规避野指针三、指针运算1.指针±整数2.指针-指针3.指针关系运算四、指针数组1.指针和...
    99+
    2022-11-13
    C语言指针使用 C语言指针
  • C++SmartPointer智能指针详解
    目录一、为啥使用智能指针呢二、shared_ptr智能指针三、unique_ptr智能指针四、weak_ptr智能指针五、智能指针怎么解决交叉引用,造成的内存泄漏5.1 交叉引用的栗...
    99+
    2024-04-02
  • 【C++】智能指针(RAII)详解
        我们在上篇文章中(异常处理详解)提到了 RAII 。那么本篇文章会对此进行详解。重点是智能指针的详解。其中会讲解到 RAII 思想、auto_ptr、unique_ptr、shared_ptr、weak_ptr、循环引用问题。希...
    99+
    2023-09-06
    c++ 开发语言
  • 【C语言初阶】指针篇—下
    目录 4. 指针运算4.1 指针+-整数4.2 指针-指针4.3 指针的关系运算 5. 指针和数组6. 二级指针7. 指针数组 C语言初阶—指针上 点击跳转 4. 指针运算 指针...
    99+
    2023-09-01
    c语言 算法 开发语言 指针
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作