首页 > 系统相关 >C++学习笔记----6、内存管理(二)---- 数组指针的双向性

C++学习笔记----6、内存管理(二)---- 数组指针的双向性

时间:2024-09-05 19:54:50浏览次数:11  
标签:int C++ doubleInts ---- 数组 theArray 双向性 指针 size

        你可能已经看到指针与数组之间的一些重叠。自由内存空间分配的数组由其第一个元素的指针进行访问。栈上的数组通过使用数组语法([])或者正常变量声明来访问。你还会看到的是,其重叠不仅如此,指针与数组有更复杂的关系。

1、数组退化至指针

        自由内存空间数组不是指向数组所用的指针的唯一位置。也可以使用指针的语法来访问栈上数组。数组的地址实际上就是第一个元素(索引0)的地址。编译器知道当你通过变量名指向数组时,你实际上就是指向了第一个元素的地址。用这种方式,指针像在自由内存空间上的数组一样工作。下面的代码生成了一个以0初始化的栈上数组,使用了一个指针来访问它:

int myIntArray[10] {};
int* myIntPtr { myIntArray };// Access the array through the pointer.
myIntPtr[4] = 5;

       通过指针访问栈上数组的能力在传递数组给函数时非常有用。下面的函数接受整型数组作为指针。注意调用者需要显示地传递数组的大小,因为指针无法知道数组大小。这也是为什么你需要使用现代比如标准库提供的函数的另一个原因。

void doubleInts(int* theArray, size_t size)
{
    for (size_t i { 0 }; i < size; ++i) 
    { 
        theArray[i] *= 2; 
    }
}

        函数调用者可以传递栈上数组或者自由内存空间数组。对于自由内存空间数组,指针早就存在,通过其值传入函数。对于栈上数组,调用者可以传递数组变量,编译器自动把数组变量当作指向数组的指针,或者你可以显示地将第一个元素的地址传进去。这三种形式的代码如下:

size_t arrSize { 4 };
int* freeStoreArray { new int[arrSize]{ 1, 5, 3, 4 } };
doubleInts(freeStoreArray, arrSize);
delete [] freeStoreArray;
freeStoreArray = nullptr;

int stackArray[] { 5, 7, 9, 11 };
arrSize = std::size(stackArray); // Since C++17, requires <array>
//arrSize = sizeof(stackArray) / sizeof(stackArray[0]); // Pre-C++
doubleInts(stackArray, arrSize);

doubleInts(&stackArray[0], arrSize);

        数组参数传递语法与指针非常类似,因为当它传递给函数时,编译器把数组当作指针。把数组作为参数的函数,并且在数组内修改其值,实际上修改的就是原来的数组,而不是其副本。与指针一样,传递数组有效地模仿了引用传递功能,因为你实际上传递给函数的是原有数组的地址,而不是副本。下面对doubleInts()的实现即使参数是数组不是指针,其改变的依然是原有数组的值。

void doubleInts(int theArray[], size_t size)
{
    for (size_t i { 0 }; i < size; ++i) { theArray[i] *= 2; }
}

函数原型中theArray之后在方括弧之间的任何数字都会被忽略。下面的三个版本是一样的:

void doubleInts(int* theArray, size_t size);
void doubleInts(int theArray[], size_t size);
void doubleInts(int theArray[2], size_t size);

        你可能会想怎么会这样呢?当数组语法在函数定义时这样用,编译器为什么不对数组进行拷贝呢?主要还是效能的考虑----拷贝数组的元素是需要时间的,也会占用大量的内存。只要传递一个指针,编译器不需要包含拷贝数组的代码。

        传递已知长度栈上数组还有一种方法就是“通过引用”给到函数,虽然语法不明显。这个对于在自由内存空间的数组不管用。例如,下面的doubleIntsStack()只接受栈上大小为4的数组。

void doubleIntsStack(int (&theArray)[4]);

        我们以后会讨论的函数模板,用于让编译器自动地推算出栈上数组的大小:

template <size_t N>
void doubleIntsStack(int (&theArray)[N])
{
    for (size_t i { 0 }; i < N; ++i) { theArray[i] *= 2; }
}

        不要直接给函数传递C风格的数组,推荐函数用类型std::span,这个以后会讨论,“标准库函数”span把数组指针与其大小进行了组合。

2、不是所有的指针都是数组!

        因为编译器允许你在期待指针的地方传递数组,就像前面的doubeInts()函数,你可能会错误地认为指针与数组是一样的。实际上,它们会有微小的但是很重要的区别。指针与数组共享许多属性,有时候可以互换使用(如前所示),但它们真的不是完全一样的。

        指针本身没有任何意义。它可能指向随机的内存地址,一个单独的对象,或者是一个数组。你问题可以用数组语法来使用指针,但这样做并不是总是合适的,因为指针不总是数组。例如,考虑一下下面的这一行代码:

int* ptr { new int };

        指针ptr是一个有效的指针,但它不是一个数组。你可以使用数组语法ptr[0]来指向其值,但这样做从风格上是值得怀疑的,并且没有什么好处啊。实际上,对于非数组指针使用数组语法是向错误开了方便之门。Ptr[1]可以是任何东东!

        数组可以退化为指针,但不是所有的指针都是数组。

标签:int,C++,doubleInts,----,数组,theArray,双向性,指针,size
From: https://blog.csdn.net/weixin_71738303/article/details/141939295

相关文章

  • 基于SpringBoot+Vue+uniapp的家纺用品销售管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • [python]线程与进程的区别及代码演示
    进程与线程多线程socket,tcp服务器实现,在最底下区别:关系区别:​线程依赖于进程,一个进程至少会有一个线程特点区别:进程间的数据是相互隔离的,线程间数据是可以共享的线程同时操作共享数据,可能引发安全问题,需要用到互斥锁进程的资源开销比线程大多进程程序比单......
  • 如何用 ThreadLocal 构建强大的 ContextManager
    在实际开发中,我们经常需要维护一些上下文信息,这样可以避免在方法调用过程中传递过多的参数。例如,当Web服务器收到一个请求时,需要解析当前登录状态的用户,并在后续的业务处理中使用这个用户名。如果只需要维护一个上下文数据,如用户名,可以通过方法传参的方式,将用户名作为参数传......
  • 内核链表基本知识
    一、基本知识内核链表:可以给里面的每一个数据都可以存储不同的数据的类型,结构体成员里面(将结点放在数据中)1、实质内核链表:有头的、双向循环链表2、注意结构体第一个成员即为结构体的首地址该链表里面的数据主要由两部分构成前驱结点,后继结点,该节点作为数据放在数据中3、......
  • 基于SpringBoot+Vue+uniapp的教务管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 零知识证明-ZK-SNARKs基础(七)
    前言这章主要讲述ZK-SNARKs所用到的算术电路、R1CS、QAP等1:算术电路算术运算电路1>半加器:实现半加运算的逻辑电路2>全加器:能进行被加数,加数和来自低位的进位信号相加,并根据求和结果给出该位的进位信号说明:2进制加,低位进位相当于结果S为=A+B+C(地位进位)高位进......
  • 轻松管理上下文:ThreadLocal 助力 ContextManager
    在实际开发中,我们经常需要维护一些上下文信息,这样可以避免在方法调用过程中传递过多的参数。例如,当Web服务器收到一个请求时,需要解析当前登录状态的用户,并在后续的业务处理中使用这个用户名。如果只需要维护一个上下文数据,如用户名,可以通过方法传参的方式,将用户名作为参数传......
  • 什么是集体商标和证明商标?
    在商标的世界里,集体商标和证明商标作为两种特殊的商标类型,各自承载着不同的功能与价值。它们不仅区分了商品和服务的来源,还为特定的群体和产品提供了有力的品牌标识与质量保证。集体商标集体商标,顾名思义,是以团体、协会或其他组织名义注册,专供该组织成员在商事活动中使用的......
  • 基于SpringBoot+Vue+uniapp的电竞交互管理系统(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 寝室|基于SSM+vue的金桂园寝室管理系统(源码+数据库+文档)
    金桂园寝室管理系统基于SprinBoot+vue的金桂园寝室管理系统一、前言二、系统设计三、系统功能设计 系统登录实现管理员模块实现宿管模块实现学生模块实现四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:博主介绍:✌️大厂码......