• 深入理解指针:【探索指针的高级概念和应用一】


    目录

    前言:

    1. 字符指针

    2. 指针数组

    3.数组指针

    3.1数组指针的定义

    3.2 &数组名VS数组名

    3.3数组指针的使用


    前言:

    🍂在了解今天的内容之前我们先复习一下指针的基本概念:

    1,内存单元是有编号的,编号就是我们所说的地址,也可以叫指针,它们是一回事。如果我们把一个指针或地址存起来的话,我们就需要一个指针变量

    2,指针变量就是个变量,用来存放地址,地址唯一标识一块空间。

    3,地址或指针的大小是固定的4/8个字节(32位平台/64位平台),也可以理解为指针变量的大小是4/8个字节。

    4,指针是有类型的,指针的类型决定了指针加减整数的步长,指针解引用操作时候的权限。


    1. 字符指针

    在指针的类型中我们知道有一种指针类型为字符指针 char* :
    🍂一般使用:

    1. #include
    2. int main()
    3. {
    4. char ch = 'w';
    5. //取出的变量ch的地址是char类型的变量,
    6. //就可以把它放在char* 类型的指针里边去
    7. char* pc = &ch;
    8. return 0;
    9. }

    🍂还有一种使用方式如下:

    1. #include
    2. int main()
    3. {
    4. //这个字符串作为一个表达式的时候它的值是首字符的地址,指向字符串的本质是指向了第一个字符,
    5. //但因为字符串在内存中是连续存放的,也可以认为是指向了一个字符串
    6. //加const是为了防止有人通过*p修改字符串常量里边的内容
    7. const char* p = "abcdef";
    8. printf("%s\n", p);
    9. //如果对这个指针解引用,因为它是char*类型,解引用只拿到一个字符,所以格式控制符应该用“%c”
    10. printf("%c\n", *p);
    11. return 0;
    12. }

     🍂下面我们来看一道面试题:

    1. #include
    2. int main()
    3. {
    4. char str1[] = "hello bit.";
    5. char str2[] = "hello bit.";
    6. const char* str3 = "hello bit.";
    7. const char* str4 = "hello bit.";
    8. if (str1 == str2)
    9. printf("str1 and str2 are same\n");
    10. else
    11. printf("str1 and str2 are not same\n");
    12. if (str3 == str4)
    13. printf("str3 and str4 are same\n");
    14. else
    15. printf("str3 and str4 are not same\n");
    16. return 0;
    17. }

    🍂这里最终输出的是: 

    🎈分析: 

     如上图所示,st1数组和str2数组是两块独立的空间,它们的起始地址肯定不相同,所以打印的结果为不同;“hello bit”是一个常量字符串,它不能被修改,而对于常量字符串来说,它的内容一样的时候,只会保存一份,不会保存多份,当这个字符串把首字符的地址交给str3的时候,str3就是一个指针变量,里边存的是'h'的地址,同理,str4指针变量里边存放的也是'h'的地址,所以,str3和str4打印结果相同。


    2. 指针数组

    在刚接触指针的时候我们就说过指针数组是数组。那该怎么理解它呢?

    🎈我们说:

    字符数组是存放字符的数组;

    整型数组是存放整形的数组;

    那指针数组就是存放指针的数组,即存放在数组中的元素都是指针类型的。

    🎈例:

    1. int* arr[5];//存放整形指针的数组
    2. char* ch[6];//存放字符指针的数组

     🍂下面我们使用指针数组模拟一个二维数组:

    1. #include
    2. int main()
    3. {
    4. int arr1[] = { 1,2,3,4,5 };
    5. int arr2[] = { 2,3,4,5,6 };
    6. int arr3[] = { 3,4,5,6,7 };
    7. //指针数组
    8. int* arr[] = { arr1,arr2,arr3 };
    9. int i = 0;
    10. for (i = 0; i < 3; i++)
    11. {
    12. int j = 0;
    13. for (j = 0; j < 5; j++)//打印一行的元素
    14. {
    15. printf("%d ", arr[i][j]);
    16. }
    17. printf("\n");
    18. }
    19. return 0;
    20. }

     🍇运行结果:


    3.数组指针

    3.1数组指针的定义

    数组指针是指针?还是数组?

    答案是指针。

    • 我们知道字符指针是指向字符的指针;
    • 整形指针是指向整形的指针;
    • 浮点型指针是指向浮点型的指针;
    • 那数组指针就是指向数组的指针!

    3.2 &数组名VS数组名

    🎈对于下面的数组:

    int arr[10];

    arr 和 &arr 分别是啥?我们知道arr是数组名,数组名表示数组首元素的地址。那&arr数组名到底是啥?我们看一段代码:

    1. #include
    2. int main()
    3. {
    4. int arr[10];
    5. printf("%p\n", arr);
    6. printf("%p\n", &arr);
    7. return 0;
    8. }

    🍂运行结果如下: 

    可见数组名和&数组名打印的地址是一样的,难道两个是一样的吗?我们再看一段代码:

    1. #include
    2. int main()
    3. {
    4. int arr[10] = { 0 };
    5. printf("arr = %p\n", arr);
    6. printf("arr+1 = %p\n", arr + 1);
    7. printf("&arr= %p\n", &arr);
    8. printf("&arr+1= %p\n", &arr + 1);
    9. return 0;
    10. }

    🍂运行结果如下: 

    1. 根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。
    2. 实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。
    3. 本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型。
    4. 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。

    3.3数组指针的使用

     那数组指针是怎么使用的呢?

    既然数组指针指向的是数组,那数组指针中存放的应该是数组的地址,看代码:

    1. #include
    2. int main()
    3. {
    4. int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    5. int(*p)[10] = &arr;//把数组arr的地址赋给数组指针变量p
    6. int i = 0;
    7. for (i = 0; i < 10; i++)
    8. {
    9. //因为p里边存放的是&arr,对它解引用,
    10. //就相当于拿到了数组名(取地址和解引用可以互相抵消),
    11. //这时候访问数组里边每个元素的时候还得用下标(*p)[i],就会显得多此一举
    12. //所以我们一般很少这样写代码
    13. (*p) == (*&arr) == (arr);
    14. }
    15. //正确写法
    16. int* p = arr;
    17. int i = 0;
    18. for (i = 0; i < 10; i++)
    19. {
    20. printf("%d ", p[i]);
    21. }
    22. return 0;
    23. }

    🍂数组指针的使用: 

    1. #include
    2. void print_arr1(int arr[3][5], int x, int y)//形参也是使用二维数组的形式
    3. {
    4. int i = 0;
    5. for (i = 0; i < 3; i++)
    6. {
    7. int j = 0;
    8. for (j = 0; j < 5; j++)
    9. {
    10. printf("%d ", arr[i][j]);
    11. }
    12. printf("\n");
    13. }
    14. }
    15. void print_arr2(int (*arr)[5], int x, int y)//形参的部分使用的是指针
    16. {
    17. int i = 0;
    18. for (i = 0; i < 3; i++)
    19. {
    20. int j = 0;
    21. for (j = 0; j < 5; j++)
    22. {
    23. printf("%d ", arr[i][j]);
    24. }
    25. printf("\n");
    26. }
    27. }
    28. int main()
    29. {
    30. int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };
    31. print_arr1(arr, 3, 5);//二维数组传参
    32. //数组名arr,表示首元素的地址
    33. //但是二维数组的首元素是二维数组的第一行
    34. //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    35. //可以数组指针来接收
    36. print_arr2(arr, 3, 5);//二维数组传参
    37. return 0;
    38. }


     


    🍂下面我们再来分析一组代码:

    int arr[5];

    arr是一个数组,数组有5个元素,每个元素是整形类型,所以arr是一个能够存放5个整形数据的数组 

    int* parr1[10];

    parr1是一个数组,数组有10个元素,每个元素的类型是int*类型 

    int(*parr2)[10];

    parr2是一个数组指针,该指针是指向数组的,指向的数组有10个元素,每个元素的类型是int 类型

    int(*parr3[10])[5];

    parr3是一个数组,是存放数组指针的数组,数组有10个元素;存放的这个数组指针,指向的数组有5个元素,每个元素是int类型 

  • 相关阅读:
    mingw-gcc编译窗体和console
    BIO、NIO、AIO
    机器学习与图像识别(二)—— OpenCV环境折腾。。
    nvidia-smi出现Failed to initialize NVML: Driver/library version mismatch
    六、python Django REST framework[认证、权限、限流]
    怎么快速入门一种编程语言
    Kali中安装和使用docker的学习笔记
    【youcans动手学模型】目标检测之 SPPNet 模型
    windows 11+docker desktop+grafana+influxDB
    Vue-Electron初始化项目及打包
  • 原文地址:https://blog.csdn.net/weixin_65931202/article/details/133998083