![](https://img-blog.csdnimg.cn/direct/cac79902b3f2489a87e9445ff466dbd8.png)
一、指针的基础知识
1.指针的定义
地址
在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为地址,就像⽣活中我们把⻔牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语⾔中给地址起了新的名字叫:指针。
所以我们可以理解为: 内存单元的编号 == 地址 == 指针
指针变量的大小
32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
取地址操作符(&)
取地址操作符的作用就和它的名字一样:获取所需内容的地址。
解引用操作符(*)
我们拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这⾥用到的操作符叫解引⽤操作符(*)。
![](https://img-blog.csdnimg.cn/direct/1c8c509720cd4ed2bb3421a410537081.png)
2.指针运算
指针+-整数
实例:
指针-指针
实例:
void*指针
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。
3.const修饰指针
const修饰变量
const的作用:使修饰的变量无法更改。
const修饰指针变量
const在修饰指针变量时在*的位置不同作用效果也不同。
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。
const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。
4.野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
野指针的成因
1)指针未初始化
2)指针越界访问
3)指针指向的空间释放
如何规避野指针
1)指针初始化
2)小心越界访问
3)指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性
5.assert断言
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。
assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。
6.指针的使用和传址调用
strlen的模拟实现
库函数strlen的功能是求字符串⻓度,统计的是字符串中 \0 之前的字符的个数。
传值调用和传址调用
![](https://img-blog.csdnimg.cn/direct/a73c84caf978450eb6363a2cfa7d22ab.png)
二、数组中的指针
1.数组名的理解
数组名就是数组⾸元素(第⼀个元素)的地址。
sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
2.使用指针访问数组
有了前⾯知识的⽀持,再结合数组的特点,我们就可以很⽅便的使⽤指针访问数组了。
3.一维数组传参的本质
本质上数组传参本质上传递的是数组⾸元素的地址。
⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
4.冒泡排序
冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较。
void Bubble_sort(int arr[], int sz)
{
int i = 0;
int j = 0;
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[10] = { 9,5,6,3,7,1,4,2,8,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
Bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
5.二级指针
是一个指针变量,指向一个一级指针,并保存该一级指针的地址;
6.指针数组
指针数组的每个元素都是⽤来存放地址(指针)的。
7.指针数组模拟二维数组
三、函数中的指针
1.字符指针变量
在指针的类型中我们知道有⼀种指针类型为字符指针 char* ;
⼀般使⽤:
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
还有⼀种使⽤⽅式如下:
int main()
{
const char* pstr = "hello bit.";
printf("%s\n", pstr);
return 0;
}
2.数组指针变量
整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。
浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
数组指针变量: p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。
这⾥要注意:[]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。
3.二维数组传参本质
⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址。
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
int i = 0;
int j = 0;
for(i=0; i<r; i++)
{
for(j=0; j<c; j++)
{
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
test(arr, 3, 5);
return 0;
}
4.函数指针变量
函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的。
#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));
printf("%d\n", pf3(3, 5));
return 0;
}
5.函数指针数组
所谓函数指针数组,就是一个存放函数指针的数组。
6.函数指针数组的⽤途:转移表
举例:计算器的⼀般实现:
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
四、回调函数
1.什么是回调函数
回调函数就是⼀个通过函数指针调⽤的函数。
举例:
2.qsort使用实例
使用qsort函数排序整形数据
使用qsort排序结构数据
五、总结
以上内容不仅是对知识点的总结,也是对我近期学习状况的总结,感谢各位的观看。