指针
1.什么是指针
1.1内存空间是通过单个的内存单元管理,指针是内存中最小单元的编号,即地址,通过内存单元编号可以找到对应的值,也被称为地址(指针)。接下来我们来看一下地址的表示形式是什么:
int main()
{
int a = 10;
printf("%p",&a);//打印地址用%p
return 0;
}
运行结果如下:
0x00dbfd98
我们发现打印出的地址是一个16进制的数字,但一个int类型所占内存空间大小为4个字节,每个内存单元都有不同的编号(地址),所以
这当中的0x00dbfd98即为第一个内存编号,通过第一个编号可以找到后面的编号。
1.2什么是指针变量
int main()
{
int a = 10;
int * p = &a;
return 0;
}
在上述代码中我们用p来存放a的地址,其数据类型为整形指针
1.3总结:指针即为地址,平常说说的指针即为指针变量,用来存放内存地址的变量内存是由内存单元组成,每个内存单元占一个字节,比如int类型占4个字节,也就是说占4个内存单元大小。其中每个内存单元都有地址,也就是编号,即指针,通过指针可以找到该内存单元。
2.指针和指针类型
指针类型的意义
int main()
{
int a = 0x11223344;
char * pc = (char *)&a;
*pc = 0;
return 0;
}
指针类型决定了指针被解引用时可以访问字节的数量,上述代码指针类型被强制转换为char*类型,char是占用一个字节,而int占4个字节,所以当被强制类型转换时,访问权限发生改变,只能访问一个字节
int main()
{
int a = 0x11223344;
int* pa = &a;
int* pc = (char*)&a;
printf("pa=%p\n",pa);
printf("pa+1=%p\n",pa+1);
printf("pc=%p\n",pc);
printf("pc+1=%p\n",pc+1);
return 0;
}
//结果
//pa=00AFF9BC
//pa+1=00AFF9C0
//pc=00AFF9BC
//pc+1=00AFF9BD
指针类型决定了指针+1/-1操作的时,跳过几个字节(决定指针步长)
3.野指针
概念:野指针就是指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)
野指针成因
- 指针未初始化
int main()
{
int* p;//p没有初始化,没有明确指向
//一个局部变量没有初始化,放的是随机值:0xccccc
*p=10;
return 0;
}
//这里的p就是野指针,因为改指针未初始化,指向的位置是随机的
- 指针访问越界
int main()
{
int arr[10]={0};
int *p =arr;//&arr[0]
int i=0;
for(i=0;i<=10;i++)
{
*p=i;
p++;
}
return 0;
}
//当p指向超出arr数组范围,会出现野指针问题
- 函数释放空间
int* fun()
{
int a = 10;
int* p = &a;
return p;
}
int main()
{
int* p = fun();
return 0;
}
//当函数访问结束后内存空间会被销毁,a所指向的地址虽说被存在p指针当中,但是p指针不能被指向一个确定的值
如何避免出现野指针
int main()
{
int a = 10;
int *p = &a;//明确给指针初始化
int* p2 = NULL;//初始化空指针,NULL相当于0
if(p2!=NULL)//当p2指向的不为空就可以进行解引用
{
*p2 = 100;
}
return 0;
}
4.指针运算
#define N
float values[N];
float *vp;
for(vp=values[0];vp<values[N];)
{
*vp++=0;
//*vp=0 -> vp++
}
数组赋值的一些指针写法
int main()
{
int arr[10];
int* p = &arr;
int sz = sizeof(arr)/sizeof(arr[0]);
for(int i=0;i<sz;i++)
{
//*p = 1;
//p++;
*(p+1) = 1;
}
return 0;
}
指针-指针
int main()
{
int arr[10]={0};
printf("%d",&arr[9]-&arr[0]);
return 0;
}
//运行结果:9
|指针-指针| 得到的是指针和指针之间元素的个数
不是所有指针都能相减,指向同一块空间的2个指针才能相减,才有意义
应用
int fun(char* str)
{
char* start = str;
while(*str!='\0')
{
str++;
}
return (str-start);
}
int main()
{
char ch[10]="abcdefg";
int len = fun(ch);
printf("%d",len);
return 0;
}
5.指针和数组
int main()
{
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (int i = 0; i < sz; i++)
{
printf("\n%p\n%p", &arr[i], p + i);
}
return 0;
}
//运行结果
0000000C82F9F518
0000000C82F9F518
0000000C82F9F51C
0000000C82F9F51C
0000000C82F9F520
0000000C82F9F520
0000000C82F9F524
0000000C82F9F524
0000000C82F9F528
0000000C82F9F528
0000000C82F9F52C
0000000C82F9F52C
0000000C82F9F530
0000000C82F9F530
0000000C82F9F534
0000000C82F9F534
0000000C82F9F538
0000000C82F9F538
0000000C82F9F53C
0000000C82F9F53C
通过上述代码可知指针p和&arr[i]所指向的地址一样,因为数组名是首元素地址,而我们先前通过int *p = arr,把地址赋值给指针变量p,
实际上arr[i]->*(arr+i)
6.二级指针
用来存放一级指针变量的地址
int main()
{
int a = 10;
int* pa = &a;//pa是一个指针变量,一级指针变量,1次解引用就可以找到a
int** ppa = &pa;//ppa是一个二级指针变量,存放指针变量pa的地址
**ppa = 20;
//*pa = 20;
printf("%d ", a);
return 0;
}
//*pa 代表pa是指针,int代表pa指向的类型
//所以*ppa代表的是指针,指向类型为int* ,即写成int* *ppa;
7.指针数组
含义:存放指针的数组
int main()
{
int a = 10;
int b = 10;
int c = 10;
int* pa = &a;
int* pb = &b;
int* pc = &c;
int* arr[3] = { pa,pb,pc };
//arr就是存放指针的数字-》指针数组
for(i=0;i<3;i++)
printf("%d\n", *arr[i]);
return 0;
}
一维数组关联成二维数组
int main()
{
int a1[4] = { 1,2,3,4 };
int a2[4] = { 2,3,4,5 };
int a3[4] = { 3,4,5,6 };
int* pa[3] = { &a1,&a2,&a3 };
int i;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%d ", *(pa[i] + j));
//printf("%d ", pa[i][j]); arr[i]==*(arr+i)
}
printf("\n");
}
return 0;
}