指针的定义 指针的运算 指针和数组 字符指针 指针和函数 回调函数 多级指针 空指针
野指针
1变量访问方式
(1)直接访问,变量名进行访问 (2)间接访问,用过指针来实现
2.指针存的是地址,指针变量简称指针,我们可以通过指针(地址)间接访问内存中的另一个数据。
3.指针的定义
一般语法格式: 数据类型 *指针变量名 [=初始地址值]; // int *ptr;
4.取址运算符( & )和 取值运算符( * )
取址运算符,取地址,作用是 取出变量的内存地址。 格式占位符是 %p
取值运算符,作用是 取出指针指向的内存地址处的数据值。
2指针运算
1.指针加减整数
指针与整数的加减运算,表示指针所指向的内存地址的移动
2.指针自增自减
指针自增、自减本质上就是指针加减整数,自增地址后移,自减地址前移。
3.同类型指针相减 (***)
1)相同类型的指针可以进行减法运算,返回它们之间的距离,即相隔多少个数据单位。
2)高位地址减去低位地址,返回的是正值;低位地址减去高位地址,返回的是负值。
3)格式占位符 是 %td
4.指针的比较运算
指针之间可以进行比较运算,如 ==、<、 <= 、 >、 >=,比较的是各自指向的内存地址的大小,返回值是 int 类型整数 1 (true)或 0 (false)。
3指针和数组
1.数组名**
数组名是常量,数组名不是指针,数组名在大多数情况下会被隐式地转换为指向数组第一个元素的指针。
数组名 与 指针的区别:
1)使用 sizeof 运算符,数组名得到的是整个数组的大小;针得到的是本身的大小
2)指数组名的指向不可更改。
3)数组名不能进行自增、自减运算。
2.指针数组 (Pointer Array)***
指针数组 是一个数组,只不过 数组中的每一个元素都是指针
语法规则:数据类型 *指针数组名[长度];
int *ptrArr[3]; // 创建一个长度为3的指针数组
3.数组指针(Array Pointer)***
数组指针 是 一个指针,指向一个数组,指向的是整个数组的地址。但在值上显示的是数组的首元素地址。
语法规则:
数据类型 (*数组指针名)[长度];
// 创建整数数组
int arr[5] = {10, 20, 30, 40, 50};
// 创建指针指向数组arr &arr表示整个数组的地址
int(*ptr)[5] = &arr;
数组指针和数组名的区别:
1.指向不同:数组名指向元素首地址,数组指针指向数组的地址。
2.类型不同 3.可变性 4.初始化 5.访问元素
4字符指针***
1.用字符指针指向一个字符串
char *ptr= "hello tom";
C语言对字符串" hello tom"是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串,程序在定义字符串指针ptr时只是把字符串首地址(即存放字符串的字符数组的首地址)赋给ptr。
5指针和函数*****
1)传地址或指针给函数
示例代码
#include <stdio.h>
// 函数原型
void func(int *);
int main()
{
int num = 100;
int *ptr = #
// 调用函数,传地址
func(&num);
printf("num = %d\n", num);
// 调用函数,传指针
func(ptr);
printf("num = %d\n", num);
return 0;
}
// 函数声明
void func(int *p)
{
*p += 1;
}
输出结果:
num = 101
num = 102
2)传数组给函数
数组名本身就代表数组首地址,因此 传数组 的本质就是 传地址。
6指针函数(返回指针的函数)*****
1) 指针函数 是一个函数,只不过 函数的返回值是一个指针, 这样的函数成为 指针函数。
语法规则:
返回类型 *指针函数名(参数列表)
2)返回值 不能指向局部变量
因为局部变量会在函数运行结束后被销毁,所以函数返回的指针不能指向这些数据。
如果确实有这样的需求,需要定义为静态局部变量。static
7函数指针(指向函数的指针)
函数指针是一个指针,只不过 该指针 指向的是一个函数。
语法规则:
返回类型 (*函数指针名)(参数列表);
注意:()的优先级高于*,第一个括号不能省略,如果省略,就成了指针函数。
8回调函数***
回调函数是由别的函数执行时调用你传入的函数。
e.g 使用回调函数的方式,给一个整型数组int arr[10] 赋10个随机数。
#include <stdlib.h>
#include <stdio.h>
// 1. f 就是函数指针
// 2. f 在 initArray 中被调用,是回调函数
void initArray(int *array, int arraySize, int (*f)())
{
// 循环
for (int i = 0; i < arraySize; i++)
{
array[i] = f(); // 通过 函数指针调用了 getNextRandomValue 函数
}
}
int main()
{
int myarray[10];
// rand 是系统函数,会返回一个随机整数,位于 <stdlib.h> 标准库中
// 传入 rand 作为参数
initArray(myarray, 10, rand);
// 输出赋值后的数组
for (int i = 0; i < 10; i++)
{
printf("%d \n", myarray[i]);
}
return 0;
}
输出结果:
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
9指向指针的指针(多级指针)
10空指针
赋为NULL 值的指针被称为空指针,NULL 是一个定义在标准库 <stdio.h>中的值为零的宏常量。
声明指针变量的时候,如果没有确切的地址赋值,为指针变量赋一个NULL 值是好的编程习惯。
11野指针*
1.野指针的原因
1)指针使用前未初始化 //没确切的地址赋值时,为指针变量赋一个NULL值的好习惯。指针使用之前检查指针是否为 NULL。
2)指针越界访问 (访问不在数组的有限范围内) //小心指针 越界
3)指针指向已经释放的空间 //避免返回指向局部变量的指针。
12总结指针使用一览
变量定义 | 类型表示 | 含义 |
int i | int | i是一个整型变量。 |
int *p | int * | p 是一个指向整型数据的指针 |
int a[5] | int[5] | a 是一个5个元素的整型数组。 |
int *p[4] | int *[4] | p 是一个指针数组,每个元素都是指向整型数据的指针。 |
int (*p)[4] | Int (*)[4] | p 是一个数组指针,指向一个4个元素的整型数组。 |
int f() | Int () | f是一个返回整型数据的函数 |
int *f() | int *() | f是一个指针函数,返回指向整数数据的指针。 |
int (*p)() | int (*)() | p 是一个函数指针,指向一个返回整型数据的函数。 |
int **p | int ** | p是一个指向指针的指针。 |