内容小复习:
字符指针:存放字符的数组
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下去代码太长了,有没有简化的方法” />
        注意点:


        总结

        指针进阶的上部分内容就到这里啦,如果对友友们有帮助的话,记得点赞收藏博客,关注后续的指针进阶下集内容哦~