指针概念
指针是C语言中的一种数据类型,用这种类型定义的数据变量称为指针变量,该变量存放的是一个地址。
int a = 10;
int *p = &a;//指针变量p保存的是整型变量a的地址
printf("%p %d", p, *p);//通过解引用可以访问地址上存储的值
比如:你有一个箱子,里面有你想要的东西,你用钥匙打开箱子拿到东西,这个钥匙就是一个一级指针。
指针大小
32位机器下:指针为4个字节
在32位的平台上,指针大小永为4
64位机器下:VS默认按照32位方式编译,所以指针大小还是为4,但是可以对编译器设置,让其按照64位的方式进行编译,此时指针大小为8
对编译器设置让程序按照64位的方式进行编译:
二级指针
你有一个箱子,里面有你想要的东西,你用钥匙打开箱子拿到东西,这个钥匙就是一个一级指针。如果,这个钥匙不能直接打开你的箱子,但可以打开存放开你这个箱子钥匙的箱子,这个钥匙就是一个二级指针。二级指针是一个存放一级指针的地址的变量
int a = 10;
int *p = &a;
int **p1 = &p1;
printf("%d %x\n", *p, *p1);
printf("%p %p %p\n", p, p1,&a);
结果:
p存放变量10的地址;
p1存放指针变量p的地址
p1通过**p1找到p,对p进行解引用找到a.”
那么二级指针多大呢?
在32位平台上,当然还是4
指针中存放的是变量的地址,32位平台上,地址的大小时32bit为,4byte的大小。(可以这样认为指针就是地址)
数组指针
数组指针是数组还是指针?
回:是指针
int* p;是能够指向整型变量的指针,float* p;是可以指向浮点型变量的指针。那么顾名思义,数组指针就是可以指向数组的指针。
int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?
答:p1是存放10个int*类型数据的数组名
p2是指向存放10个元素的数组的指针变量名
数组指针的使用:
void print_arr2(int (*arr)[5], int row, int col)
{
int i = 0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
print_arr2(arr, 3, 5);
return 0;
}
数组名arr,表示首元素的地址
但是二维数组的首元素是二维数组的第一行
所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址,可以数组指针来接收
函数指针
函数指针是一个指针,用来存储函数地址。
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
结果:hehe
hehe
test和&test是等同的
利用函数指针保存函数地址。
int max(int a,int b)
{
return a>b?a:b;
}
//把函数指针当做参数
int fun(int a,int(*p)(int,int))
{
int ret=p(10,20);
return ret>a:ret:a;
}
int main()
{
fun(10,max)
int (*p)(int ,int) = max;
int sum = (*p)(10,20);
//==>等同与p(10,20),也就是test(10,20)
return 0;
}
int (*pf)(int *,char );指向返回值为int,有两个参数,分别是int*,和char类型参数的函数。
野指针
野指针就是指针指向的位置是不可知的,不确定的。
野指针产生的原因:
- 指针未初始化
- 指针指向的空间被释放了,但是没有把该指针指向一个合法的位置
- 指针越界访问,比如在遍历数组时,访问超过数组元素个数
使用指针时的注意事项
- 一般情况下,定义一个指针变量,最好让该指针变量有一个合法的指向,如果没有合法的指向,则指向NULL
- 避免产生野指针,或者垂悬指针( 指针指向访问受限的空间或该空间以及被释放的空间 )
- 在使用指针时,最好先判空
指针和数组的区别
数组:一组相同元素的集合
一维数组的使用:
#include <stdio.h>
int main()
{
int arr[10] = {0};//数组的不完全初始化
int sz = sizeof(arr)/sizeof(arr[0]);//计算数组的元素个数
int i = 0;//数组下标从0开始
for(i=0; i<sz; i++)
{
arr[i] = i;
}
for(i=0;i<sz;++i)//输出数组的内容
{
printf("%d\n",arr[i]);
}
return 0;
}
一维数组在内存中的存储:
#include <stdio.h>
int main()
{
int arr[10] = {0};
int i = 0;
//int*p = arr;
for(i=0; i<sizeof(arr)/sizeof(arr[0]); ++i)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
//printf("%p\n",p+i);
}
return 0;
}
结果:
随着数组下标的增长,元素地址有规律的递增。数组在内存中是连续存放的。
二维数组(是一个特殊的一维数组):
定义一个二维数组arr[3][3],由于二维数组在内存中也是按照顺序存储,所以,arr[2]其实就相当是一个数组指针;指向arr[0][0],arr[2][1],arr[2][2]
指针数组
指针数组:存放指针的数组
int *arr[3];
//[]优先级高,所以arr[3]先结合,是一个数组,
//里面存放int *类型变量
eg:
int arr1[3]={1,2,3};
int arr2[3]={4,5,6};
int arr3[3]={7,8,9};
int * p[3]={arr1,arr2,arr3};
int **q=p;
//p是数组名,代表数组首元素地址
//首元素是一个int *类型的地址,需要int**去接收
数组的特性:
- int arr[10];
- 数组的类型,
- int [10] 数组存储元素的类型,
- int 数组名不能直接++、–
- 只有在sizeof(arr),&arr时,arr表示的是数组本身
指针和数组的区别:
1.数组存放的是数据,指针存放的是地址
2.数组直接对元素进行访问,指针要通过解引用才能访问,间接访问
3.指针通常用于动态数据结构,数组用于存放固定数目且类型相同的元素
4.指针通常指向匿名数据,数组存放已知的