目录
本篇介绍:
- 字符指针
- 数组指针
- 指针数组
- 数组传参和指针传参
- 函数指针
- 函数指针数组
一、字符指针
int main()
{
//1.
char ch = 'w';
char* pc = &ch;
*pc = 'w';
printf("%c\n", *pc);
//2.
const char* pstr = "hello bit";//本质上是把字符串hello bit的首字符的地址放到了pstr中。
printf("%s\n", pstr);
return 0;
}
上面的str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当 几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同。
二、指针数组
指针数组就是一个存放指针类型的数组。
int main()
{
int* arr[10];//存放整型指针的数组
char* arr2[10];//存放字符型指针的数组
char** arr3[10];//存放二级字符指针的数组
return 0;
}
三、数组指针
数组指针存放的是数组的地址
3.1数组指针的定义
int main()
{
int(*p)[10];//数组指针
//p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组。
//所以p是一个指针,指向一个数组,所以叫数组指针
//注意:[] 的优先级要高于 * ,所以先加上 () 来保证p先和*结合
return 0;
}
3.2&数组名和数组名
除了这两种情况:sizeof(arr)和 &arr, 其他地方的数组名都是数组首元素的地址。
sizeof(arr)求的是整个数组的大小;
&arr 求的是整个数组的地址,它的类型是int(*)[10], 是一种数组指针类型,数组的地址+1,跳过整个数组的大小,所以&arr+1相对于&arr的差值是40
3.3数组指针的使用
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*pa)[10] = &arr;//数组指针
return 0;
}
//数组指针的使用
void print1_arr(int arr[3][5], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print2_arr(int(*arr)[5], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", *(*(arr + i) + j));
//printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
//print1_arr(arr, 3, 5);
print2_arr(arr, 3, 5);
return 0;
}
看一下以下几行代码:
int main()
{
int arr[5];//数组
int* parr1[5];//指针数组
int(*parr2)[5];//数组指针
int(*parr3[10])[5];//数组指针数组——是用来存放数组指针的数组return 0;
}
四、数组传参和指针传参
4.1一维数组传参的几种方法
4.2二维数组传参的几种方法
4.3一级指针传参
//一级指针传参
void print(int* pa, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", *(pa + i));
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(pa, sz);
return 0;
}
如果以一个一级指针作为一个函数的参数,可以接收什么参数?
void test(int* p)
1.可以接收一个变量的地址
int a = 0;
test(&a);
2.可以接收一个指针变量
int* pa = &a;
test(pa);
3.可以接收一个一维数组
int arr[10];
test(arr);
4.4二级指针传参
//二级指针传参
void test(int ** pp)
{
printf("num = %d\n", **pp);
}
int main()
{
int n = 10;
int* p = &n;
int** pp = &p;
test(pp);
test(&p);
return 0;
}
如果以一个二级指针作为一个函数的参数,可以接收什么参数?
void test(int ** p)
1.可以接收一个一级指针变量的地址
int a = 10;
int* pa = &a;
test(&pa);
2.可以接收一个二级指针变量
int ** ppa = &pa;
test(ppa);
3.可以接收一个指针数组
int* arr[10];
test(arr);
五、函数指针
对于函数来说,直接写函数名或者&函数名都是这个函数的地址。
那如果我们想把test函数的地址保存下来,改如何保存呢?
保存test函数的地址需要一个函数指针——因为保存一个地址需要指针变量,又因为保存函数类型的地址,所以使用函数类型的指针;
一个函数,除了函数名以外,其他的全是函数的类型
因为 * 的优先级比 () 函数调用操作符的优先级低,所以需要与变量名加上括号,以保证它是一个指针变量。
下面我们来分析两段代码的意思:
六、函数指针数组
函数指针数组的定义:
函数指针数组的用途——转移表
//用函数指针数组来实现一个计算器
void menu()
{
printf("***********************************\n");
printf("********* 1.add 2.sub *********\n");
printf("********* 3.mul 4.div *********\n");
printf("********* 0.exit *********\n");
printf("***********************************\n");
}
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
int main()
{
int x = 0, y = 0;
int input = 0;
int ret = 0;
//函数指针数组
int(*pfun[5])(int, int) = { NULL, add, sub, mul, div };
do
{
menu();
printf("请输入选项:>");
scanf("%d", &input);
if (input <= 4 && input >= 1)
{
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = pfun[input](x, y);
printf("%d\n", ret);
}
else
{
if (input == 0)
printf("退出程序\n");
else
printf("输入错误\n");
}
} while (input);
return 0;
}