指针2
1.数组名的理解
int arr[ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };int *p = &arr[ 0 ];17391692786
arr是数组名,数组名是首元素地址,&arr[0]就是取出首元素的地址放在指针变量p中。
#include <stdio.h>
int main()
{int arr[2][10] = { 1,2,3,4,5,6,7,8,9,10 };//一行为10个元素,一共两行;//printf("&arr[0] = %p\n", &arr[0]);//printf("arr = %p\n", arr);printf("%p\n", &arr[0]);//arr[0]是第一行一维数组的数组名,&数组名,打印第一行数组的地址(十六进制) printf("%p\n", arr[0]);//arr[0]是第一行的数组名,数组名是首元素的地址,打印第一行数组第一个元素的地址printf("%p\n", *arr);//arr是二维数组的数组名,*arr代表取出二维数组的首元素 这个二维数组由两个一维数组组成,即*arr代表arr[0],*arr==*(arr+0)==arr[0]printf("%d\n", *arr);//地址打印为十进制printf("==============\n");printf("%p\n", &arr[1]); //arr[1]是第二行一维数组的数组名,&数组名,打印第二行数组的地址printf("%p\n", arr[1]);//arr[1]是第二行的数组名,数组名是首元素的地址,打印第二行数组第一个元素的地址printf("%p\n", *(arr + 1));//arr是二维数组的数组名,arr + 1代表访问第二行元素,*(arr + 1)获取第二行元素数组的地址 *(arr + 1)==arr[1]printf("%d\n", *(arr + 1));//地址打印为十进制printf("==============\n");printf("%p\n", *(arr + 1)+1);//*(arr + 1)获取第二行元素数组的地址 *(arr + 1)+1获取第二行第二个元素的地址printf("%p\n", &arr[1][1]);//获取第二行第二个元素的地址printf("==============\n");printf("%d\n", sizeof(arr));//特例:sizeof(数组名)表示计算arr数组的大小(数组空间内存)printf("%d\n", sizeof(arr[0]));//特例:sizeof(数组名)表示计算arr数组的大小(数组空间内存) arr[0]是第一行一维数组的数组名printf("%d\n", sizeof(arr[1]));//特例:sizeof(数组名)表示计算arr数组的大小(数组空间内存) arr[1]是第二行一维数组的数组名printf("%p\n", &arr);//特例:&数字名 表示整个二位数组的地址printf("==============\n");printf("%p\n", &arr[0] + 1);//&arr[0]获取第一行数组的地址 &arr[0] + 1获取第二行数组的地址printf("%p\n", &arr + 1);//&arr获取二维数组的地址 &arr+ 1 跳过此二维数组到下一个地方(跳过20*4=80Byte)return 0;
}
其实数组名就是数组⾸元素(第⼀个元素)的地址是对的,但是有两个例外:
#include < stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}
//运行结果可以发现 sz1=10,sz2=1;
为什么这个函数的结果不对呢?
这就要搞清楚函数中传的参数是啥,也就是函数中传的参数是啥,从上方代码可test(arr);arr是一个一维数组,也是个数组名,刚从1.数组名的理解知道除了两个例外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。所以说传给函数test是数组的地址,那么sizeof(地址)=4或8(要看在32位系统还是64位系统),int sz2 = sizeof(arr) / sizeof(arr[0]);这个arr和arr[0]都是地址,所以sz2=1;
再看一个:
void test1(int arr[])//参数写成数组形式,本质上还是指针
{printf("%d\n", sizeof(arr));
}
void test2(int* arr)//参数写成指针形式
{printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };test1(arr);test2(arr);return 0;
}
//运行结果可以发现 sizeof(arr)=4;说明一维数组传参传的就是地址
int main()
{int a = 100;int* pa = &a;int** pb = &pa;printf("a的地址是:%p\n", pa);printf("pa的地址是:%p", pb);return 0;
}
画个图描述一下
字符数组:存放字符的数组char arr1[5]={'a','b','c','d','e'} 5个char类型 那么指针数组就是存放指针的数组呗, 那就有整形指针数组,字符指针数组等等; int* arr1[5]={指针1,指针2,指针3,指针4,指针5} 5个 int* 类型
指针数组的每个元素都是⽤来存放地址(指针)的,⼜可以指向⼀块区域。用以下代码说一下指针数组。
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;}
#include <stdio.h>//整形数组指针
//int arr[10] = {0};
//&arr;//得到的就是数组的地址
//找个变量来接收找个数组地址 → int(*p)[10]=&arr
// int (*p) [10] = &arr;
// | | |
// | | |
// | | p指向数组的元素个数
// | p是数组指针变量名
// p指向的数组的元素类型int main()
{int arr[5] = { 1, 2, 3, 4, 5 }; // 定义一个整形数组int(*p)[5]; // 定义一个指向包含5个整形元素的数组的指针p = &arr; // 将指针指向数组//int(*p)[5]=&arr;// 通过指针访问数组中的元素for (int i = 0; i < 5; i++){//printf("arr[%d] = %d\n", i, (*p)[i]);printf("arr[%d] = %d\n", i, p[0][i]);}return 0;
}//字符数组指针
int main1()
{char str[20] = "Hello, world!"; // 定义一个字符数组char(*p)[20]; // 定义一个指向包含20个字符的数组的指针p = &str; // 将指针指向数组// 通过指针访问数组中的元素printf("String: %s\n", *p);//printf("String: %p\n", p);//printf("String: %p\n", *p);//printf("String: %p\n", p[0]);//printf("String: %c\n", **p);printf("String: %c\n", *p[0]);//**p== *p[0]return 0;
}
void test(int a[3][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 ", a[i][j]);}printf("\n");}
}
//这是之前的传参写法,我们知道了二维数组传参的本质,可以修改如下
void test1(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("%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);test1(arr, 3, 5);return 0;
}
7.函数指针
void test()
{printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)() = test;int Add(int x, int y)
{return x + y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//函数名就是函数的地址&Add==Add 都可以获取函数的地址,x和y写上或者省略都是可以的 int (*pf3) (int x, int y)
| | ------------
| | |
| | pf3指向函数的参数类型和个数的交代
| 函数指针变量名
pf3指向函数的返回类型int (*) (int x, int y) //pf3函数指针变量的类型
ps:函数名就是函数的地址,可以用函数名来代表函数的地址,也可以用 &函数名 来表示
#include <stdio.h>// 一个简单的函数,接收两个整数并返回它们的和
int add(int x, int y)
{return x + y;
}int main()
{// 声明一个函数指针,指向接收两个int参数并返回int的函数//int (*pf)(int, int);// 将函数指针指向具体的函数add//pf = add;int (*pf)(int, int) = add; // int (*pf)(int, int)=&add;// 使用函数指针调用函数int result = pf(10, 20);int result1 = (*pf)(10, 30); //注意一定是加上()不能是 *pf(10, 30)进行调用printf("Result: %d\n", result); // 输出:Result: 30printf("Result1: %d\n", result1); // 输出:Result: 40return 0;
}
7.函数指针数组
//转移表 (设计一个简易计算器)
#include <stdio.h>
#include <stdlib.h>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;
}
void menu()
{printf("********************************\n");printf("****** 1. add 2. sub *****\n");printf("****** 3. mul 4. diV *****\n");printf("****** 0. exit *****\n");printf("********************************\n");
}
int main()
{int input = 0;int (*pf[5])(int,int) = {0, add, sub, mul, diV};do{ menu();int x, y = 0;scanf("%d", &input);if (input > 0 && input < 5){printf("请输入操作数:");scanf("%d %d", &x, &y);int ret = pf[input](x, y);printf("%d\n", ret);}else if (input == 0){printf("退出计算器");}else{printf("输入错误,重新输入\n");}} while(input);return 0;
}