一、地址
在电脑中,我们所使用的数据一般存储在内存当中,为了高效管理内存空间,计算机将内存划分为一个一个的内存单元,每个单元占一个字节。这些内存单元的编号我们称之为地址,就像是根据酒店房间的门牌号能快速找到入住的客人,有了地址,我们就能快速地查找或者修改其中所储存的数据。
二、指针初识
指针变量,就是存放地址的变量。当我们需要将地址存储起来以备之后使用的时候,我们就将地址储存在指针变量中。
1、创建指针变量的过程:
(1)向内存申请空间:创建变量就是在想内存申请空间:int a = 10;
(2)得到变量的地址->取地址操作符(&)->&a得到了变量a的地址
(3)创建指针变量存储地址->int * pa=&a;
int 代表pa指向的变量是int类型
*代表pa是指针变量
2、解引用操作符(*)
将地址储存在指针变量中后,可以通过指针找到地址所指向的对象。
#include <stdio.h>
int main()
{
int a = 100;
int* pa = &a;
*pa = 0;
return 0;
}
*pa 的意思就是通过pa中存放的地址,找到指向的空间,*pa其实就是a变量了;所以*pa=0,这个操作符是把a改成了0。
3、特殊指针void*
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指
针),这种类型的指针可以⽤来接受任意类型地址。但是void* 类型的指针不能直接进⾏指针的+-整数和解引⽤的运算。
4、const修饰指针
(1)const在*右边:指针变量指向的地址不变,但指针的内容可变
(2)const在*左边:指针变量的内容不变,但指针的指向的对象可变)
三、数组与指针
数组名在大多数情况下是数组首元素的地址(&arr和sizeof(arr)除外,代表在整个数组),我们可以将数组名和指针相联系,利用指针访问数组。
#include <stdio.h>
int main()
{
int arr[10] = {0};
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));
}
return 0;
}
我们同样可以用p[i]来访问数组arr的内容,所以一维数组传参的本质是传递数组首元素的地址。
四、指针数组
指针数组是数组,是用来存放指针的数组,基本类型是 int *[]。
#include <stdio.h>
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
五、数组指针
数组指针是指针,是存放数组地址的指针变量,基本类型是 int (*)[ ]
⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
int i = 0;
int j = 0;
for(i=0; i<r; i++)
{
for(j=0; j<c; j++)
{
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
test(arr, 3, 5);
return 0;
}
六、函数指针
函数指针变量是存放函数地址的变量,之后通过调用地址就可以调用函数。
函数是有地址的,&函数名和直接用函数名表示相同的地址
函数指针的创建:
函数指针的调用:
例:int num=(pf3)(3,4) (num=7)
七、函数指针数组
将函数的地址存放到数组中,就是函数指针数组
创建形式为: int (*parr[3])();
函数指针数组可以将返回类型,参数类型,参数个数相同的函数的地址存放到数组中,能更方便快捷地进行调用。例如计算器函数进行加减乘除的调用。