首页 > 其他分享 >为什么要有二级指针

为什么要有二级指针

时间:2024-08-16 17:52:57浏览次数:9  
标签:二级 为什么 int 地址 printf array 实参 指针

提示:文章

文章目录

前言

前期疑问:
本文目标:


一、背景

之前一直疑问为什么要有二级指针,一直没有写这个帖子,今天整理了一下,收获颇丰

二、

2.1

// 增加对二级指针的使用

/*
 * 这两天突然想到为什么要有二级指针,二级指针的作用是什么
 * 我自己能想到的原因是因为指针指向内存可以访问内存。但是指针想改变内存中数据,就需要使用二级指针。
 * 然后基于上述的想法,我就写了下面的demo,但是实际情况和我想的不一样。
 * 我就想起来之前牛客题目涉及到的一个二级指针的题目,即没有使用二级指针的时候,没办法访问到指向的数据
 * 2024年8月16日14:28:31今天把牛客题目找了出来,看了下才恍然大悟
 * 今天这边两三天断断续续的内容整理起来
 */

//下面是验证一级指针指向内存中数据,能访问但是不能改变数据的情况。
//

#include <cstdio>
using namespace std;

void testDiliverPointer(int *array)
{
    printf("array:%p\n", array);
    for (int i = 0; i < 6; i++) {
        printf("diliverPointer: %d ", array[i]);
    }
    printf("\n");
    array[0] = 3;
    for (int i = 0; i < 6; i++) {
        printf("change: %d ", array[i]);
    }
    printf("\n");
}

void testPoint()
{
    int array[] = {1, 2, 3, 4, 5, 6};
    for (int i = 0; i < 6; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    int* p = array;
    *p = 2;
    for (int i = 0; i < 6; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    printf("array:%p\n", array);
    testDiliverPointer(array);
}

void testCharDiliverPointer(char* array)
{
    printf("%s\n", array);
    array[1] = 'a';
}

void testCharPointer()
{
    char array[] = "hello";
    char array2[] = "world";
    testCharDiliverPointer(array);
    printf("%s\n", array);
}

void swap_int(int a , int b)
{
    int temp = a;
    a = b;
    b = temp;
}

void swap_str(char*a , char*b)
{
    char*temp = a;
    a = b;
    b = temp;
}

int DiliverSecondaryPointer(void)
{
    int a = 10;
    int b = 5;
    char*str_a = "hello world";
    char*str_b = "world hello";
    swap_int(a , b);
    swap_str(str_a , str_b);
    printf("%d %d %s %s\n",a,b,str_a,str_b);

    return 0;
}

void DiliverParam(int param)
{
    printf("diliverParam addr:%p\n", &param);
}

void DiliverParamPointer(int* paramPointer)
{
    printf("diliverParam pointer addr:%p\n", paramPointer);
}

void Paramtest()
{
    int param = 0;
    printf("addr:%p\n", &param);
    DiliverParam(param);
    DiliverParamPointer(&param);
}

int main()
{
    testPoint();
    //打印信息
    /*
     * 1 2 3 4 5 6
     * 2 2 3 4 5 6
     * array:000000ca8cfffb90
     * array:000000ca8cfffb90
     * diliverPointer: 2 diliverPointer: 2 diliverPointer: 3 diliverPointer: 4 diliverPointer: 5 diliverPointer: 6
     * change: 3 change: 2 change: 3 change: 4 change: 5 change: 6
     */
     // 从上述打印信息来看,
     // 第一次使用指针指向数组,再对数组成员指针解引用赋值,改变数组的值,可以通过指针更改变量的值
     // 第二次将数组指针传参,数组名弱化为指针。对指针解引用,更改指向的内存数据,可以实现。指针作为参数时,是进行拷贝的。但是因为指针是地址常量。拷贝后还是这个值。依然可以指向指向的内存
     // (这里我突然想到,参数为array,那这个array是个拷贝了实参数组地址的副本。这边的形参array的值改变了。但是拷贝的值是一样的。依然可以指向对应的内存)
     // (但是我打印的实参和形参的地址值是一样的啊,奇怪了),下面要验证一下这个形参地址和实参 地址一不一样?

     // 没有看到预期的结果。即没有传二级指针指针就不能更改参数的值。甚至我怀疑是不是只有在字符串中才存在这种情况?我又写了字符串来验证。
    testCharPointer();
    // 打印结果如下
    /*
     * hello
     * hallo
     */
    // 根据打印结果,字符串传参一级指针也可以更改字符串数据。我没有重现之前题目。就去找了题目。看了题目恍然大悟,知道之前的题目是怎么样的。下面是之前的题目

    DiliverSecondaryPointer();
    // 打印结果 10 5 hello world world hello
    // 然后我又仔细看了swap_str函数做的事情。又联想到之前问小鲁班为什么要有二级指针,回答是“当我们需要在函数中修改指针指向的内存地址时,我们需要传递指向指针的指针,即二级指针”
    // 上述的函数就是更改指针指向的地址
    // 所以应该就是这样,使用一级指针可以访问指针指向的内存。二级指针才能更改指针指向的内存。有点通透了啊

    //题外话,形参实参地址是否变化
    Paramtest();
    // 打印信息
    /*
     * addr:0000009e581ffafc
     * diliverParam addr:0000009e581ffad0
     * diliverParam pointer addr:0000009e581ffafc
     */
    // 根据打印信息,函数DiliverParam形参和实参的地址不一样。
    // DiliverParamPointer形参和实参的地址一样。这边我就懵逼了
    // 查了资料看到了一个很熟悉的名词,传参和传地址。又恍然大悟。

    // 事情还没完。当我在看传地址和‌传值的区别时在想。传地址是怎么实现只传了实参的地址。而没有进行形参对实参的地址值得拷贝。
    // 然后我又看了下代码。为什么Paramtest前后地址值是一样的。我发现了问题。就是我在Paramtest函数中,打印的是param的值。其实应该打印&param的地址。
    // 做完上面的判断我发现我的理解还是出了问题。那就是其实不是打印&param的值。实际情况是这样
    /*
     * int *paramPointer = &param。即定义一个参数变量p指向变量param。所以打印p的值就是param的地址。但是实际上我使用的不是%p吗。
     * 想到这边我尝试写这样的代码printf("diliverParam pointer addr:%p\n", *paramPointer);这样也不对了,因为我不能打印变量的地址,要写成printf("diliverParam pointer addr:%p\n", &(*paramPointer));
     * 这不就是printf("diliverParam pointer addr:%p\n", paramPointer);吗,所以还是对的。所以原因是这样的。printf("diliverParam pointer addr:%p\n", paramPointer);打印就是实参param的地址。
     * 回到最初的问题,传地址是怎么实现值传递了实参的地址?是因为使用了一个指针指向实参的内存。然后使用这个指针形参可以访问内存。避免了拷贝。实际上当数据量比较大时,才有必要使用指针。
     * 所以在C语言中要避免大量拷贝数据,就要使用指针。当然在C++中有了更好的选择,即引用。引用可以避免空指针的情况出现。
     */

    return 0;
}


//‌传地址和‌传值的区别主要体现在以下几个方面:
//
//定义:
//传值:将函数调用中‌实参的值复制一份给形参,形参和实参互不影响。在函数中修改形参的值不会影响实参的值。‌12
//传址:将函数调用中实参的地址(指针)作为形参传递给函数,函数中修改形参的值会直接影响到实参的值。
//内存使用:
//传值:传递参数时会复制一份实参的值,形参会在函数内部重新分配内存空间,修改形参的值不会影响到实参的值,也不会影响到其他变量的值。‌2
//传址:传递参数时只传递了实参的地址,形参并不会重新分配内存空间,修改形参的值会直接影响到实参的值,也会影响到实参指向的其他变量的值。
//效率:
//传值:传递参数时需要复制一份实参的值,如果实参的值较大,会造成比较大的开销,对于一些复杂的数据结构,如数组、结构体等,可能会导致程序运行效率较低。
//传址:传递参数时只需要传递地址,对于较大的数据结构,可以避免复制大量的数据,从而提高程序运行效率。
//通过例子进一步说明:
//
//传值:就相当于克隆了一个同样的变量,操作的是克隆出来的那个,原来的变量没有变化。‌34
//传址:直接对原来的变量进行操作,没有克隆新的变量


//上述的整理还是很通透的。

2.2

三、

3.1


总结

未完待续

标签:二级,为什么,int,地址,printf,array,实参,指针
From: https://blog.csdn.net/2301_77560238/article/details/141266108

相关文章

  • C++智能指针讨论
    一段有问题的代码。#include<iostream>intmain(){for(inti=0;i<10000000;i++){double*p=newdouble(1);}return0;}这里就有了内存泄漏。修改为下边的代码,是可以的,但是会比较占用CPU资源。#include<iostream>intmain()......
  • QT 开发循环delete指针的安全操作
    背景在做TcpSocket例子的时候,发下移除QList<QTcpSocket*>后,第二次重新连接发现出现异常。经过排查发现,原来是deleteLater与delete有区别原因分析deleteLater和delete都是在Qt中用于对象内存管理的关键方法,但它们的作用和使用时机有所不同。deleteLater用于安全异步删......
  • C++速览之智能指针
    1、存在的问题c++把内存的控制权对程序员开放,让程序显式的控制内存,这样能够快速的定位到占用的内存,完成释放的工作。但是此举经常会引发一些问题,比如忘记释放内存。由于内存没有得到及时的回收、重复利用,所以在一些c++程序中,常会遇到程序突然退出、占用内存越来越多,最后不......
  • 指针学习(3)
     目录1.字符指针变量​编辑2.数组指针变量2.1定义2.2存放3.二维数组传参的本质4.函数指针变量4.1创建4.2使用 ​编辑5.typedef关键字6.函数指针数组6.1转移表1.字符指针变量顾名思义,字符指针也就是char*,在使用中,一般简单的使用可以这样#include<stdio.h>i......
  • 指针:存放内存地址的变量
    //指针:类型跟存放变量的类型一致定义格式:数据类型*变量名;static关键字可以防止内存被释放禁止使用野指针和悬空指针特殊指针:void*p;空类型指针,可以存放任何类型指针,但是不能进行操作//指针高级应用:以字节为单位,交换两个变量的值#include<stdio.h>voidSwap(void*p1,void*......
  • C:指针学习-指针变量—学习笔记
    今日伊雷娜:目录前言:1、字符指针变量1.1使用字符指针存放字符1.2使用字符指针变量存放字符串 2、数组指针变量2.1什么是数组指针变量?2.2数组指针变量初始化2.3关于数组指针类型的解析3、函数指针变量3.1函数地址3.2 函数指针变量的创建3.3关于指针的连续......
  • C语言-使用数组法,指针法实现将一个5X5的矩阵中最大的元素放在中心,四个角分别放四个最
    1.题目要求:将一个5X5的矩阵中最大的元素放在中心·,四个角分别放四个最小的元素(顺序为从左到右,从上到下,从小到大存放),写一函数实现之。2.数组法实现#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>//一、数组法实现intmain(){ intarr[5][5]={ {1,2,3,4,5},......
  • 【C++】动态内存(二)智能指针
    由于new和delete会造成一定程度的内存泄漏问题,以及内存所有权不清晰,因此引入自动销毁相应内存空间的智能指针。智能指针是抽象数据类型,本身具有析构函数,因此调用之后会自动调用析构函数,在析构函数中会自动调用delete来释放相应内存空间,因此不用手动显式的调用delete。【......
  • Spring使用实现类注入为什么会导致高耦合度(举例)
    场景描述假设我们要开发一个日志记录器组件,记录日志的方式可能有多种实现:控制台输出、文件输出、甚至是发送到远程服务器。为了实现这个功能,我们可以定义一个Logger接口来抽象日志记录功能,然后根据不同的需求创建不同的实现类。1.接口注入的实现方式首先,我们定义一个Logger......
  • 百万赞同:网络安全为什么缺人_ 缺什么样的人?
    1.网络安全为什么缺人?缺人的原因是有了新的需求以前的时候,所有企业是以产品为核心的,管你有啥漏洞,管你用户信息泄露不泄露,我只要做出来的产品火爆就行。这一切随着《网络安全法》、《数据安全法》、《网络安全审查办法》等一系列有关网络安全的法律法规出台戛然而止,上到......