一、二维数组和指针![](https://img-blog.csdnimg.cn/782b47ceb2fd44a095ec3290a9ccbc81.png)
1.1数组指针
由于一级指针存不了二维数组的地址,于是有了数组指针,本质上是个指针
值:arr[i][j]-->*(*(arr+i)+j)-->*(*(&arr[0]+i)+j)-->*(arr[i]+j)
:p[i][j]-->*(*(p+i)+j)-->*(*(&p[0]+i)+j)-->*(p[i]+j)
地址:&arr[i][j]-->*(arr+i)+j-->*(&arr[0]+i)+j-->arr[i]+j
:&p[i][j]-->*(p+i)+j-->*(&p[0]+i)+j-->p[i]+j
练习:打印二维数组中所有数据及地址
#include<stdio.h>
int main() {
int arr[2][3] = { 1,2,3,4,5 };
int (*p)[3]= arr;
int len= sizeof(arr) / sizeof(arr[0]);
printf("%d\n",len);
for (int i = 0; i < len;i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
for (int j = 0; j < len; j++) {
for (int i = 0; i < 3; i++) {
printf("%p ", *(p + i) + j);
}
printf("\n");
}
}
1.2指针数组
练习 :遍历指针数组
#include <stdio.h>
int main() {
int a[3] = { 1,2,3 }, b[3] = { 1 ,59,6 }, c[5] = { 0 };
int* p[3] = { a,b,c };
int sizes[3] = { 3, 3, 5 }; // 数组的大小
// 外层循环遍历指针数组
for (int i = 0; i < 3; i++) {
// 内层循环遍历每个数组
for (int j = 0; j < sizes[i]; j++) {
printf("Array %d, Element %d = %d\n", i + 1, j + 1, p[i][j]);
}
}
return 0;
}
1.3字符指针数组![](https://img-blog.csdnimg.cn/74875a03725c4fcc9db18d6c6cb71efc.png)
1> 字符指针数组存储多个字符数组的地址
char str1[]="ASDF",str2[]="abcde",str3[]="12",str4[]="!@#";
char *p[]={str1,str2,str3,str4};
//
printf("%s\t",str1);
*(*p+1)='s';//可以发生更改
int len=sizeof(p)/sizeof(p[0]);
for(int i=0;i<len;i++)
{
printf("%s\n",*(p+i));
}
2> 字符指针数组存储多个字符串常量的地址
char *q[]={"ASDF","abcde","12","!@#"};
// *(*q+1)='s';段错误
len=sizeof(q)/sizeof(q[0]);
for(int i=0;i<len;i++)
{
printf("%s\n",*(q+i));
}
1.4指针函数![](https://img-blog.csdnimg.cn/fe797e819ac94e3cb7ba99a3cf3edb7f.png)
实现strcpy函数
#include<stdio.h>
char *my_strcpy(char *dest, const char *src) {
char* ret = dest;
while (*dest++ = *src++);
return ret;
}
int main() {
char a[]= "hello";
char b[]= "world";
printf("%s\n",my_strcpy(a, b));
}
1.5函数指针
示例:
#include<stdio.h>
int my_add(int x,int y) {
return x + y;
}
int my_sub(int x,int y) {
return x - y;
}
int main() {
int m=20;
int n=10;
printf("my_add(m,n)=%d\n",my_add(m,n));
printf("my_sub(m,n)=%d\n",my_sub(m,n));
//定义函数指针的格式
// 返回值类型 (*函数指针名)(函数的形参列表)
int (*p1)(int,int)=my_add;//函数名就是函数的地址
int (*p2)(int,int)=my_sub;
//定义了一个函数指针 可以指向返回值为int类型,形参列表为(int,int)类型的函数
//当函数指针指向了一个函数之后,可以通过函数指针来调用函数
printf("p1(m,n)=%d\n", p1(m, n));//30
printf("p2(m,n)=%d\n", p2(m, n));//10
return 0;
}
而函数指针也多用于回调函数当中:
#include<stdio.h>
int my_add(int x,int y) {
return x + y;
}
int my_sub(int x,int y) {
return x - y;
}
int jisuan(int x,int y,int (*p)(int,int)) {
//函数内部通过指针调用函数时,具体调用哪个函数
//取决于 用户在调用jisuan函数时,传递的第三个参数
//传什么函数,就调用什么函数 所以叫做回调函数
return p(x, y);
}
int main() {
int m=20;
int n=10;
int ret1 = jisuan(m, n, my_add);
printf("ret1 = %d\n", ret1);//30
int ret2 = jisuan(m, n, my_sub);
printf("ret2 = %d\n", ret2);//10
return 0;
}
1.6函数指针数组
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int add(int a,int b)//100 10
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
int mul(int a,int b)
{
return a*b;
}
int divs(int a,int b)
{
return a/b;
}
int main(int argc, const char *argv[])
{
int a=100,b=10;
//需要使用4个函数指针
int (*p1)(int,int)=add;
int (*p2)(int,int)=sub;
int (*p3)(int,int)=mul;
int (*p4)(int,int)=divs;
int (*p[4])(int,int)={add,sub,mul,divs};
for(int i=0;i<4;i++)
{
int s=(*(p+i))(a,b);
printf("s=%d\n",s);
}
return 0;
}
1.7 多级指针
一级指针存储变量的地址
二级指针存储一级指针的地址
三级指针存储二级指针的地址
1.8通用类型指针
通用类型指针,可以指向任意一种类型的指针,可以指向任意一块地址,但是在使用时,必须进行类型强转。
格式: void *指针变量名
一般用来传参时使用,c基础阶段用得比较少