指针是一个地址,一个变量的地址称为该变量的指针,而指针变量是存放地址的变量,指针变量就是地址变量,用来存放地址,指针变量的值就是地址(指针)。
定义指针变量的一般形式为:类型名 *指针变量名
例如:int a = 10;
int * pa = &a;
这⾥pa左边写的是 int* , * 是在说明pa是指针变量,⽽前⾯的 int 是在说明pa指向的是整型(int) 类型的对象。
指针的类型一般有:整型、字符型、浮点型、数组指针、函数指针和结构体指针。我用代码展示一下:
int n = 100;
int* pn = &n;//整型指针 指针类型是int *
char c = 'w';
char* pc = &c;//字符型指针 指针类型是char *
float f = 3.14f;
float* pf = &f;//浮点型指针 指针类型是float *
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*pa)[10] = &arr;//数组指针 每个元素的类型是int 指针类型是int (*)[10]
int* pb[10]=&arr;//指针数组 每个元素的类型是int* 数组类型是int* [10]
void add(int,int){
...
}
int (*ph)(int, int) = &add;//函数指针 指针类型是int (*)(int, int)
//结构体指针有两种定义方法
struct stu {
...
}*p;
struct stu *p;//结构体指针 指针类型是struct stu*
结构体指针的访问变量方法
1.p->结构体成员;
2.(*p).结构体成员;
解引⽤操作符是*,如果我们定义了一个指针变量p指向某个元素的地址,*p 的意思就是通过p中存放的地址,找到指向的空间。比如:
int a = 100;
int* p= &a;
printf("%d\n",*p);//*p就是a地址空间的内容,即100
指针变量的大小取决于地址的大小 ,32位平台下地址是32个bit位(即4个字节) ,64位平台下地址是64个bit位(即8个字节)。
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+-整数和解引⽤的运算。⼀般 void* 类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以 实现泛型编程的效果。使得⼀个函数来处理多种类型的数据。
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
出现野指针的原因:
1. 指针未初始化:就是在开始定义指针变量的时候没有给它内容。
2. 指针越界访问:比如当指针p指向的范围超出数组的范围时,p就是野指针。
3. 指针指向的空间释放:比如在主函数中指针p指向了函数,函数调用完后内存释放,p就是野指针。
规避野指针我们就可以:1.指针初始化,指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性。2.小心指针越界,不能超出范围访问,超出了就是越界访问。3.指针使⽤之前检查有效性,避免返回局部变量的地址。
指针变量也是变量,是变量就有地址,我们可以用二级指针指向指针变量的地址。比如:
int a=10;
int * pa=&a;
int ** ppa=&pa;
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引用操作: *pa ,找到的是 a。三级指针也是一样的道理。
常量指针:如果在定义指针变量的时候,指针变量前用const修饰,被定义的指针变量就是指向常量的指针变量,指向常量的指针变量称为常量指针。比如:
const int* p=&a;
int const * p=&a;
大家可以理解为const修饰的是*,指针变量可以修改,但是指针变量所指向的内存空间是不可以修改的。
指针常量:顾名思义它就是一个常量,但它是指针修饰的。比如:
int * const p=&a;
大家可以理解为const修饰的是指针变量,指针变量不可以修改,但是指针变量所指向的内存空间是可以修改的。引用的本质就是指针常量。
这篇文章是我个人对C语言中指针的认识,如果觉得对你有帮助可以收藏下来慢慢理解,欢迎大家进行批评指正,指针是我们的一大利器,大家要理解指针并懂得如何运用才会让我们编写程序事半功倍。一起加油