❤️欢迎来到我的博客❤️ |
字符指针
char*
一般使用:
int main()
{
char ch = "a";
char* pc = &ch;
return 0;
}
这里的pc就是一个字符指针变量,这种方法是让我们的字符指针指向了一个字符变量。
另一种使用方式如下:
把字符串首字符的地址赋给了一个指针。
int main()
{
const char* p = "Hello World";
return 0;
}
因为这个字符串是一个常量字符串(不能被修改)所以在char*前面加一个const会更加严谨。
指针数组
指针数组就是存放指针的数组或存放地址的数组。
存放字符指针的数组:
int main()
{
const char* arr[4] = { "abcd,qwer,asdf,zxcv" };
return 0;
}
这四个字符串的首字符的地址都被放在了指针数组arr中。
打印:
int main()
{
const char* arr[4] = { "abcd","qwer","asdf","zxcv" };
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
运行效果:
存放整形指针的数组:
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 arr4[5] = { 4,5,6,7,8 };
int* arr[4] = { arr1,arr2,arr3,arr4 };
return 0;
}
打印:
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 arr4[5] = { 4,5,6,7,8 };
int* arr[4] = { arr1,arr2,arr3,arr4 };
int i = 0;
for (i = 0; i < 4; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
运行效果:
数组指针
数组指针的定义
数组指针也是指针。
字符指针 - 存放字符地址的指针 - 指向字符的指针 char*
整形指针 - 存放整形地址的指针 - 指向整形的指针 int*
浮点型指针 - 指向浮点型的指针 float* double*
数组指针 - 存放数组地址的指针 - 指向数组的指针
数组指针的写法:
int arr[10];
int (*pa)[10] = &arr;
这里的“pa”就是一个数组指针
pa和 * 号结合,他是个指针,他指向了“[10]”(10个元素的数组),数组的每个元素的类型是" int "
&arr取出的是数组的地址,只有数组的地址才需要数组来接收
&数组名和数组名的区别
先来看一段代码:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n", arr + 1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0] + 1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
return 0;
}
运行效果:
可以看到前面两种写法+1都只跳过了4个字节,证明他们的类型都是“ int* ",而最后一种写法跳过了40个字节(整个数组)证明他的类型是 int(*)[10],那么我们就能理解他们之间的区别了。
数组名 - 数组首元素的地址
&数组名 - 是数组的地址
数组首元素的地址和数组的地址从值的角度来看是一样的,但是意义不一样。
如果我们想拿到整个数组的地址我们就可以用 &数组名,如果只想拿到 数组首元素的地址 就可以用数组名。
在一维数组中很少使用数组指针,在二维数组中才可能使用。
数组指针的使用
void print1(int(*p)[4],int r,int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%d ", (*(p + i))[j]);//或printf("%d ", p[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][4] = { {1,2,3,4},{2,3,4,5},{6,7,8,9} };
print1(arr, 3, 4);
return 0;
}
数组名表示首元素的地址,对于二维数组来说,他的第1行就是他的第一个元素,第一行的地址,相当于是一个一维数组的地址。
那么我们就可以放到一个数组指针里( int(*p)[4] )。
数组参数和指针参数
函数的参数应该如何设计呢?
一维数组传参
一维数组传参的时候形参该如何写?
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int* arr)
{}
void test2(int* arr[20])
{}
void test2(int** arr)
{}
int main()
{
int arr[10] = { 0 };
int* arr2[20] = { 0 };
test(arr);
test2(arr2);
}
以上方法均可
二维数组传参
二维数组传参的时候形参该如何写?
void test(int arr[3][5])
{}
void test(int arr[][5])
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int(*arr)[5])
{}
int main()
{
int arr[3][5] = { 0 };
test(arr);
}
以上方法均可
一级指针传参
指针变量传参,指针变量接收
#include <stdio.h>
void print(int *p, int sz)
{
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d\n", *(p+i));
}
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
void test(int* p)
{}
int main()
{
int a = 10;
int* p = &a;
int arr[10];
test(p);//可以传一级指针
test(arr);//可以传一维数组的数组名
test(&a);//可以传整型变量的地址
return 0;
}
二级指针传参
void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int* p = &n;
int** pp = &p;
test(pp);
test(&p);
return 0;
}
二级指针传参,形参部分用二级指针接收。
当函数的参数为二级指针的时候,可以接收什么参数?
void test(int** p)
{}
int main()
{
int** ptr;
int* pp;
int* arr[10];
test(ptr);//可以传二级指针变量
test(&pp);//可以传一级指针变量的地址
test(arr);//可以传指针数组的数组名
return 0;
}
函数指针
前面我们讲到了数组指针:指向数组的指针。
inr arr[10];
int (*p) [10] = &arr;
那么函数指针是什么呢?其实就是指向函数的指针
其实函数也是有地址的,我们来看下面这条代码:
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("%p\n", &Add);
return 0;
}
运行效果:
可以看到,我们把Add函数的地址打印了出来。
那么函数指针应该怎么写呢?很简单,我们看下面这条代码:
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int,int) = &Add;
//pf是一个存放函数地址的指针变量 — 函数指针
return 0;
}
函数指针的写法和数组指针的写法非常相似。
首先pf是个指针,pf指向的是函数,函数的参数类型是(int int),pf指向的函数的返回类型是int,这样我们的pf就定义好了。
&函数名和函数名都是函数的地址
所以我们也可以这样写:
int (*pf)(int, int) = Add;
那我们能不能通过pf指针来调用Add函数呢?
可以。方法也很简单:
int (*pf)(int, int) = Add;
int ret = (*pf)(2, 3);//或int ret = pf(2,3);
printf("%d\n", ret);
运行效果:
首先pf是个指针,指针解引用才能找到对应的函数(可以省略为pf,但方便理解我们还是写上:(*pf),调用的时候要传参,那我们就传个2和3:(*pf)(2,3),传过去之后函数计算完结果,那我们就把结果放在ret里面:int ret = (*pf)(2,3);
函数指针数组
想要写出函数指针数组,要从函数指针的基础上进行改造。
int (*pf)(int,int) = &Add;//函数指针
int (*pfA[5])(int,int) ={&Add};//函数指针数组
那么函数指针数组有什么作用呢?
我们来用函数指针数组写一个简易的计算器。
简易计算器
#include<stdio.h>
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 (*pf[5])(int, int) = { 0,Add,Sub,Mul,Div };
//输入1对应Add,输入2对应Sub
//输入3对应Mul,输入4对应Div
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();
printf("请选择->");
scanf("%d", &input);
if (input == 0)
{
printf("退出计算器\n");
break;
}
else if (input >= 1 && input <= 4)
{
printf("请输入两个操作数\n");
scanf("%d %d", &x, &y);
ret = pf[input](x, y);//通过输入数调用函数
printf("%d\n", ret);
}
else
{
printf("选择错误,请重新选择\n");
}
} while (input);
return 0;
}
这里的函数指针数组代替了switch函数,简化了很多代码,但是他也有缺点:因为函数指针数组限制了他(函数里的参数类型、返回类型必须一致),所以他只能计算双目操作数。
指向函数指针数组的指针
建议在函数指针数组的基础上进行修改。
我们先来看一下函数指针数组:
int (*pf[5])(int, int);
这里的pf和[]结合说明他是一个数组,但是我们希望他是指针,那我们就在这个基础上进行修改:
int (*pf[5])(int, int);//函数指针数组
int (*(*ppf)[5])(int, int) = &pf;//ppf - 指向函数指针数组的指针
我们只需要加上*然后再把ppf括起来,这时候ppf就是一个指针了。
以上就是本篇的全部内容了,希望大家看完能有所收获。
❤️ 创作不易,点个赞吧~❤️ |