【C++基础】10. 指针

news2024/11/30 11:30:04

文章目录

  • 【 1. 指针的定义 】
  • 【 2. 指针的调用 】
  • 【 3. NULL 空指针 】
  • 【 4. 指针的算术运算 】
    • 4.1 指针的递加
    • 4.2 指针的递减
    • 4.3 指针的比较
  • 【 5. 指针与数组 】
    • 5.1 通过指针操作数组
    • 5.2 指针数组、数组指针
  • 【 6. 指向指针的指针(多级间接寻址)】
  • 【 7. 传递指针给函数 】
  • 【 8. 函数返回指针 】

  • 指针的作用:通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。
  • 内存和指针的关系:每一个变量都有一个内存位置(理解为:每一个变量在内存中都占有一个位置 / 占用一定内存空间),每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。 内存位置相当于房间,地址相当于门牌号

【 1. 指针的定义 】

  • 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
  • 不同数据类型的指针都是一个代表内存地址的长的十六进制数 。唯一的不同是,指针所指向的变量或常量的数据类型不同。
  • 指针变量声明的一般形式为:
    • type 是指针的基类型,它必须是一个有效的 C++ 数据类型;
    • 用来声明指针的星号 * 与乘法中使用的星号是相同的,但在这个语句中,星号用来指定一个变量是指针;
    • var-name 是指针变量的名称。
type *var-name;
  • 实例:有效的指针声明:
int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */

【 2. 指针的调用 】

  • 使用指针时会频繁进行以下几个操作:① 定义一个指针变量② 把变量地址赋值给指针③ 访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。
#include <iostream>
using namespace std;

int main ()
{
   int  var = 20;   // 实际变量的声明
   int  *ip;        // 指针变量的声明

   ip = &var;       // 在指针变量中存储 var 的地址

   cout << "Value of var variable: ";
   cout << var << endl;

   // 输出在指针变量中存储的地址
   cout << "Address stored in ip variable: ";
   cout << ip << endl;

   // 访问指针中地址的值
   cout << "Value of *ip variable: ";
   cout << *ip << endl;

   return 0;
}

在这里插入图片描述

【 3. NULL 空指针 】

  • 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值(即指向地址为0的内存)是一个良好的编程习惯。赋为 NULL 值的指针被称为 空指针
  • NULL 指针是一个定义在标准库中的值为零的常量。
  • 地址为0的内存 在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而 指向内存地址 0的NULL空指针表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
  • 实例:
#include <iostream>

using namespace std;

int main ()
{
   int  *ptr = NULL; // ptr为NULL指针,指向地址为0的内存
   cout << "ptr 的值是 " << ptr ;
   if 0  // 测试查看ptr指向的值,报错说明地址为0的内存不可访问
      cout << "*ptr 的值是 " << *ptr ;
   end
   return 0;
}

在这里插入图片描述

  • 检查一个指针是否是空指针:
if(ptr)     /* 如果 ptr 非空,则完成 */
if(!ptr)    /* 如果 ptr 为空,则完成 */
  • NULL指针的意义:很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。因此, 如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以 防止误用一个未初始化的指针

【 4. 指针的算术运算 】

  • 指针的值表示地址,但归根到底还是一个变量。因此,我们可以对指针执行算术运算。
  • 可以对指针进行四种算术运算:++、- -、+、-。
  • 指针运算的基本单元 = 指针指向变量的数据类型所占字节大小
  • 假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,我们对该指针执行下列的算术运算:ptr++;
    在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。
  • 如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

4.1 指针的递加

  • 实例:下面的程序递增变量指针,以便顺序访问数组中的每一个元素
#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中的数组地址
   ptr = var;
   for (int i = 0; i < MAX; i++)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 移动到下一个位置
      ptr++;
   }
   return 0;
}

在这里插入图片描述

4.2 指针的递减

    • 实例:下面的程序递减变量指针,以便顺序访问数组中的每一个元素。
#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中最后一个元素的地址
   ptr = &var[MAX-1];
   for (int i = MAX; i > 0; i--)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 移动到下一个位置
      ptr--;
   }
   return 0;
}

在这里插入图片描述

4.3 指针的比较

  • 指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
  • 下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:
#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中第一个元素的地址
   ptr = var;
   int i = 0;
   while ( ptr <= &var[MAX - 1] )
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 指向上一个位置
      ptr++;
      i++;
   }
   return 0;
}

在这里插入图片描述

【 5. 指针与数组 】

5.1 通过指针操作数组

  • 我们经常在程序中使用指针存储数组首元素的地址,即指针指向数组首元素。这是因为 指针作为一个变量可以递增,而 数组名本身就是一个常指针,不能赋值
#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int *ptr;
   ptr= var;
	
   for (int i = 0; i < MAX; i++)
   { 
	 if (1) // 正确的 
	 {
	 	cout<< *ptr <<endl;
	 	ptr++;
	 }
	 else // 错误的
	 {
	 	cout<< *var  <<endl; 
	 	//var++; // 数组名是常指针,不能被赋值
	 }
   }
   return 0;
}

在这里插入图片描述

  • 通过指针修改数组元素值
*(var + 2) = 500;

5.2 指针数组、数组指针

  • 详见文章:指针数组、数组指针

【 6. 指向指针的指针(多级间接寻址)】

  • 指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时, 第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的地址
  • 一个指向指针的指针变量必须如下声明,即 在变量名前放置两个星号。如下声明了一个指向 int 类型指针的指针:
int **var;
  • 实例:当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符:
#include <iostream>

using namespace std;

int main ()
{
    int  var;
    int  *ptr;
    int  **pptr;

    var = 3000;

    // 获取 var 的地址
    ptr = &var;

    // 使用运算符 & 获取 ptr 的地址
    pptr = &ptr;

    // 使用 pptr 获取值
    cout << "var 值为 :" << var << endl;
    cout << "*ptr 值为:" << *ptr << endl;
    cout << "**pptr 值为:" << **pptr << endl;

    return 0;
}

在这里插入图片描述

【 7. 传递指针给函数 】

  • C++ 允许我们传递指针给函数,只需简单地声明函数参数为指针类型即可。
  • 指针作为函数形参时,若在函数内部改变了指针所指向变量的值,则调用完该函数后该变量的值也会变化,因为这是直接对指针所指向的内存地址中的数据进行操作的。
  • 实例
#include <iostream>
#include <ctime>

using namespace std;
void getSeconds(unsigned long *par)
{
   // 获取当前的秒数
   *par = time( NULL );
   return;
}

int main ()
{
   unsigned long sec;


   getSeconds( &sec );

   // 输出实际值
   cout << "Number of seconds :" << sec << endl;

   return 0;
}

在这里插入图片描述

  • 实例:数组名作为函数形参
#include <iostream>
using namespace std;

// 函数声明
double getAverage(int *arr, int size);

int main ()
{
   // 带有 5 个元素的整型数组
   int balance[5] = {1000, 2, 3, 17, 50};
   double avg;

   // 传递一个指向数组的指针作为参数
   avg = getAverage( balance, 5 ) ;

   // 输出返回值
   cout << "Average value is: " << avg << endl; 

   return 0;
}

double getAverage(int *arr, int size)
{
  int    i, sum = 0;       
  double avg;          

  for (i = 0; i < size; ++i)
  {
    sum += arr[i];
   }

  avg = double(sum) / size;

  return avg;
}

在这里插入图片描述

【 8. 函数返回指针 】

  • 从函数返回指针,一般形式:
int * myFunction()
{
	...
}
  • C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量
  • 实例:生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

// 要生成和返回随机数的函数
int * getRandom( )
{
  static int  r[10];

  // 设置种子
  srand( (unsigned)time( NULL ) );
  for (int i = 0; i < 10; ++i)
  {
    r[i] = rand();
    cout << r[i] << endl;
  }

  return r;
}

// 要调用上面定义函数的主函数
int main ()
{
   // 一个指向整数的指针
   int *p;

   p = getRandom();
   for ( int i = 0; i < 10; i++ )
   {
       cout << "*(p + " << i << ") : ";
       cout << *(p + i) << endl;
   }

   return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue面试题二十七】、你了解axios的原理吗?有看过它的源码吗?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说下你的vue项目的目录结…

第三章 内存管理 四、连续分配管理方式

目录 一、内存空间的分配与回收 1、连续分配管理方式 &#xff08;1&#xff09;、单一连续分配 优点&#xff1a; 缺点&#xff1a; &#xff08;2&#xff09;、固定分区分配 分区大小相等&#xff1a; 分区大小不等&#xff1a; &#xff08;3&#xff09;、动态分区…

leetcode17.04面试题:消失的数字

数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 思路1&#xff1a;暴力枚举 定义一个[0~n]的数组与所给数组nums进行循环遍历&#xff0c;如果不相等则返回那个数。 int missingNumber(int…

Git 安装和配置教程:Windows / Mac / Linux 三平台详细图文教程,带你一次性搞定 Git 环境

Git是一款免费、开源的分布式版本控制系统&#xff0c;广泛应用于软件开发领域。随着开源和云计算的发展&#xff0c;Git已经成为了开发者必备的工具之一。本文将为大家介绍Git在Windows、Mac和Linux三个平台上的安装和配置方法&#xff0c;带你一次性搞定Git环境 Windows平台 …

windows计划任务的配置文件

界面操作 创建计划 依次设置 命令行操作 SCHTASKS 命令简介 SCHTASKS 命令是由微软公司开发并内置于 Windows 系统中的一个命令行工具。该命令可用于设置、修改、查询和删除计划任务&#xff0c;或启动计划任务中所定义的程序或脚本。 SCHTASKS 命令的基本语法 SCHTASKS 命…

【算法|动态规划No.20】leetcode416. 分割等和子集

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

38_Nginx 启动流程

文章目录 src/core/nginx.cint ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;

CSS基础详细解析(附带综合小练习)

目标&#xff1a;掌握 CSS 属性基本写法&#xff0c;能够使用文字相关属性美化文章页。 01-CSS初体验 层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种 样式表 语言&#xff0c;用来描述 HTML 文档的呈现&#xff08;美化内容&#…

JVM之class文件结构剖析

文章目录 0.前言1. 引言1.1 Java编译原理基础1.2 Class文件在Java编译过程中的角色 2. Class文件的整体结构2.1 Class 文件组成 3. Class文件的详细解析3.1 魔数与版本号的作用和意义3.2 常量池的结构和作用3.3 访问标志的含义和可能的值3.4 类索引、父类索引和接口索引集合的作…

如何在小程序中设置页面显示的文字

不同商家&#xff0c;对于小程序有不同的要求。所以&#xff0c;小程序应该支持商家在后台灵活配置小程序各个页面的文字显示。下面具体介绍如何显示各个页面的文字。 朋友圈分享图文字&#xff1a;会显示在朋友圈海报顶部 升级会员提示&#xff1a;对于普通会员&#xff0c;在…

一些基础知识

一些基础知识笔记Git clone gitxxxxx pip install -r requirements.txt -i https://pypi.mirrors.ustc.edu.cn/simple wget google.com 可以快速看你的服务器到底有没有链接代理 benchmark和baseline L1 loss & MSE loss L1是差的绝对值和&#xff0c;MSE是差的平方和 …

KMP 算法 + 详细笔记

给两个字符串&#xff0c;T"AAAAAAAAB"&#xff0c;P"AAAAB"; 可以暴力匹配&#xff0c;但是太费时和效率不太好。于是KMP问世&#xff0c;我们一起来探究一下吧&#xff01;&#xff01;&#xff01; &#xff08;一&#xff09;最长公共前后缀 D[i] p[…

【Vue面试题三十】、vue项目本地开发完成后部署到服务器后报404是什么原因呢?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;vue项目本地开发完成后部…

电脑技巧:PrivaZer电脑清理工具介绍

目录 一、软件介绍 二、功能介绍 三、软件特点 清理和保护 防止恢复 Cookie的智能清理 四、软件下载 今天给大家推荐一款非常实用的电脑垃圾清理工具&#xff0c;感兴趣的朋友可以下载看看&#xff01; 一、软件介绍 PrivaZer是一款免费好用的老牌清理软件&#xff0c;除…

详解Pinia和Vuex

一、vuex介绍 1.什么是vuex&#xff1f;为什么要使用vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 在vue最重要的就是数据驱动和组件化&#x…

苍穹外卖(八) 使用WebSocket协议完成来单提醒及客户催单功能

WebSocket介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信(双向传输)——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP…

排序-算法

文章目录 一、排序的概念及引用1.1 排序概念1.2 排序运用1.3 常见排序算法 二、常见排序算法的实现2.1 插入排序2.1.1 基本思想2.1.2 直接插入排序2.1.3 希尔排序 2.2 选择排序2.2.1 基本思想2.2.2 直接选择排序2.2.3 堆排序 2.3 交换排序2.3.1 冒泡排序2.3.2 快速排序2.3.3 快…

Godot C# 扩展方法持续更新

前言 为了简化Godot 的编写&#xff0c;我会将我的扩展方法写在这里面。 更新日期(2023年10月15日) Nuget 包安装 扩展方法 public static class GD_Extension{/// <summary>/// 假数据生成&#xff0c;详情请看Bogus官方文档/// </summary>public static Faker…

介绍6种解决电脑找不到vcomp140.dll,无法继续执行代码的方法。

在编程和软件开发领域&#xff0c;我们经常会遇到各种错误和问题。其中&#xff0c;找不到vcomp140.dll文件导致无法继续执行代码是一个非常常见的问题。这个问题可能会影响到软件的正常运行&#xff0c;甚至导致整个项目延期。因此&#xff0c;我们需要找到解决方案来解决这个…

pwnable-1-fd

pwn的学习周期确实比较长&#xff0c;需要的前置内容也很多&#xff0c;了解到第一题还算比较简单的&#xff0c;那就先来体验一波~顺带附一波网站链接:&#x1f449;网站链接 题目 WP 最后一行给出了ssh链接方式&#xff0c;那就先连接一波 第一次连接会有第四行的询问&…