一.对指针的认识
1.内存和地址
一个内存单元就是一个字节,内存就像房间,地址就是房间号,可以根据地址找到某个内存单元(好比用房间号找房间)
内存单元的编号==地址==指针
如何理解编址?
cpu和内存之间有大量的数据交互,所以cpu和内存之间用一条线连起来
我们来理解一下地址总线,在32位机器下有32条地址线,一条地址线有两种情况(0或1,表示脉冲的有无),所以32条地址总线有2^32种情况
cpu将地址的信息通过地址总线传给内存,内存拿到地址可以找到地址所对应的对象,将数据通过数据总线传回cpu的寄存器中
2.指针变量和地址
&是取地址操作符,取出的地址放到变量中去,这个变量就叫指针变量,
指针变量是存放地址的变量,
int main()
{
int a = 0;
int* p = &a;//取出a的地址放入p中
printf("%p\n",p);//int有4个字节,取出的是首字节的地址
//解引用操作符*,可以把通过指针,找到指针指向的对象
//可以把对象的值改变
*p = 20;
printf("%d\n", a);
return 0;
}
3.如何理解指针类型:
int main()
{
int a = 10;
int* p = &a;
//*说明p是一个指针变量,int表示p指向的对象的类型是整形类型
return 0;
}
如果是(x86)32位环境下,就有32根地址线,一个地址就有32bit的大小,也就是4个字节
64位平台下就是8个字节
32位平台下地址是32个bit位,指针变量大小是4个字节
64位平台下地址是64个bit位,指针变量大小是8个字节
注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的
指针类型的意义:决定了解引用向前或向后走多远的距离
比如char*类型的指针解引用访问1个字节,int*类型的指针解引用访问4个字节
void* 类型的指针可以接收任何类型的地址,一般void* 用于函数的参数部分,用于接收不同类型的指针,但是void* 的指针不能用于指针计算
4.const修饰变量与指针变量
const修饰变量,变量就拥有了常属性,变量不能被修改,但本质上还是变量
通过地址还是能把变量的值改变,这样不就打破语法规则了,所以我们要用const去修饰指针变量
有两种修饰指针变量的方法:
1.
2.
5.指针的运算
指针的运算有3种:都可以用于打印数组
1.指针加减整数:
2.指针 - 指针:的绝对值是两个指针之间的元素个数
3.指针之间的逻辑运算:例如指针之间比较大小等价于地址与地址比较大小
6.野指针
野指针:指针指向的位置是不知道的
野指针的成因有很多种
例如:
1.指针未初始化,未初始化指针默认为随机值
2.指针指向数组的越界访问:指针指向超出了数组的范围
3.指针指向的空间释放:
n出函数后把n的空间还给了操作系统,再去找n的位置就相当于非法访问了,你就没有权限去访问了,但那个空间还在那里
assert断言要包含头文件assert.h,assert(p != NULL),括号里为真,继续执行下面的语句,为假停止执行并点出文件名和行号
如果不使用assert了,可以在assert.h前面加上NDEBUG,就把assert禁用掉了
#define NDEBUG
#include<assert.h>
二.对于指针在数组中的理解
1.数组名表示数组首元素的地址
sizeof(数组名)计算的是整个数组的大小
&arr:取出的是整个数组的地址
除这两种外数组名都表示数组首元素的地址
假设数组名是arr
虽然数组名指向数组首元素的地址和 &数组名 都是指向首元素的,
但是arr+1跳过1个元素,&arr跳过整个数组
2.二级指针
一级指针通过a的地址找到a所对应的元素10
二级指针通过p的地址找到p所对应的元素0x11223344
3.指针数组与数组指针
指针数组是存放指针的数组,数组中的每个元素都是指针
int* arr[5] :指针数组
int (*p)[5]:指针p指向的是长度为5,每个元素是int的数组,p是数组指针变量
p指向的是整个数组,&arr取出的是整个数组的地址
int main()
{
int arr[10] = {0};
int(*p)[10] = &arr;
}
去掉变量就是类型
int(*)[5]:数组指针类型
三.各种类型的指针变量
1.字符指针变量
int main()
{
char* p = "abcdef";
//是把字符串的首字符的地址放入指针变量p中
//这种常量字符串不可以改变值的
//因为它存在于内存中的代码段中
char arr[] = "abcdef";
//这种把字符串存入了数组中
//就可以改变值了
// 因为数组中的每个元素都可以重新赋值
//创建一个数组开辟一个空间
return 0;
}
2.二维数组数组名的含义
二维数组的数组名表示整个第一行的地址(第一行整个一维数组的地址)
二维数组:*一次找到一维数组,*两次找到一个元素
3.函数指针变量
函数指针变量是用来存放函数地址的变量
int main()
{
int (*p) (int a, int b);
return 0;
}
函数指针变量p 指向的函数的参数是两个int类型的,返回类型是int
函数指针变量的类型:int(*)(int a,int b)
函数指针数组:存放函数地址的数组
int (*p)(int a, int b) arr[5];
这个数组有5个元素,每个元素都是一个函数的地址
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));//*可以不写,*是一个摆设
printf("%d\n", pf3(3, 5));
return 0;
}
qsort函数是一个排序函数,可以排序各种数据