IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言:指针详解 -> 正文阅读

[C++知识库]C语言:指针详解

目录

指针就是地址,口语中说的指针通常指的是指针变量

指针的定义以及指针类型

野指针

指针运算

a.指针+/-整数

b.指针只能-指针,不能+指针

指针与数组

二级指针

指针数组

指针的大小是固定的4/8个字节(32位平台/64位平台)

字符指针

指针数组

数组指针

数组指针的使用

数组指针和指针数组的区分

数组名与&数组名的区别

数组传参和指针传参

一维数组传参

二维数组传参

一维指针传参

二维指针传参

函数指针

函数指针数组

回调函数


  • 指针就是地址,口语中说的指针通常指的是指针变量

  • 指针的定义以及指针类型

例如:int* p;

p的类型并不是int,而是int*

当然的,除了int类型的指针还有short*的float*,double*等等的类型的

当然这里值得一提的是,这里的3个printf,都是打印4.

在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以

一个指针变量的大小就应该是4个字节。

那这样指针的类型不一样但都是4个字节,那指针的类型有什么用呢?答案在下面

由图中可以知道,第一个图int类型的a的地址由int*来存储

第二个图int的a的地址由char*来存储。可以看到第一个图更改了4个字节的地址,但第二个图只更改了1个字节的地址。

所以要用相同类型的指针变量来存储相同类型的变量地址,就像第一个图一样。

其实:

char* 类型的指针是为了存放 char 类型变量的地址。

short* 类型的指针是为了存放 short 类型变量的地址。

int* 类型的指针是为了存放 int 类型变量的地址。

而指针类型的例外一个作用:指针的类型决定了指针向前或者向后走一步有多大(距离)

  • 野指针

定义:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

比较常见的成因是:指针未定义,以及数组越界访问,形参或者其他原因造成的指针指向的空间释放

我们在编写代码时,需要努力的规避野指针,来避免程序出错

  • 指针运算

a.指针+/-整数

例如:

int arr[10]={1,2,3,4,5,6,7,8,9,10};

int *p=arr;

*p+1;

这里*p+1访问的是arr[1];

这里,++的运算级别比*高,所以先进行vp++,再加*,因为是后置++所以*vp++是访问的是*vp,然后再进行++,进入到下一个。

下图红色区域为数组地址的位置。

这里当数组减到values[0]的时候,因为判断条件是vp>=values[0],所以还会进行一次循环判断,这里就会超出数组的范围啦。

这样的话,能不能成功运行取决于编译器,所以最好不要这样写。

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与

指向第一个元素之前的那个内存位置的指针进行比较。

这里我给翻译一下,就是可以跟数组后面的指针作比较,但不可以跟数组前面的的指针作比较。

b.指针只能-指针,不能+指针

  • 指针与数组

当数组的首地址(数组名)定义给了指针的话。

.p+i 其实计算的是数组 arr 下标为i的地址。(p为指针)

  • 二级指针

二级指针其实就是将一个指针的地址再将其放在一个指针中,类似于套娃。.

**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .

  • 指针数组

int arr[10]其实就是存有int类型数据的数组

同理可得,指针数组也是一个数组,是一个存有指针的数组.

例如:int* arr[10];

指针的大小是固定的4/8个字节(32位平台/64位平台)

  • 字符指针

字符指针简单来说就是存放字符变量的指针

我们来研究一下这个代码:

从这里我们可以看到,p2存放的是一个字符串,所以字符指针不止可以存放字符还可以存放字符串

我们将p2解引用打印出来发现打印出a,所以如果存放的是字符串,字符串存到p2(指针)中存放的是字符串首元素的地址

我们要打印首元素的话需要解引用,也就是*p2

如果我们要打印字符串的时候,我们只要给字符串首元素的地址就好,也就是p2

这里p2存放的是常量字符串,常量字符串不允许修改

而如果我们想要修改的话,就得利用可以修改的空间,用数组来存储的时候就可以修改了

  • 指针数组

说白了,就是存放指针的数组

  • 数组指针

存放数组变量的地址的指针

  • 数组指针的使用

我们看一下这个代码,我们会发现这个代码很别扭

这个代码奇怪的地方就在print传过去的&arr和print接受的指针类型,以及打印的写法。

首先说明不建议这么写。

这里传过的&arr是一个地址,而地址就是指针,这个指针指向数组,所以是数组指针

p是&arr,而p不就是&arr,和&不就相互抵消了嘛,所以p=arr

二维数组传参(写成指针)

arr1为二维数组,而arr1这个数组名表示二维数组的首地址,而二维数组的首地址是第一行的地址。

所以二维数组的数组名是指向二维数组的第一行的,这个第一行相当于一个一维数组

相当二维数组的首地址是一个指针,然后它指向一个一维数组,所以写成数组指针。

而这个我解释一下,p1+i相当于访问第i行的地址,*(p1+i)解引用相当于第i行,然后再加j然后解引用,相当于找第i行第j列的那一个。

  • 数组指针和指针数组的区分

  • 数组名与&数组名的区别

我们来看一个例子

这里我们发现arr和&arr是一样,而arr是首元素地址,&arr是整个数组的地址,但整个数组的地址也得从首元素一样啊。

我们看下面两个,这两个的后两位一个是2C一个是50,2C是2x16+12x1=44. 50是5x16=80,这两个的差值是36加上第一个的地址的4刚好是40,跳过一整个数组的大小。

  • 数组传参和指针传参

数组传参时,形参可以是数组也可以是指针。

一维数组传参

这里比较有困惑的应该是第五个,我们的arr2是一个存放整形指针(地址)的数组,而我们的int**arr是二级指针

二级指针就是存放着一级指针的指针,这两个不就是相同的嘛,所以可以传过去。

二维数组传参

一维指针传参

一级指针传参只能用一级指针来接收

二维指针传参

二级指针传参只能用二级指针来接收

当形参确定为一级指针时,可以将什么变量传过去呢?

一级指针(*p),一级数组(arrp[10]),&a

当形参确定为二级指针时,可以将什么变量传过去呢?

二级指针(**p),对一级指针取地址(&p2)(p2为一级指针),指针数组(int*p[10])

  • 函数指针

我们先来看一个例子:

我们通过这个例子我们可以知道,原来函数名也等于函数的地址啊

函数指针的定义方法:int(*p)(int x,int y)=Add;

调用函数指针的时候,函数指针的传过去的值可以写名字也可以不写名字

下面这个例子要理解一下

  • 函数指针数组

说白了就是存放了函数指针的数组

int(*p[5])(int x, int y) = { 0, add, sub, mul, div };

  • 回调函数

回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个

函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数

的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进

行响应。

简单来说就是:一个函数指针(或者地址)作为一个函数参数被另外一个函数调用,这个函数就叫做回调函数

我们先来看一个库函数qsort(只是一个排列函数)(头文件#include)

代码完整实现

void*类型的指针很宽容,什么类型的指针都可以放进去,但应用的时候不好运用

void型时你p+1访问的几个字节的长度不清楚

如果我们利用冒泡排序的方法写一个与qsort类似的函数呢

不同类型的数据,比较方法也不一样,用冒泡排序来举例子就是

如果我们利用冒泡排序的方法的话

我们就需要找到要比较的两个值的地址,但void*不可以进行+/-等操作。所以要下面这样

完整代码如下

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:45:50  更:2022-08-19 18:46:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 16:44:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码