c++指针【1】

news/2024/11/28 22:38:14/

在C++中,指针是一种特殊的变量,它存储了一个内存地址。C++指针在处理内存、数组、函数参数传递、文件I/O、动态内存分配等方面有着重要的应用。

一个指针变量通常被声明为特定类型的指针。例如,一个整数类型的指针可以指向一个整数。在声明指针变量时,应该在变量名前面加上星号(*)。

例如,下面的代码声明了一个整数类型的指针:

int* p;

 要初始化一个指针,可以使用另一个变量(或其他类型的内存地址)来赋值给它。例如:

int x = 10;  
int* p = &x;  // p现在指向x的内存地址

 在C++中,可以通过解引用操作(使用*运算符)来访问指针指向的值。例如:

std::cout << *p << endl;  // 输出10,因为p指向x的内存地址*,p就是取出这个地址的值

 获取对象地址,要想获取改地址,需要使用取地址符(操作符&);

int val = 56;
int *p = &val; //p存放变量val的地址,或者说p是指向变量val的指针
double val;
double *pd = &val; //正确:初始值是double型对象的地址
double *pd2 = pd;  //正确:初始值是指向double对象的指针int *pi  = pd;     //错误:指针pi的类型和pd的类型不匹配pi  = &val;   //错误:试图把double型对象的地址赋值给int型指针

 指针值

指针的值(即地址)应属于下列4种状态之一:

1.指向一个对象。

2.指向紧邻对象所占空间的下一个位置。

3.空指针,意味着指针没有指向任何对象。

4.无效指针,也就是上述情况之外的其他值。

利用指针访问对象

如果指针指向了一个对象,则允许使用解引用符(操作符*)来访问该对象;

int val = 42;
int *p  = &val;   //p存放着变量val的地址,或者说p是指向变量val的指针
cout   <<  *p;   //由符号*得到指针p所指向的对象,输出42;*p = 0;    //由符号*得到指针p所指向的对象,即可有p为变量val赋值
cout << *p;    //输出0 

 接引用操作,仅适用于那些确实指向了某个对象的有效指针

空指针

空指针(null pointer)不指向任何对象,在试图使用一个指针之前代码可以先检查他是否为空。以下列出几个生成空指针的方法:

int *p1 = nullptr;  //等价于int *p1 = 0;

int *p2 = 0;        //直接将p2初始化为字面常量0

//需要首先#include cstdlib

int *p3 = null;  //等价于int *p3 = 0;

得到空指针最直接的办法就是字面值nullptr来初始化指针。

赋值和指针

指针和引用都能提供对其他对象的间接访问

记住:赋值永远改变的是等号左侧的对象

void* 指针

void*是一种特殊的指针类型,可用于存放任意对象的地址。一个void*指针存放着一个地址。

double obj = 3.14,*pd = &obj; //正确:void*能存放任意类型对象的地址

void *pv = &obj; //obj可以是任意类型的对象

pv = pd;        //pv可以存放任意类型的指针

        利用 void*指针能做的事儿比较有限:拿它和别的指针比较、作为函数的输入或输出,或者赋给另外一个void*指针。不能直接操作 void*指针所指的对象,因为我们并不知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。

总的概括:以void*的视角来看内存空间,没办法访问内存空间中所存的对象。

练习巩固:

 1.c++编写指针代码,分别更改指针的值以及指针所指向对象的值

#include<iostream>int main()
{float  x = 3.6; //定义一个整型变量x并初始化为3.6float *ptr = &x ; //定义一个指向x的指针ptrstd::cout << "原始指针的值:ptr = " << ptr << std::endl;std::cout << "原始指针所指向的对象的值:*ptr = " << *ptr << std::endl;//更改指针的值float  y = 2.3;ptr = &y;std::cout << "更改后指针的值:ptr = " << ptr << std::endl;std::cout << "更改后指针所指向对象的值: *ptr = " << *ptr << std::endl;//更改指针所指向对象的值*ptr = 3030;std::cout << "再次更改指针所指向的对象的值: *ptr= " << *ptr << std::endl;return 0;
}

2.说明指针和引用的主要区别:

C++中的指针和引用是两个重要的概念,它们都可以用来间接访问其他对象,但它们之间存在一些关键的区别:

  1. 基本性质:指针是一个变量,存储的是另一个变量的地址;而引用是变量的别名,它和变量指向同一块内存空间。
  2. 初始化:引用在定义时必须被初始化,并且初始化后不能改变;而指针在定义时可以不被初始化,初始化后也可以改变其所指向的对象。
  3. 空值:指针可以为NULL,但引用不能。
  4. 取值方式:引用直接访问其所指向的对象,像操作普通变量一样;而指针需要通过解引用操作符*来访问其所指向的对象。
  5. 安全性:引用比指针更安全,因为引用总是指向一个存在的变量,而指针则可能指向一个不存在的内存地址。
  6. 语法形式:引用使用起来就像使用普通变量一样简单,而指针需要使用解引用操作符*来访问其所指向的对象。

总的来说,指针和引用都可以用来间接访问其他对象,但它们的使用方式和设计目标不同。指针更加灵活,可以用来操作内存中的任意地址;而引用更加安全和方便,可以像使用普通变量一样使用。

#include<iostream>int main()
{int x = 10;   // 定义一个整型变量x并初始化为10  int* ptr = &x; // 定义一个指向x的指针ptr  int& ref = x;  // 定义一个引用ref,它是变量x的别名  // 输出指针、引用和变量的值  std::cout << "x = " << x << std::endl;std::cout << "ptr = " << ptr << ", *ptr = " << *ptr << std::endl;std::cout << "ref = " << ref << std::endl;// 修改变量的值  x = 20;ptr[0] = 30;ref = 40;// 输出指针、引用和变量的值  std::cout << "x = " << x << std::endl;std::cout << "ptr = " << ptr << ", *ptr = " << *ptr << std::endl;std::cout << "ref = " << ref << std::endl;return 0;
}

3.请简述下面这段代码的作用:

int i= 42;
int *p1 = &i;
*p1 = *p1 * *p1;

这段代码的主要作用是使用指针来修改它所指向的变量的值。

  1. int i= 42;  //定义了一个整型变量i并初始化为42。
  2. int *p1 = &i;//定义了一个整型指针p1,并将它初始化为变量i的地址。
  3. *p1 = *p1 * * p1;//这里有两个指针解引用操作(*p1),第一个解引用操作获取p1所指向的值(即变量i的值),第二个解引用操作获取p1所指向的变量的地址。然后,代码将这两个值相乘,并将结果存回p1所指向的变量中。

因此,这段代码的作用是将变量i的值从42修改为42*42(即1764)。

 4.假设p是一个int型指针,请说明下述代码的含义

if(p) // ...
if(*p) //...

这两个条件判断语句的含义是不同的。

  1. if(p) // ...这个语句是在检查指针变量 p 是否为非空(即指向一个有效的内存地址)。如果 p 非空,则会执行后面的代码块;如果 p 为空,则不会执行后面的代码块。
  2. if(*p) //...这个语句是在检查指针 p 所指向的内存地址中存储的值是否为非零。如果 *p 非零,则会执行后面的代码块;如果 *p 为零,则不会执行后面的代码块。

5.下面代码中为什么 p 合法而 lp 非法?

int i = 42;void *p = &i;long *lp = &i;

        在C语言中,intlong是两种不同的数据类型。int通常用于存储整数,而long通常用于存储较大的整数。在大多数平台上,intlong的长度是不同的。int通常为32位,而long通常为64位。

在这段代码中:

int i = 42;
void *p = &i;
long *lp = &i;

第一行代码定义了一个名为i的整数,并初始化为42。

第二行代码定义了一个名为pvoid指针,并将它初始化为整数i的地址。这是合法的,因为void指针是一个通用指针类型,可以存储任何数据类型的地址。

第三行代码试图定义一个名为lp的长整数指针,并将它初始化为整数i的地址。

        这是非法的,因为整数i的地址不能被直接赋给一个长整数指针。虽然它们的位数不同,但它们的对齐要求可能不同,也就是说,它们的内存模型可能不同。因此,将一个int的地址赋值给一个long指针可能会导致未定义的行为。

        在C++中,你不能将一个类型的地址直接赋给另一个类型,除非它们是兼容的类型。例如,如果你有一个指向整数的指针,你可以将它转换为指向字符的指针(因为一个字符的大小和一个整数的大小通常是一样的),但你不能将它转换为指向长整数的指针。


http://www.ppmy.cn/news/1183627.html

相关文章

RabbitMQ如何保证消息不丢失呢?

RabbitMQ 是一个流行的消息队列系统&#xff0c;用于在分布式应用程序之间传递消息。要确保消息不会丢失&#xff0c;可以采取以下一些措施&#xff1a; 持久化消息&#xff1a; RabbitMQ 允许你将消息标记为持久化的。这意味着消息将被写入磁盘&#xff0c;即使 RabbitMQ 服务…

目标检测类项目数据集汇总

一、玩手机数据集及检测 玩手机数据集下载地址分享: https://download.csdn.net/download/qq_34717531/19870205 二、狗的数据集及检测 狗目标检测数据集下载地址分享:https://download.csdn.net/download/qq_34717531/20813390 三、猫数据集及检测 猫数据集下载地址分享: ht…

Linux服务器部署Spring Boot项目的一些shell命令脚本

1.启动jar包的命令&#xff08;根据jar包数量创建&#xff0c;并指定相对应的jar包&#xff09; nohup java -server -Xms64m -Xmx128m -jar 项目jar包的名称.jar --spring.profiles.activeprod > 记录jar包的日志.log 2>&1 &可以写在start.sh文件里&#xff08…

力扣第763题 划分字母区间 c++ 哈希 + 双指针 + 小小贪心

题目 763. 划分字母区间 中等 相关标签 贪心 哈希表 双指针 字符串 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得…

PLC案例集合

这里写自定义目录标题 按时断电一次性按钮震荡电路上升沿和下降沿红绿灯案例抢答器未完待续 下载程序时&#xff0c;必须将PLC处于停机状态&#xff08;STOP&#xff09; 重新下载程序后&#xff0c;M会保持上一次程序中的状态。 所以&#xff0c;程序开始前要对中继进行复位 …

2023年江西省“振兴杯”工业互联网安全技术技能大赛暨全国大赛江西选拔赛 Write UP

文章目录 一、协议分析 - modbus二、协议分析 - 异常的流量三、协议分析 - S7Error四、协议分析 - OmronAttack五、组态编程 - 工程的秘密六、组态编程 - 工程的秘密七、组态编程 - 简单的计算八、组态编程 - 交通灯九、组态编程 - 有趣的转盘十、应急处置 - 登录日志分析十一、…

Python基础入门例程19-NP19 列表的长度(列表)

最近的博文&#xff1a; Python基础入门例程18-NP18 生成数字列表&#xff08;列表&#xff09;-CSDN博客 Python基础入门例程17-NP17 生成列表(列表)-CSDN博客 Python基础入门例程16-NP16 发送offer(列表)-CSDN博客 目录 描述 输入描述&#xff1a; 输出描述&#xff1…

吴恩达《机器学习》2-2->2-4:代价函数

一、代价函数的概念 代价函数是在监督学习中用于评估模型的性能和帮助选择最佳模型参数的重要工具。它表示了模型的预测输出与实际目标值之间的差距&#xff0c;即建模误差。代价函数的目标是找到使建模误差最小化的模型参数。 二、代价函数的理解 训练集数据&#xff1a;假设我…