### 14. 指针
学习 C 语言的指针既简单又有趣。通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的。
正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:
~~~
void main(){
int var1;
char var2[10];
//%p : 输出指针地址
//%#x:以十六进制形式输出无符号整数(输出前缀0x)
printf("var1 变量的地址:%p \n", &var1);
printf("var2 变量的地址:%p \n", &var2);
}
~~~
输出:
~~~
var1 变量的地址:0x7ffee7e976b8
var2 变量的地址:0x7ffee7e976be
~~~
例子:
```
#include <stdio.h>
int main ()
{
int var_runoob = 10;
int *p; // 定义指针变量
p = &var_runoob;
printf("var_runoob 变量的地址: %#x\n", p);
printf("指针变量p的地址: %#x\n", &p);
return 0;
}
```
输出结果
~~~
var_runoob 变量的地址: 0x7fff1a9ef2fc
指针变量p的地址: 0x1a9ef2f0
~~~
![](https://www.runoob.com/wp-content/uploads/2014/09/c-pointer.png)
通过上面的实例,我们了解了什么是内存地址以及如何访问它。接下来让我们看看什么是指针。
#### 什么是指针?
**指针**是一个变量,其**值为另一个变量的地址,即内存位置的直接地址**。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
~~~
type *var-name
~~~
在这里,**type** 是指针的基类型,它必须是一个有效的 C 数据类型,**var-name** 是指针变量的名称。**用来声明指针的星号 \* 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针**。以下是有效的指针声明:
~~~
int *i; //一个整型的指针
double *d;//double 型指针
float *f;//浮点型指针
char *ch//字符型指针
~~~
**所有实际数据类型**,不管是整型、浮点型、字符型,还是其他的数据类型,**对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数**。
**不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同**。
#### 如何使用指针?
使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 \*来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:
例子:
~~~
//如何使用指针
int var = 66;//实际变量的声明
int *ip;//指针变量的声明
ip = &var; //指针变量中存储 var 的地址
printf("var 变量的地址 : %p \n", &var);
//在指针变量中存储的地址
printf("ip 的值:%p \n", ip);
//使用指针访问地址
printf("ip 指针对应的地址:%p \n", &ip);
//使用指针访问地址对应的值
printf("ip 指针中存储的地址对应的值:%d \n", *ip);
~~~
输出:
~~~
var 变量的地址 : 0x7ffe7469379c
ip 的值:0x7ffe7469379c
ip 指针对应的地址:0x7ffe74693790
ip 指针中存储的地址对应的值:66
~~~
#### C 中的 NULL 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为**空**指针。
NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
```
void main() {
int *ptr;
ptr = NULL;
printf("指针变量ptr的值是:%d\n",ptr);//0
printf("指针变量ptr的地址是:%#x\n", &ptr);//%#x:以十六进制形式输出无符号整数(输出前缀0x)
//printf("指针变量ptr的值是:%d", *p);//p不指向任何东西,那么*p也就没有任何意义了,这里如果运行会报错,读取访问权限冲突
//检查一个空指针
if (ptr) printf(" ptr 不是空指针,则执行");
else printf(" ptr 是空指针,则执行............\n");
system("pause");
}
```
输出结果是
~~~
指针变量ptr的值是:0
指针变量ptr的地址是:0x1d8984d8
ptr 是空指针,则执行............
~~~
#### C 指针详解
在 C 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:
| 概念 | 描述 |
| --- | --- |
| [指针的算术运算](https://www.runoob.com/cprogramming/c-pointer-arithmetic.html) | 可以对指针进行四种算术运算:++、--、+、- |
| [指针数组](https://www.runoob.com/cprogramming/c-array-of-pointers.html) | 可以定义用来存储指针的数组。 |
| [指向指针的指针](https://www.runoob.com/cprogramming/c-pointer-to-pointer.html) | C 允许指向指针的指针。 |
| [传递指针给函数](https://www.runoob.com/cprogramming/c-passing-pointers-to-functions.html) | 通过引用或地址传递参数,使传递的参数在调用函数中被改变。 |
| [从函数返回指针](https://www.runoob.com/cprogramming/c-return-pointer-from-functions.html) | C 允许函数返回指针到局部变量、静态变量和动态内存分配。 |
- 前言
- JNI基础知识
- C语言知识点总结
- ①基本语法
- ②数据类型
- 枚举类型
- 自定义类型(类型定义)
- ③格式化输入输出
- printf函数
- scanf函数
- 编程规范
- ④变量和常量
- 局部变量和外部变量
- ⑤类型转换
- ⑥运算符
- ⑦结构语句
- 1、分支结构(选择语句)
- 2、循环结构
- 退出循环
- break语句
- continue语句
- goto语句
- ⑧函数
- 函数的定义和调用
- 参数
- 函数的返回值
- 递归函数
- 零起点学通C语言摘要
- 内部函数和外部函数
- 变量存储类别
- ⑨数组
- 指针
- 结构体
- 联合体(共用体)
- 预处理器
- 预处理器的工作原理
- 预处理指令
- 宏定义
- 简单的宏
- 带参数的宏
- 预定义宏
- 文件包含
- 条件编译
- 内存中的数据
- C语言读文件和写文件
- JNI知识点总结
- 前情回顾
- JNI规范
- jni开发
- jni开发中常见的错误
- JNI实战演练
- C++(CPP)在Android开发中的应用
- 掘金网友总结的音视频开发知识
- 音视频学习一、C 语言入门
- 1.程序结构
- 2. 基本语法
- 3. 数据类型
- 4. 变量
- 5. 常量
- 6. 存储类型关键字
- 7. 运算符
- 8. 判断
- 9. 循环
- 10. 函数
- 11. 作用域规则
- 12. 数组
- 13. 枚举
- 14. 指针
- 15. 函数指针与回调函数
- 16. 字符串
- 17. 结构体
- 18. 共用体
- 19. typedef
- 20. 输入 & 输出
- 21.文件读写
- 22. 预处理器
- 23.头文件
- 24. 强制类型转换
- 25. 错误处理
- 26. 递归
- 27. 可变参数
- 28. 内存管理
- 29. 命令行参数
- 总结
- 音视频学习二 、C++ 语言入门
- 1. 基本语法
- 2. C++ 关键字
- 3. 数据类型
- 4. 变量类型
- 5. 变量作用域
- 6. 常量
- 7. 修饰符类型
- 8. 存储类
- 9. 运算符
- 10. 循环
- 11. 判断
- 12. 函数
- 13. 数学运算
- 14. 数组
- 15. 字符串
- 16. 指针
- 17. 引用
- 18. 日期 & 时间
- 19. 输入输出
- 20. 数据结构
- 21. 类 & 对象
- 22. 继承
- 23. 重载运算符和重载函数
- 24. 多态
- 25. 数据封装
- 26. 接口(抽象类)
- 27. 文件和流
- 28. 异常处理
- 29. 动态内存
- 30. 命名空间
- 31. 预处理器
- 32. 多线程
- 总结
- 音视频学习 (三) JNI 从入门到掌握
- 音视频学习 (四) 交叉编译动态库、静态库的入门学习
- 音视频学习 (五) Shell 脚本入门
- 音视频学习 (六) 一键编译 32/64 位 FFmpeg 4.2.2
- 音视频学习 (七) 掌握音频基础知识并使用 AudioTrack、OpenSL ES 渲染 PCM 数据
- 音视频学习 (八) 掌握视频基础知识并使用 OpenGL ES 2.0 渲染 YUV 数据
- 音视频学习 (九) 从 0 ~ 1 开发一款 Android 端播放器(支持多协议网络拉流/本地文件)
- 音视频学习 (十) 基于 Nginx 搭建(rtmp、http)直播服务器
- 音视频学习 (十一) Android 端实现 rtmp 推流
- 音视频学习 (十二) 基于 FFmpeg + OpenSLES 实现音频万能播放器
- 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)