每天进步一点点,希望的火苗不熄灭。
目录
一、指针是什么?
指针:指针是个变量,存放内存单元的地址(编号),内存单元是一字节一字节划分的。 在计算机科学中,指针 ( Pointer )是编程语言中的一个对象,利用地址,它的值直接(points to )存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“ 指针 ” 。意思是通过它能找到以它为地址的 内存单元 。
#include <stdio.h>
int main()
{
int a = 10;//在内存中开辟一块空间
int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
//将a的地址存放在p变量中,p就是一个之指针变量。
return 0;
}
总结:指针就是变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
二、指针的大小
在 32位的机器上 ,地址是 32 个 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来储,所以一个指针变量的大小就应该是 4个字节。如果在 64位机器上 ,如果有 64 个地址线,那一个指针变量的大小是 8个字节 ,才能存放一个地址。
三、指针和指针类型
我们都知道,变量有不同的类型,例如整形,浮点型等。其实指针也是有类型的。
//将&num(num的地址)保存到p中,我们知道p其实是一个(int *)类型的指针变量。
int num = 10;
p = #
指针类型举例:
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
这里可以看到,指针的定义方式是:
type + *
其实:char* 类型的指针是为了存放 char 类型变量的地址。short* 类型的指针是为了存放short类型变量的地址。int* 类型的指针是为了存放int类型变量的地址。
四、指针类型的意义
1.指针+-整数
#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n); //n的地址(4字节)
printf("%p\n", pc); //n的首字节地址(4字节中的第一个字节地址)
printf("%p\n", pc+1); //n的第二个字节地址(4字节中的第二个字节地址)
printf("%p\n", pi); //n的地址
printf("%p\n", pi+1); //n的地址+4字节
return 0;
}
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
2.指针的解引用
//演示实例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; //0x11223300 小端存储
*pi = 0; //0x00000000
return 0;
}
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如:
char*
的指针解引用就只能访问一个字节,而 int*
的指针的解引用就能访问四个字节。
五、野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。
1.野指针成因
- 指针未初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
- 指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
- 指针指向的空间释放
这部分的内容在动态内存开辟的时候已经整理过了。
2.如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放即使置NULL
- 指针使用之前检查有效性
#include <stdio.h>
int main()
{
int *p = NULL;
//....
int a = 10;
p = &a;
if(p != NULL)
{
*p = 20;
}
return 0;
}
六、指针运算
1.指针+-整数
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
总结:指针向后移动的字节数(不同的指针类型向后移动的字节数不同)。
2.指针-指针
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
总结:两个指针之间包含的元素个数(注意不是字节数)。
七、指针和数组
1. 数组名表示的是数组首元素的地址
。
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
2. 我们可以直接通过指针来访问数组。
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i)); //通过指针*(p+i)来访问
}
return 0;
}
八、二级指针
二级指针: 也是一个变量,变量里面存放的是一级指针的地址。
int a=10; //a为一个变量;
int* pa=&a; //pa为一个一级指针
int** ppa=&pa; //ppa为一个二级指针
我们也可以通过二级指针来修改变量的内容。
*pa=20; //通过一级指针pa将a的内容修改为20
**ppa=30; //通过二级指针ppa将a的内容修改为30
九、指针数组
指针数组:
指针数组是一个数组,是存放指针的数组。
数组我们已经知道整形数组,字符数组。
int arr1[5];
char arr2[6];
int* arr3[5];
//arr3是一个数组,有五个元素,每个元素是一个整形指针。