内容小复习:
字符指针:存放字符的数组
char arr1[10];
整型数组:存放整型的数组
int arr2[5];
指针数组:存放的是指针的数组
存放字符指针的数组(字符指针数组)
char* arr3[5];
存放整型指针的数组(整型指针数组)
int* arr[6];
下面进入学习了哦~
文章目录
- 前言
- 一、字符指针
- 面试题讲解
- 二、指针数组
- 1.字符指针数组
- 2.整型指针数组
- 三、数组指针
- **1.整型指针**:指向整型的指针
- **2.字符指针**:指向字符的指针
- **3.数组指针**:指向数组的指针
- **4.注意区分:arr 和&arr**
- 5.访问数组的三种形式
- (1)下标访问
- (2)指针访问
- (3)数组指针访问(不推荐)
- 6.数组传参
- (1)一维数组传参,形参写成数组或者指针的形式
- I.写成数组的形式
- II. 写成指针的形式
- (2)二维数组传参
- I.形式参数写成数组的形式
- II.形式参数写成指针的形式
- 7.分析代码
- (1)
- (2)
- (3)
- 四、数组参数、指针参数
- 1.一维数组传参
- 以下test的写法可行吗” />
注意:
在有一些编译器中下面的代码会报错,因为”abcdef”是常量字符串,本质上不能修改,将这个字符串交给p是很危险的,char p 没有保护起来,所以通过p万一去修改a,在运行的时候就会出错.char* p="abcdef";*p='w';
解决办法:
加上const,意思是const修饰的是p,限制了p,
此时*p不能被修改const char* p="abcdef";
所以即使是在vs2019中可以运行,但最好也在前面加上const
面试题讲解
#include int main(){char str1[] = "hello world.";char str2[] = "hello world.";const char* str3 = "hello world.";const char* str4 = "hello world.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;}
分析:
拿”hello world.”分别初始化一个数组,是必然都会创建的.创建两个数组在内存中的位置一定是有区别的.所以str1和str2不相等
对于const 修饰的常量字符串,不能被改,没有必要存两份,所以str3和str4里面存的是一样的
该题拓展:
下面的代码相等吗” />二、指针数组
指针数组:存放的是指针的数组
存放字符指针的数组(字符指针数组)
char* arr3[5];
存放整型指针的数组(整型指针数组)
int* arr[6];1.字符指针数组
int main() {char* arr[] = { "abcdef","hehe","qwer" };for (i = 0; i< 3; i++) {printf("%s\n", arr[i]);}return 0;}
2.整型指针数组
int main() {int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//数组首元素地址是整型地址//arr是一个存放整型指针的数组int* arr[] = { arr1,arr2,arr3 };int i = 0;for (i = 0; i < 3; i++) {//arr[i]拿到的是arr1/arr2/arr3的地址//加上一个j再解引用就可以拿到里面的各个元素int j = 0;for (j = 0; j < 5; j++) {//arr[i][j]也可以写成arr[i]+jprintf("%d ", arr[i][j]);//printf("%d ", *(arr[i] + j));}printf("\n");}return 0;}
三、数组指针
类比上面的定义:
1.整型指针:指向整型的指针
int a = 20;int* p = &a;
2.字符指针:指向字符的指针
char ch = 'w';char* pc = &ch;
3.数组指针:指向数组的指针
数组名是首元素的地址,有两个例外:
一是sizeof内部单独放一个数组名
另一个是取地址数组名,这个取出的是数组的地址int arr[10];
&arr; //取出的是数组的地址
pa说明pa是指针,当去掉pa时剩下int [10],说明pa指向的是数组int arr[10];int(*pa)[10] = &arr;
char arr2[10];char(*pc)[10] = &arr2;
4.注意区分:arr 和&arr
绝大多数情况下,数组名是数组首元素的地址
但是有两个例外:
1.sizeof(数组名) sizeof内部单独放一个数组名的时候,数组名表示整个数组,计算得到的是数组的总大小
2.&arr 这里的数组名表示整个数组,取出的是整个数组的地址,从地址值的角度来讲和数组首元素的地址一样,但是意义不一样int main() {int arr[10] = { 0 };printf("%p\n", arr);printf("%p\n", &arr[0]);printf("%p\n", &arr);return 0;}
int main() {int arr[10] = { 0 };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;}
printf(“%p\n”, arr);
printf(“%p\n”, arr+1);
数组名+1,数组名的类型是int*,int类型的指针+1之后跳过的是4个字节
printf(“%p\n”, &arr[0]);
printf(“%p\n”, &arr[0]+1);
&arr[0]的类型也是int,int*类型的指针+1之后跳过的是4个字节
printf(“%p\n”, &arr);
printf(“%p\n”, &arr+1);
&arr的类型是指向数组的指针,它的类型是int( * )[10],+1的时候跳过整个数组的长度5.访问数组的三种形式
(1)下标访问
(2)指针访问
(3)数组指针访问(不推荐)
int main() {int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);//使用指针来访问int* p = arr;for (i = 0; i < sz; i++) {printf("%d ", *(p + i));}//下标访问的形式访问数组for (i = 0; i < sz; i++) {printf("%d ", arr[i]);}//取出整个数组的地址,与上面访问数组的结果相同,但是不易于理解,不推荐int(*pa)[10] = &arr; //pa相当于&arr *pa相当于*&arr也就是*pa=arr for (i = 0; i < sz; i++) {printf("%d ", *((*pa) + i));//*pa是首元素的地址//printf("%d ", (*pa)[i]);与上面等同}}
6.数组传参
(1)一维数组传参,形参写成数组或者指针的形式
I.写成数组的形式
void print(int arr[10],int sz){int i = 0;for (i = 0; i < sz; i++) {printf("%d ", arr[i]);}printf("\n");}int main() {int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);}
II. 写成指针的形式
void print(int *arr, int sz) {int i = 0;for (i = 0; i < sz; i++) {printf("%d ", arr[i]);}printf("\n");}int main() {int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);}
(2)二维数组传参
I.形式参数写成数组的形式
void print(int arr[3][5],int r,int c) {int i = 0;for (i = 0; i < 3; i++) {int j = 0;for (j = 0; j < 5; j++) {printf("%d ", arr[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 };//封装一个函数打印二维数组//需要传数组,行和列print(arr, 3,5);return 0;}
II.形式参数写成指针的形式
二维数组的数组名也表示首元素的地址.
二维数组其实是一维数组的数组.
每一行都是一个元素
二维数组的首元素是” />//二维数组传参,形式参数用指针表示void print(int (*arr)[5], int r, int c) {int i = 0;for (i = 0; ![在这里插入图片描述](https://img-blog.csdnimg.cn/d69157ed8d1c428ea0d1a878b4d476c0.png)i < 3; i++) {int j = 0;for (j = 0; j < 5; j++) {//printf("%d ", *(*(arr+i)+j)); //等价于下一行的写法printf("%d ",arr[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 };//封装一个函数打印二维数组//需要传数组,行和列print(arr, 3, 5);return 0;}
注意:7.分析代码
(1)
int *parr1[10];
parr1和[]结合,是数组,十个元素,每个元素是int*类型,所以它是指针数组
(2)
int(*parr2)[10];
parr2是一个指针,指向的是数组,数组十个元素每个元素是int类型,所以它是数组指针
(3)
int(*parr3[10])[5];
parr3首先和[]结合是数组,数组名和数组个数parr3[10]除外,剩下的就是数组元素的类型int( * )[5],int( * )[5]说明是指针,指针指向的是5个元素的数组,每个元素的类型是int
parr3是数组,数组中存放指针,该指针又指向数组
可以理解为指针数组存放的是数组指针四、数组参数、指针参数
1.一维数组传参
int main() {int arr1[10] = { 0 };int *arr2[20] = { 0 };test(arr1);test2(arr2);}
以下test的写法可行吗” />
2.函数指针变量用来存放函数的地址
pf是函数指针的名字,去掉它是函数指针的类型,不需要交代形参的名字
int Add(int x, int y) {return x + y;}int main() {int (*pf)(int,int) = Add;//pf是函数指针的名字,去掉它是函数指针的类型,不需要交代形参的名字return 0;}
3.通过函数指针调用它指向的函数
int Add(int x, int y) {return x + y;}int main() {int (*pf)(int,int) = Add;//pf是函数指针的名字,去掉它是函数指针的类型,不需要交代形参的名字int ret = (*pf)(3, 5); //调用printf("%d\n", ret);return 0;}
pf是函数指针的名字,去掉它是函数指针的类型.把Add放到pf里边,Add和pf就是一回事总结:
(1)函数指针调用:
int ret = (*pf)(3, 5);
在看完下面的(2)(3)之后发现这里的*其实就是一个摆设,那为什么既然是一个摆设,还能用呢” />
知识点练习
写一个计算器能完成整数的±*/
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 input = 0;int x = 0;int y = 0;int ret = 0;do {menu();printf("请选择->");scanf("%d", &input);//只有输入1234的时候才需要打印结果//为了避免无关紧要的一些结果的输出switch (input) {case 1:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Add(x, y);printf("%d\n", ret);break;case 2:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("%d\n", ret);break;case 3:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("%d\n", ret);break;case 4:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Div(x, y);printf("%d\n", ret);break;case 0:printf("退出计算器\n");break;default:printf("选择错误\n");break;}}while (input);return 0;}
在计算机基础上, 增加一些其他的功能:>> << & | ^ && ||
一直case下去代码太长了,有没有简化的方法” />
注意点:
总结
指针进阶的上部分内容就到这里啦,如果对友友们有帮助的话,记得点赞收藏博客,关注后续的指针进阶下集内容哦~
- 以下test的写法可行吗” />