#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int i = 0;
int* pi = &i;
int** pa = π
return 0;
}
int a=10;
int* p=&a;
int* *pi=&p;
int*:说明指针指向的对象类型是int*
*pi:说明pi是指针变量
注意:指针变量也是变量!!!
一级指针时的解引用:
int a =10;
int b =20;
int* pi=&a;
printf("%d",*pi);//等价为a
二级指针的解引用:
int a = 10;
int* p=&a;
int* *pi=&p;
**pi=30;//等价为a=30
类比:
整型数组为存放整型的数组,字符数组是存放字符的数组,那么指针数组即为存放指针的数组
画图对比:
发现:指针数组的每个元素都是⽤来存放地址(指针)的,指针数组的每个元素是地址,⼜可以指向⼀块区域
例题一:
指针模拟二维数组
编程实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 2,3,4,5,6 };
int arr3[5] = { 3,4,5,6,7 };
int* pi[3] = { arr1,arr2,arr3 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", pi[i][j]);
}
printf("\n");
}
return 0;
}
结果:
虽然这个代码模仿了二维数组,但实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的
指针数组是⼀种数组,数组中存放的是地址(指针),那么数组指针变量又是啥?
还是类比:
对比指针数组和数组指针:
int* pi[5];//数组指针
int(*pi)[5];//指针数组
why???
这时候就要好好分析结和性了,我们知道[]的优先级要⾼于*号的,对于一式,pi与[]先结合,所以是数组指针,对于二式,pi先和*结合,说明p是⼀个指针变量,然后指着指向的是⼀个⼤⼩为5个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。
对数组指针初始化:
int(*pi)[]=&arr;//&arr是整个数组
char* pc="hello world.";
请问这个字符指针是将整个字符串放入指针变量里面了吗?
运行后会发现,实际上还是将第一个字符(可以把字符串想象为一个字符数组,但是这个数组是不能修改的)放进指针变量了
看到这,我们来看一道《剑指offer》中的题目:
例题二:
请判断下面的代码的打印结果:
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
char arr1[] = "hello world.";
char arr2[] = "hello world.";
char* pc1 = "hello world.";
char* pc2 = "hello world.";
if (arr1 == arr2)
{
printf("arr1 and arr2 are same\n");
}
else
{
printf("arr1 are arr2 are not same\n");
}
if (pc1 == pc2)
{
printf("pc1 and pc2 are same\n");
}
else
{
printf("pc1 and pc2 are not same\n");
}
return 0;
}
结果如下:
哈哈哈,猜对了吗?奥,不,答对了吗?
下面解释为啥?
当我们还没学指针是我们在函数中传数组时,我们会写以下代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include
void Print(int arr[3][3], int m, int n)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][3] = { {1,2,3},{2,3,4},{3,4,5} };
Print(arr, 3, 3);
return 0;
}
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include
void Print(int(* arr)[3], int m, int n)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d ", *((*arr+i)+j));
//*arr+i代表行的解引用
//*(()+j)代表列的解引用
}
printf("\n");
}
}
int main()
{
int arr[3][3] = { {1,2,3},{2,3,4},{3,4,5} };
Print(arr, 3, 3);
return 0;
}
六.函数指针变量
还是类比即可:
得出:函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的
那么问题来了,函数有地址吗?
试试就知道了,看代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include
void test()
{
//printf("haha\n");
}
int main()
{
test();
printf("%p\n", &test);
printf("%p\n", test);
return 0;
}
结果:
发现,确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址,当然也可以通过 &函数名 的⽅式获得函数的地址。
int (*pf) (int x, int y)
int Add(int x, int y)
{
return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
typedef 是⽤来类型重命名的,可以将复杂的类型,简单化
typedef unsigned int uint;
//将unsigned int 重命名为uint
typedef int* prt_i;
//将int*指针重命名为prt_i
但是对于数组指针和函数指针稍微有点区别:
typedef void(*Add)(int, int);
typedef int(*arr)[5];
新的类型名必须在*的右边