当前位置:   article > 正文

C语言基础指针*_指针**

指针**

目录

一、字符指针

1.const作用简单介绍

二、指针数组、数组指针

1.指针数组

2.数组指针

3.数组指针的使用

 3.1数组指针传参

四、数组传参

4.1一维数组传参

4.2二维数组传参

五、函数指针

 5.1函数指针存储

5.2函数指针调用

5.3练习


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

指针大小4/8字节(32位平台/64位平台)

指针是有类型的,其类型决定了指针±整数时的步长,和对其解引用‘*’时的权限(能够操作几个字节)

一、字符指针

char arr='d';

char*p=&arr;(取出arr地址放入到p中)

此时*p=='d';

*p='w';(把对应地址存放变量d赋值为w)

其余类型指针情况类似

一个特殊情况

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

此时打印的结果是hello world,是把hello world放入到str指针变量里了吗?显然不是

"hello world"为常量字符串,本质是把字符串的首地址放入到了str中。

一个练习

  1. #include <stdio.h>
  2. int main()
  3. {
  4.    char s1[] = "hello";
  5.    char s2[] = "hello";
  6.    const char *s3 = "hello";
  7.    const char *s4 = "hello";
  8.    if(s1 ==s2)
  9. printf("s1等于s2\n");
  10.    else
  11. printf("s1不等于s2\n");
  12.      
  13.    if(s3 ==s4)
  14. printf("s3等于s4\n");
  15.    else
  16. printf("s3不等于s4\n");
  17.      
  18.    return 0;
  19. }

 结果为s1不等于s2

            s3等于s4

        原因是s3和s4指向的是同一个常量字符串,C/C++会把常量字符串存储单独存储到一个内存区域,当几个指针指向同一个字符串时,实际上会指向同一内存。但是用相同的常量字符串初始化不同数组时就会开辟不同的内存块。

1.const作用简单介绍

const修饰的常变量(本质还是变量)不能用于arr[中];

const在*同一侧时起的作用都是相同的

const char*p;char const*p,此时*p不能赋值改变

char* const p,此时p不能被赋值改变

二、指针数组、数组指针

1.指针数组

用于存放指针的数组

int *arr[5];//存放五个int类型的指针数组

int **arr[5];(二级指针)//存放五个指针指向int*的数组

数组名表示的是数组首元素地址,以下两种情况除外

此时&arr为取出整个数组地址,(但是&arr==arr);sizeof(arr)中的arr为整个数组字节大小

2.数组指针

指向数组的指针,用于存放整个数组的地址

int(*p)[5];//p为指针,指向含有五个元素的整型数组。

int*p[5];

[]的优先级高于*,如果不加(),p会和[5]先结合成一个有五个元素的数组

下面举个例子进行练习

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

 

 可以看到arr和&arr的输出是相同的,但是当二者都加1后结果却不相同了,原因就在于,&arr取出的是整个数组地址,加1后跳过的是整个数组

3.数组指针的使用

  1. #include<stdio.h>
  2. int main()
  3. {
  4. int arr[5]={1,2,5,4,7};
  5. int(*p)[5]=&arr;
  6. return 0;
  7. }

 3.1数组指针传参

二维数组传参是传的是第一行元素的地址,行数可以不设置,但列一定要设置

  1. #include <stdio.h>
  2. void arr1(int arr[][4], int row, int col)
  3. {
  4.    int i = 0;
  5.    for(i=0; i<row; i++)
  6.   {
  7.        for(j=0; j<col; j++)
  8.       {
  9.            printf("%d ", arr[i][j]);
  10.       }
  11.        printf("\n");
  12.   }
  13. }
  14. void arr2(int (*arr)[4], int row, int col) {
  15.    int i = 0;
  16.    for(i=0; i<row; i++)
  17.   {
  18.        for(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][4] = {1,2,3,4,5,6,7,8,9,10};
  28.   arr1(arr, 3, 4);
  29.    arr2(arr, 3, 4);
  30.    return 0;
  31. }

在我们了解以上知识后我们来看看这个int(*arr[8])[6]

对其进行分析arr和[8]相结合,组成一个数组,有8个元素,每个元素为指针类型,指针指向含有6个int型元素的数组,每个元素类型为int(*)[6],存放数组指针的数组。

四、数组传参

4.1一维数组传参

一维数组传参传的是首元素地址,数组存放是连续的

  1. #include <stdio.h>
  2. void test(int arr[])//F or T?
  3. {}
  4. void test1(int arr[10])//F or T?[]中的数字没有意义,仅仅是为了方便初学者学习理解,并不会创建一个形参数组
  5. {}
  6. void test2(int *arr)//F or T?
  7. {}
  8. void test3(int *arr[20])//F or T?
  9. {}
  10. void test4(int **arr)//F or T?
  11. {}
  12. int main()
  13. {
  14. int arr[10] = {0};
  15. int *arr2[20]={0};//传地址二级指针(地址的地址),每个元素为int*类型
  16. test(arr);
  17. test1(arr);
  18. test2(arr);
  19. test3(arr2);
  20. test4(arr2);
  21. }

 答案:T T T F T

4.2二维数组传参

二维数组传的是第一行元素的地址,二维数组本质上也是连续存放的,第一行后面跟着第二行。。。。。

  1. void test(int arr[3][5])// T
  2. {}
  3. void test(int arr[][])// F
  4. {}
  5. void test(int arr[][5])// T 行可以省略,列不能省略
  6. {}
  7. //二维数组传参,函数形参的设计只能省略第一个[]的数字。
  8. void test(int *arr)// F
  9. {}
  10. void test(int* arr[5])// F 是指针数组
  11. {}
  12. void test(int (*arr)[5])// T 数组指针
  13. {}
  14. void test(int **arr)// F 二级指针
  15. {}
  16. int main()
  17. {
  18. int arr[3][5] = {0};
  19. test(arr);
  20. }

五、函数指针

  1. #include <stdio.h>
  2. void test()
  3. {
  4. printf("C++\n");
  5. }
  6. int main()
  7. {
  8. printf("%p\n", test);
  9. printf("%p\n", &test);//和数组不同,这两种都是函数地址
  10. return 0;
  11. }

 5.1函数指针存储

  1. int Add(int x,int y)
  2. {
  3. return 0;
  4. }

 函数返回类型为int,其参数为两个int元素,int (*pp) (int,int)=Add;pp就是函数指针变量

5.2函数指针调用

pp中存放的是Add地址,进行调用对其解引用*即可,(*pp)(num1,num2);

注意不要写成*pp(num1,num2)这种形式

但其实不对其解引用直接pp(num1,num2);也可以正常使用。*在此处并没有意义

写成*pp(1,2)这种形式就变成了*3,就会出现问题。

5.3练习

  1. //码1
  2. (*(void (*)())0)();
  3. //码2
  4. void (*evial(int , void(*)(int)))(int);

这两串代码是什么意思?

例1

(  *(  void (*)  (  )  )0  )(); //假设此处0为一个地址
void(*)()//函数指针类型,指向的函数为无参返回值为void型
(void(*)())0//对0进行强制类型转换,转换为函数指针类型,意味着0地址处放一个函数
*(  void (*)  (  )  )0 //对其进行解引用
(  *(  void (*)  (  )  )0  )()//解引用后对其传参

 

例2

void (  *eva(  int , void(*)(int)  )  )(int);

void(*)(int)和int为eva( , )的两个参数的类型

eva的返回值类型为void(*)(int)

其形式比较复杂,我们可以通过typedef对其函数指针类型进行重命名

  1. typedef void(*pp)(int)//将函数指针类型void(*)(int)重命名为pp
  2. typedef void(*)(int) pp;//这种形式是错误的
  3. pp eva(int,pp)

 

后续会更新函数指针数组,指向函数指针数组的指针和回调函数qsort模拟实现。

感谢各位的阅读。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/784033
推荐阅读
相关标签
  

闽ICP备14008679号