指针
1. 指针是什么?
指针就是地址,内存中最小单元的编号
口语中说得指针通常指的是指针变量
int a = 0;
// a 是整型变量,占用4个字节的内存空间
int* pa = &a;
// pa 是指针变量,存放着 a 的地址
指针的大小32位平台上是4个字节,在64平台上是8个字节
2. 指针和指针类型
有多少种数据类型就有多少种对应的指针类型
指针类型决定了指针在被解引用的时候访问几个字节。
int* 的指针 ,解引用的时候访问 4 个字节
char* 的指针,解引用的时候访问 1 个字节
等等
指针类型决定了指针+ - 整数操作的时候,跳过了几个字节。
int a = 0;
int* pa = &a;
pa+1; //这里的 pa 指针 +1 跳过 4 个字节内存,访问下一个
char c = 0;
int pc = &c;
pc+1; //这里的 pc 指针 +1 跳过 1 个字节内存,访问下一个
3. 野指针
野指针就是指针指向的位置是不可知的
3.1 野指针的成因
- 指针未初始化
//局部变量指针未初始化,默认为随机值。
int* pa ;
*pa = 10;
- 指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr; //int* p = &arr[0]
int i = 0;
// i 的循环次数是 11 次,但数组只存储了 10 个整型
//最后一次循环时,*p 访问的内容就不是数组 arr 了
for (i = 0; i <= 10; i++)
{
*p = i;
p++; // 地址+1
}
return 0;
}
- 指针指向的空间释放
3.2 如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放及时置为NULL
- 避免返回局部变量的地址
- 指针使用前检查有效性
4 指针运算
- 指针 + - 整数
- 指针 - 指针
- 指针的关系运算
4.1 指针 + - 整数
指针 + - 整数就是指针跳过相应指针类型内存大小,指向下一个内存的地址
int arr[10] = { 0 };
int* p = arr; //指针 p 指向的时数组首元素地址
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
*p = 1;
p++; //p++ 表示指针指向了数组下一个元素的地址
}
4.2 指针 - 指针
指针 - 指针得到的是指针和指针之间的元素个数
注:只有指向同一块内存的指针才能相减
#include <stdio.h>
int my_strlen(char* str)
{
char* start = str; //开始地址
while (*str != '\0')
{
str++;
}
// str 是最后一个元素的地址
return (str - start);
}
int main()
{
char str[] = "abcdef";
int len = my_strlen(str);
printf("%d\n", len);
return 0;
}
4.3 指针的关系运算
进行指针指向的内存位置的大小比较
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较。
但不允许与指向第一个元素之前的那个内存位置的指针进行比较。
5. 指针和数组
通过指针来访问数组
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
//printf("%d ", *p);
//p++;
printf("%d ", *(p + i));
//两种访问方法
}
6. 二级指针
二级指针是存储一级指针的地址的指针变量
一级指针
int* p = NULL;
int a = 0;
int* pa = &a; //pa是指针变量,是一个一级指针
int** ppa = &pa; //ppa是一个二级指针
**ppa = 10; //通过两次解引用找到 a 的地址并改变 a 的值
printf("%d \n", a);
7. 指针数组
存放指针的数组
int a = 10;
int b = 20;
int c = 30;
//创建指针数组来存放a,b,c的地址
int* parr[3] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", *(parr[i]));
}