• Linux C语言(8)


    1、指针

    1.1 概念

    1.  指针就是地址
    2.  指针是一种数据类型,是一种保存地址的数据类型
    3.  int是一种数据类型,是一种保存整数的数据类型 1 2 3 4
    4.  float是一种数据类型,是一种保存浮点数的数据类型 3.14

    1.2 什么是地址

    1.  内存分配的最小单位是字节,每一个字节都有一个编号,我们把整个编号就叫做地址
    2.  ​
    3.  地址的本质:内存单元的编号
    4.  ​
    5.  指针:指针就是地址
    6.  ​
    7.  指针的本质:内存单元的编号

    1.3 什么是指针变量

    1.  int a;
    2.  ​
    3.  float b;
    4.  ​
    5.  指针变量:专门原来保存地址(内存单元的编号)的变量

    1.4 定义

    1.  存储类型 数据类型 *指针变量名;
    2.  int * p;
    3.  数据类型表示本指针变量所指向的变量的数据类型
    4.  存储类型表示本指针变量所指向的变量的存储类型
    5.  指针变量名是*后面的内容,*只是说明定义的是一个指针变量
    6.  只能指向相同数据类型的变量
    7.  int * p;
    8.  存储类型:autostaticexternregister
    9.  数据类型:指针所执行的数据类型 //int
    10.  指针数据类型(去掉指针变量名):数据类型 *  //int*  
    1.  *在c语言中有3种用法:
    2.  1、作为双目运算符,表示乘法 3*4
    3.  2、在定义变量的时候使用,表示指针这种数据类型
    4.  3、作为单目运算符,表示取值 *p(取指定变量p所存储的地址) 通过指针间接访问指针所指向的对象
    1.  在C语言中,变量的地址是由编译系统分配的,用户不知道变量的具体位置。C语言中提供了地址运算符“&”来表示变量的地址,其一遍形式为 &变量名;
    2.  int i,*p;
    3.  p = &a;

    注意

    1.  1、指针的指向是可以改变的
    2.  2、给指针赋值时,要注意数据类型的匹配
    3.  &是取地址运算符 *(地址)是取值运算符
    4.  3、&和*互为逆运算,可以相互抵消,正和负的关系
    5.  4、&为引用,*为解引用

    在32OS系统中,所有的指针都占4个字节

    在64OS系统中,所有的指针都占8个字节

    思考

    1.  1、什么是指针
    2.   指针是一种数据类型,是一种保存地址的数据类型(内存单元的编号)
    3.  2、什么是地址
    4.   内存单元的编号
    5.  3、什么是指针变量
    6.   专门用来保存指针的变量
    7.  4、如何定义一个指针变量
    8.   存储类型 数据类型 * 指针变量名
    9.  5、如果给指针变量赋值
    10.   p = &a
    11.  6、赋值之后可以做什么呢
    12.   修改、操作变量a

    2、空指针

    1. 空指针:int * p = NULL;
    2. 没有指向的指针(值为0的指针,就认为该指针没有指向)
    3. 注意:0号地址禁止操作(一旦操作会出现段错误//Segmentation fault (core dumped))非法访问内存空间。

    要操作必须改变空指针的指向

    3、野指针

    1. int * p;
    2. 不知道指向哪里的指针
    3. 局部变量没有初始化的时候,其值为随机值
    4. 局部指针变量没有初始化,就成了野指针
    5. 空指针操作不会出问题,野指针操作可能会出问题(随机值)//不清楚具体指向,修改取值会报错
    6. 如何避免野指针的出现?初始化为NULL

    4、gdb的调试

    Linux中调试使用调试器gdb

    1. 编辑器:vim
    2. 编译器:gcc
    3. 调试器:gdb

    调试步骤

    1. (1)编译程序的时候添加 "-g"参数
    2. gcc -g error.c -o error
    3. (2)启动gdb调试器
    4. gdb 可执行文件的名字 (gdb error)
    5. (3)设置断点
    6. b main
    7. b 行号
    8. (4)运行
    9. r
    10. (5)其它参数
    11. n(next):下一步,不进入子函数
    12. s(step):下一步,进入子函数
    13. p(printf) a(要打印的值)
    14. c(continue):可以直接跳出循环,执行下一步
    15. q(quit):退出

    5、值传递

    编写一子函数,实现两个数的交换

    1. 值传递:以下类型变量作为函数参数传递,包括基本数据类型变量(例如intchardouble等)、结构体类型变量。被调函数中对形参值的修改,不影响主调函数中的实参值。
    2. 值传递:类似物体的克隆,被调函数操作克隆的物体,主调函数操作源物体。本质是形参的地址空间与实参的地址空间不同。

    6、地址传递

    1. include
    2. void swp(int * m, int * n);
    3. int main(void)
    4. {
    5. int a = 1;
    6. int b = 2;
    7. swp(&a,&b);
    8. printf("%d\n",a);
    9. printf("%d\n",b);
    10. return 0;
    11. }
    12. void swp(int * m, int * n)
    13. {
    14. int tmp =0;
    15. tmp = *m;
    16. *m = *n;
    17. *n = tmp;
    18. }

    1. 地址传递:以下类型变量作为函数参数传递,包括数组名、指针或地址。被调函数中对形参值的修改,会影响主调函数中的实参值。
    2. 地址传递:类似物体的移动,两个函数先后操作同一个物体。本质是形参的地址空间与实参的地址空间相同。

    7、const修饰的指针

    const:只读

    用来修饰变量,使用const修饰的变量只能读,不能被修改(未修改存储位置,仍在栈区)

    1. int a = 10;//存放在栈区
    2. const int a = 10;//

    判断const修饰的变量是否在常量区

    const修饰的指针:

    1. 指针变量:
    2. (1)指针常量: 指针的指向不能发生改变
    3. int * const p = NULL;//值可改,指向不可改
    4. (2)常量指针: 指针所指向的内容不能被修改
    5. int const *p = NULL;//指向可改,值不可改
    6. (3)值和指向都不能修改
    7. const int * const p = NULL;//值和指向都不能被修改

    8、二级指针

    8.1 概念

    1. 二级指针:指针的指针
    2. 二级指针的内存空间存放的是一级指针变量的地址

    8.2 定义

    1. 一级指针: 存储类型 数据类型 *指针变量名;
    2. 数据类型:指针所指向的数据类型
    3. 一级指针:列指针,*一级指针:取值
    4. 二级指针:行指针,*二级指针:变为一级指针(列指针、一维数组名)
    5. 二级指针的定义:
    6. 存储类型 数据类型 **指针变量名;
    7. 二级指针的数据类型:数据类型 **
    8. p = &a;
    9. pp = &p;
    10. pp = &&a;//不能对a的地址常量取地址

    案例

    1. (1).若有语句int *point, a=4;point=&a;下面均代表a的地址的一组选项是(D)
    2. A. a, point,*&a B. &*a, &a,*point
    3. C. &point, *&point, &a D. &a, &*point, point
    4. (2).已有定义int k=2; int*ptr1,*ptr2;且ptr1和ptr2均已指向变量k,下面不能正确执行赋值语句的
    5. 是(B)
    6. A. k=*ptr1+*ptr2; B.ptr2=k;
    7. C.ptr1=ptr2; D. k=*ptr1*(*ptr2);

    总结

    1. 1、指针指向的数据类型就是将变量名和*(一个)去掉,剩下的就是指针所指向的数据类型
    2. int *p; // int
    3. int **p; //int *
    4. int ***p;//int **
    5. 2、指针的数据类型就是就变量名去掉,剩下的就是数据类型
    6. int *p;//int *
    7. int **p;//int **
    8. int ***p;//int ***
    9. 3、*p所能访问的空间大小,有p指向的数据类型来决定
    10. char *p;//*p所能访问的内存空间的大小为1byte
    11. int *p;//*p所能访问的内存空间的大小为4byte
    12. int **p;//**p所能访问的空间的大小为4byte

    作业

    1. int a[5] = {0};
    2. 1-------数组的输入
    3. 2-------数组的输出
    4. 3-------求数组中的次大值
    5. 4-------排序
    6. -1 -----exit

    1. #include
    2. #define N 5
    3. #include
    4. void menu();
    5. void input();
    6. void output();
    7. void sub();
    8. void swap();
    9. void quit();
    10. int main(void)
    11. {
    12. int fun = 0;
    13. int a[N] = {0};
    14. while(1)
    15. {
    16. menu();
    17. printf("请选择功能");
    18. scanf("%d",&fun);
    19. switch(fun)
    20. {
    21. case 1:
    22. input(a);
    23. break;
    24. case 2:
    25. output(a);
    26. break;
    27. case 3:
    28. sub(a);
    29. break;
    30. case 4:
    31. swap(a);
    32. break;
    33. case -1:
    34. quit();
    35. }
    36. }
    37. return 0;
    38. }
    39. void menu()
    40. {
    41. printf("功能菜单\n");
    42. printf("1-数组的输入\n");
    43. printf("2-数组的输出\n");
    44. printf("3-求数组中的次大值\n");
    45. printf("4-排序\n");
    46. printf("-1-exit\n");
    47. }
    48. //输入
    49. void input(int * a)
    50. {
    51. for(int i = 0; i
    52. {
    53. scanf("%d",&a[i]);
    54. }
    55. }
    56. //输出
    57. void output(int * a)
    58. {
    59. for(int i = 0; i
    60. {
    61. printf("%d\n",a[i]);
    62. }
    63. }
    64. //次大值
    65. void sub(int * a)
    66. {
    67. int i,max,mid;
    68. for(i = 0;i<5;i++)
    69. {
    70. if(a[i]>max)
    71. {
    72. mid = max;
    73. max =a[i];
    74. }
    75. else if(a[i]>mid&&a[i]
    76. {
    77. //另一种情况 arr[i]在两者之间*/
    78. mid = a[i];
    79. // 把arr[i]赋给mid
    80. }
    81. }
    82. printf("次大值:%d\n",mid);
    83. }
    84. //排序
    85. void swap(int * a)
    86. {
    87. int i,j,tmp = 0;
    88. for(i=1;i
    89. {
    90. for(j=0;j
    91. {
    92. if(a[j]>a[j+1])
    93. {
    94. tmp=a[j];
    95. a[j]=a[j+1];
    96. a[j+1]=tmp;
    97. }
    98. }
    99. }
    100. }
    101. //退出
    102. void quit()
    103. {
    104. exit(0);
    105. }

  • 相关阅读:
    1331. 数组序号转换 : 简单模拟题
    redis问题:三种集群——主从、哨兵、cluster集群;16384槽等
    数据库相关概念复习--个人复习使用
    集合—Collections工具类
    Go单体服务开发最佳实践
    以太坊实现、语言模型应用与实用工具 | 开源日报 0817
    Flutter常见UI组件使用
    关于pytorch nn.KLDivLoss()损失计算loss值为负数的原因
    MySQL数据库备份与恢复 未完成版。。。
    网络安全-信息收集简介
  • 原文地址:https://blog.csdn.net/m0_58540923/article/details/134235600