指针的两个要点
内存是如何存放变量的?
指针和指针变量
地址的产生
232 个地址,1个地址管理1个字节,总共能管理 232 个字节(4GB)的空间。
同样的,在 64 位系统中,就有 264 个地址。
总结
指针的具体类型
int num = 10;
p = #
char* pc = NULL;//char* 就是 pc 的类型
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;
指针类型的意义
先说结论
举个栗子
#include
int main()
{
int a = 0;
char b = 'c';
int* pa = &a;
char* pb = &b;
printf("%p\n", &a);
printf("%p\n", pa);
printf("%p\n", pa + 1);//int* 类型的指针一步跨 4 字节
printf("----------------\n");
printf("%p\n", &b);
printf("%p\n", pb);
printf("%p\n", pb + 1);//char* 类型的指针一步跨 1 字节
return 0;
}
野指针的概念
举个栗子
#include
int main()
{
int* a;
*a = 123;
return 0;
}
1. 指针未初始化
#include
int main()
{
int* p;//局部变量指针未初始化,默认为随机值
*p = 20;//非法访问内存,将随机一个地址中存的值改成 20
return 0;
}
2. 指针越界访问
int main()
{
int i = 0;
int arr[10] = { 0 }; //数组名就是首元素地址 arr = &arr[0]
int* p = arr; //p 指向了数组的第一个元素,p + 1 指向第二个元素
for (i = 0; i <= 10; i++)
{
*p = i;
p++; //弄到最后会让 p + 10 相当于 arr[10],直接就越界了
}
return 0;
}
3. 指针指向的空间释放
int* test()
{
int a = 10;
return &a;
//因为 a 是局部变量,当把 a 的地址返回之后,变量 a 自动销毁
//原来的地址存放的就不再是变量 a 了,
}
int main()
{
int* p = test();
//用 p 来接收返回的 a 的地址
//当接收了 p 的地址后,再往下使用 p 就成了野指针
//当变量 a 销毁之后,p 还是记得传过来的地址,但此时这个地址已经不再指向 a 了
//当 p 用这个地址往回找的时候,就不晓得找的到底是谁了
return 0;
}
指针初始化
int a = 110;
int* p1 = &a;//明确把 a 的地址赋给 p1
int* p2 = NULL;//p2 哪都没指向,它是个空指针
指针指向空间释放及时置NULL
free(p); //释放 p 所指向的空间
p = NULL; //释放完之后要及时将该指针置空
指针使用之前检查有效性
if(p != NULL)
{
*p = 100;//不是空指针就可以对 p 进行解引用
}
指针 - 指针的用途
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
指针和数组的区别
举个栗子
int main()
{
int count = 0;
char str[] = "hello word!";
while (*str != '\0')
{
str++;//数组名是个常量,不可以自增
count++;
}
printf("总共有 %d 个字符\n", count);
return 0;
}
左值的定义
int main()
{
int count = 0;
char str[] = "hello word!";
char* target = str;
while (*target != '\0')
{
target++;//指针是个左值(变量),可以修改
count++ ;
}
printf("总共有 %d 个字符\n",count);
return 0;
}
结论
1. 二级指针的定义
int a = 10;
int* pa = &a; //pa 是一级指针变量,存放整型变量 a 的地址
int** ppa = &pa;//ppa 是二级指针变量,存放指针变量 pa 的地址
2. 二级指针的类型
char** ppa = NULL;
int** ppb = NULL;
short** ppc = NULL;
long** ppd = NULL;
float** ppe = NULL;
double**ppf = NULL;
3. 二级指针解引用
4. 二级指针的用途
1. 指针数组的定义
int* p[5];
//p 先和 [5] 结合,表明 p 是一个指针数组
//数组的每个元素都是一个 int* 类型的指针
2. 指针数组的用途
int a = 10;
int b = 20;
int c = 30;
......
int arr[5] = {10,20,30,......};
/可以用整型数组将多个同类型的值存储起来
int* pa = &a;
int* pb = &b;
int* pc = &c;
......
int* parr[5] = {&a,&b,&c,......};
//也可以用数组将多个同类型的指针存储起来
3. 指针数组的访问
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* parr[5] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", *(parr[i]));
//找到数组对应下标内存放的地址,然后解引用
}
putchar('\n');
return 0;
}
4. 使用指针数组模拟二维数组
int arr1[4] = { 1,2,3,4 };
int arr2[4] = { 2,2,3,4 };
int arr3[4] = { 3,2,3,4 };
int* parr[3] = { arr1,arr2,arr3 };
int main()
{
int arr1[4] = { 1,2,3,4 };//第一行
int arr2[4] = { 2,2,3,4 };//第二行
int arr3[4] = { 3,2,3,4 };//第三行
int* parr[3] = { arr1,arr2,arr3 };
//parr[i],访问指针数组的每个元素的时候,
//就相当于拿到了上面三行每一行的第一个元素
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%d ", parr[i][j]);
}
putchar('\n');
}
return 0;
}