c++指针【1】

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

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

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

cpp 复制代码
int* p;

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

cpp 复制代码
int x = 10;  
int* p = &x;  // p现在指向x的内存地址

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

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

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

cpp 复制代码
int val = 56;
int *p = &val; //p存放变量val的地址,或者说p是指向变量val的指针
cpp 复制代码
double val;
double *pd = &val; //正确:初始值是double型对象的地址
double *pd2 = pd;  //正确:初始值是指向double对象的指针

int *pi  = pd;     //错误:指针pi的类型和pd的类型不匹配
     pi  = &val;   //错误:试图把double型对象的地址赋值给int型指针

指针值

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

1.指向一个对象。

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

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

4.无效指针,也就是上述情况之外的其他值。
利用指针访问对象

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

cpp 复制代码
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++编写指针代码,分别更改指针的值以及指针所指向对象的值

cpp 复制代码
#include<iostream>

int main()
{
	float  x = 3.6; //定义一个整型变量x并初始化为3.6
	float *ptr = &x ; //定义一个指向x的指针ptr

	std::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. 语法形式:引用使用起来就像使用普通变量一样简单,而指针需要使用解引用操作符*来访问其所指向的对象。

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

cpp 复制代码
#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.请简述下面这段代码的作用:

cpp 复制代码
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型指针,请说明下述代码的含义

cpp 复制代码
if(p) // ...
if(*p) //...

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

  1. if(p) // ...这个语句是在检查指针变量 p 是否为非空(即指向一个有效的内存地址)。如果 p 非空,则会执行后面的代码块;如果 p 为空,则不会执行后面的代码块。
  2. if(*p) //...这个语句是在检查指针 p 所指向的内存地址中存储的值是否为非零。如果 *p 非零,则会执行后面的代码块;如果 *p 为零,则不会执行后面的代码块。
    5.下面代码中为什么 p 合法而 lp 非法?
cpp 复制代码
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++中,你不能将一个类型的地址直接赋给另一个类型,除非它们是兼容的类型。例如,如果你有一个指向整数的指针,你可以将它转换为指向字符的指针(因为一个字符的大小和一个整数的大小通常是一样的),但你不能将它转换为指向长整数的指针。

相关推荐
sukalot1 分钟前
windows C#-查询表达式基础(一)
开发语言·c#
ahadee12 分钟前
蓝桥杯每日真题 - 第12天
c++·vscode·算法·蓝桥杯
一二小选手21 分钟前
【Java Web】分页查询
java·开发语言
大G哥21 分钟前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python
vortex534 分钟前
解决 VSCode 中 C/C++ 编码乱码问题的两种方法
c语言·c++·vscode
Code成立35 分钟前
《Java核心技术 卷I》用户图形界面鼠标事件
java·开发语言·计算机外设
Xiao Fei Xiangζั͡ޓއއ1 小时前
一觉睡醒,全世界计算机水平下降100倍,而我却精通C语言——scanf函数
c语言·开发语言·笔记·程序人生·面试·蓝桥杯·学习方法
记录无知岁月1 小时前
【MATLAB】目标检测初探
开发语言·yolo·目标检测·matlab·yolov3·yolov2
远望清一色1 小时前
基于MATLAB身份证号码识别
开发语言·图像处理·算法·matlab
NMBG221 小时前
[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
java·开发语言·面试·java-ee·intellij-idea