• C语言---------深入理解指针


    目录

    一、字符指针

    二、指针数组:

    三、数组指针:

    1、定义:

    2、&数组名和数组名区别:

    3、数组指针的使用:

    四、数组参数,指针参数:

    1、一维数组传参:

    2、二维数组传参:

    3、一级指针传参:

    4、二级指针传参:

    五、函数指针:

    1、定义:

    2、函数名和&函数名:

    3、函数指针的调用:

    六、函数指针数组:

    七、指向函数指针数组的指针


    一、字符指针

    定义:字符指针就是指向一个字符串的指针。指针类型为char*

    1. int main()
    2. {
    3. char c = 'z';
    4. char* pc = &c;
    5. printf("%c\n", c);
    6. return 0;
    7. }

    或者:

    1. int main()
    2. {
    3. const char* pc = "abcdef";
    4. printf("%s\n", pc);
    5. return 0;
    6. }

    这里因为是个常量字符串,所以可以用const修饰来达到后面不会被修改的问题。

    上面const char* pc = "abcdef"这里并不是将abcdef赋给pc的指针变量里面,而是将字符串的首字符的地址放在pc中。

    接下来看一个经典题目:

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

    这串代码的意思是:

    将hello ppr.给到数组str1和str2中,判断二者是否相等。

    将hello ppr.的地址给到str3和str4中,判断二者是否相等。

    那么为什么会出现这样的结果呢?

    对于str1和str2,这两个是开辟了两块不同的空间,比较数组名就是比较首元素的地址,毕竟空间不同肯定比较出来就会不同。

    对于str3和str4

    首先要知道这是一个常量字符串是不能够被修改的,所以在内存就没有必要存储两份了,那么这两个字符指针就都会指向那同一块空间。

    二、指针数组:

    定义:存放指针的数组就是指针数组。

    1. int main()
    2. {
    3. int arr1[5] = { 1,2,3,4,5 };
    4. int arr2[5] = { 2,3,4,5,6 };
    5. int arr3[5] = { 3,4,5,6,7 };
    6. int arr4[5] = { 0,0,0,0,0 };
    7. int* arr[4] = {arr1,arr2,arr3,arr4};
    8. for (int i = 0; i < 4; i++)
    9. {
    10. for (int j = 0; j < 5; j++)
    11. {
    12. //printf("%d ", arr[i][j]);
    13. printf("%d ", *(*(arr + i) + j));
    14. }
    15. printf("\n");
    16. }
    17. return 0;
    18. }

    如上代码所示:

    arr先和右边的[]结合,就是一个数组,然后里面每一个元素都是int* ,这就是一个存放整形指针的数组。

    例如:

    int* arr1[10]//这是一个整形指针的数组,里面有10个元素。

    char* arr2[10]//这是一个这是一个字符指针的数组,里面有10个元素。

    char** arr3[10]这是一个二级字符指针的数组,里面有10个元素。

    三、数组指针

    1、定义:

    定义:这是一个指针,是能够指向数组的指针。

    写法:int* p1[10]       or        int (*p2)[10]

    这两种写法是哪一种呢?

    很显然是后面的,因为前一个和指针数组一样。

    因为p2和[]结合的优先级高于*,所以需要用小括号来改变其结合的优先顺序。

    2、&数组名和数组名区别:

    例如:

    对于int arr[10];

    arr和&arr分别有啥区别?

    同样从代码入手:

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

    如上图所示,如果只看arr和&arr的话,二者是相等的,但是如果对二者都进行指针运算+1后,arr跳过了增加了4,跳过了一个整型,而&arr增加了28(十六进制),换算成十进制为40,所以就是跳过了10个整型,也就是这个数组。

    故有结论:arr是这个数组的首元素的地址

                    &arr是这整个数组的地址,所以+1是跳过这个数组的大小

    3、数组指针的使用:

    数组指针大多时候是在二维数组的传参中使用的,在一维数组中的作用不大。

    依然从代码入手:

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

    如上代码所示:

    这里用了自己创建的两个打印二维数组的函数,在其中唯一不同的是形参的接收不同,在print_arr1中,用传统的二维数组来接收,而在print_arr2中,用数组指针(指向数组的指针)来接收是一样的效果。

    拓展:int (*parr[10])[5] 这是个啥?

    首先parr和[10]结合成为一个数组,所以parr是个数组,在这个数组里面有10个元素,

    其中每个元素的类型是int(*)[5]这个数组指针

    四、数组参数,指针参数:

    1、一维数组传参:

    1. #include
    2. void test(int arr[])
    3. {}
    4. void test(int arr[10])
    5. {}
    6. void test(int* arr)
    7. {}
    8. void test2(int* arr[20])
    9. {}
    10. void test2(int** arr)
    11. {}
    12. int main()
    13. {
    14. int arr[10] = { 0 };
    15. int* arr2[20] = { 0 };
    16. test(arr);
    17. test2(arr2);
    18. }

    如上代码中,所有传参均是可以的,用数组接收或者用指针接收。

    2、二维数组传参:

    3、一级指针传参:

    当一个函数的参数部分为一个一级指针的时候,函数能接收的参数有:

    1. void test(int* a)
    2. {}
    3. int main()
    4. {
    5. int a = 10;
    6. int* pa = &a;
    7. int arr[10];
    8. test(&a);
    9. test(pa);
    10. test(arr);
    11. return 0;
    12. }

    4、二级指针传参:

    当一个函数的参数部分为一个二级指针的时候,函数能接收的参数有:

    1. void test(int** a)
    2. {}
    3. int main()
    4. {
    5. int** a ;
    6. int* pa ;
    7. int* arr[10];
    8. test(a);
    9. test(&pa);
    10. test(arr);
    11. return 0;
    12. }

    五、函数指针:

    1、定义:

    类比一下:

    数组指针是指向数组的指针,函数指针就是指向函数的指针。

    (类比于数组指针)

    那么函数指针该怎么写呢?

    例如有一个函数int Add(int x,int y);

    假设我要定义一个函数指针变量名为ppr只想Add函数

    那么首先要是一个指针就需要用()来进行:(*ppr)

    然后需要是个函数里面写形参的类型就是:(*ppr)(int,int)

    最后看返回值:int (* ppr)(int,int)= &Add;        

    2、函数名和&函数名:

    函数名和&函数名在C语言中大多数情况下都是等效的,都表示函数的地址。然而,使用&可以使代码更加清晰明确。

    3、函数指针的调用:

    1. int Add(int x, int y)
    2. {
    3. return x + y;
    4. }
    5. int main()
    6. {
    7. //int (*pf)(int, int) = &Add;
    8. int (* pf)(int, int) = Add;
    9. //int ret = Add(2, 3);
    10. int ret = pf(2, 3);
    11. int ret = (*pf)(2, 3);
    12. printf("%d\n", ret);
    13. return 0;
    14. }

    如上代码所示:

    将Add赋给pf后pf就可以像Add函数一样地调用了,也可以对pf解引用后调用,语法上可以这样理解。

    六、函数指针数组

    存放函数指针的数组就是函数指针数组。

    写法:

    在函数指针的基础上改变:

    如上所示:

    int (* ppr)(int,int)这是一个函数指针,

    int (* ppr[5])(int,int)此时ppr会和[5]先结合,就是一个数组,去掉数组名和个数剩下的

    int (*)(int,int)这个就是函数指针类型。

    应用场景:转移表

    七、指向函数指针数组的指针

    我们从函数指针数组入手:

    int (* pr[5])(int,int)这是一个函数指针,

    现在我想要一个指向函数指针数组的指针,所以就可以将ppr与一个*结合使其成为指针

    int (* (*ppr)[5])(int,int) = ≺

    这个就成为了 指向函数指针数组的指针

    这个的函数指针类型就是去掉 (*ppr)

    这个int (* [5] )(int,int)就是一个函数指针类型

    接下来画个图来理解:


     

  • 相关阅读:
    Radware Alteon负载均衡-基于域名的七层负载均衡
    湖仓一体电商项目(二十四):合并Iceberg小文件
    python微信小程序 springboot个人健康管理系统java php
    redis之持久化(RDB、AOF)
    Django后端开发——中间件
    如何使用tornado将python代码封装成api
    VR酒店专业情景教学演示
    YOLOV7详细解读(一)网络架构解读
    crisprcas9基因编辑步骤
    【qml】QML最佳实践02
  • 原文地址:https://blog.csdn.net/2303_80828380/article/details/139661655