指针

1.认识指针


 (1).指针概念
  指针 就是 地址 
  地址 就是 内存单元的编号 
  
  代表的意义:
    地址 只是 告诉了说 在哪里
 (2).指针类型 
  地址 本身 是一种特殊的数据 --- 是具有指向含义的 整数 
  c语言为了能够表示这种特殊的数据 
  专门设计一种数据类型 --- 指针类型 


2.定义指针(变量)


  语法:   
    基类型 *  指针变量名;
     (1)    (2)     (3)

(1)基类型    
        基类型说明了 通过指针 找到的空间
        a.多大
        b.怎么用
        就是 指针找到的空间上 所存储的 数据类型 
(2) *    
       只是一个修饰符 
       用来说明现在定义的变量,不是普通变量,而是指针变量 
(3)指针变量名
       是个标识符 ,符合标识符命名规则 
           
定义多个指针变量:
int *p1,*p2,*p3; //*用来修饰变量名 


*p1 
*p2
*p3 
eg:
  int a = 10;    //定义一个int型变量 初始化为10
  int * p = &a;  //定义了一个指针类型的变量p
                                 //用a的地址初始化
                           //说,p指向了a 
                 
eg:
  地址 是 内存单元的编号 -- 就是编号本身 
  记录地址的指示牌 --- 相当于是指针变量 
 
 通过指针变量(指示牌) ---获得地址信息 
                        |----告诉说在哪里
                        
理解:   
   1.指针 就是 地址 
     地址  内存单元编号 
   2.通过地址 只能 完成 找到 对应的空间 这个事情

 
 
3.通过指针实现数据引用 


 int a = 10;
 int *p = &a;
 此时通过p 找到空间 
 
 如果要用,还必须 指针的间接访问 操作 
 
 指针运算符 *
 
  *地址数据      
    作用: 
       表示 使用 地址 所在的 空间 
      
  *p  //相当于是在用a的空间 
  
 此时a的空间两种使用方式
 1.通过a直接使用 ---  直接访问 
 2.通过p来使用  ---  通过p拿到地址值 ,再对地址做*运算 ,才能使用到a的空间 
                                                     间接访问
 
 *p 运算过程:
 step1:从p中拿出地址值,到内存中定位 
 step2:从定位处开始偏移sizeof(基类型)大小的一块空间
 step3:将这块空间当做一个基类型变量/数据来看 

 *p <=> a  


4.为什么需要指针的间接访问


  a.可以使函数带出多个结果 
    //指针间接访问
  b.提高效率 
    函数传参 
    避免了大数据的拷贝     


5.用途 


  被调函数中,实现对主调函数中 数据的使用和修改 
  
  指针类型 
  int *p; //p是个什么类型?
          //int* ---指针类型 ---表示的是这么一类指针 --- 基类型为int型的这一类指针 
          
6.想要实现 被调 修改 主调   
  a.要修改谁 就把谁的地址传过去 
  b.被调函数中,还必须有对应的 *p 这样运算 
  
  
  函数传参的方式:
       值传递     --- 实参的值 给到 形参变量 
       地址传递   --- 可以实现被调修改主调   

练习:
   实现一个函数,得到 两个整数 和 和 差 


练习:
   实现一个函数,找出两个整数中的最大值 和 最小值 


   
练习:
   实现一个函数,完成两个整型数的交换 

指针的运算



int a = 10;
int *p = &a;

指针的多种表示

printf("%p\n",&*p);  //&(*p)
printf("%p\n",*&p);  //*(&p) //
printf("%d\n",*&a); 
printf("%d\n",&*a);  //error a是整型数据 不是 地址数据

指针 算术运算 


    + - * / % ++ -- 

   p+1    //指针加 1 表示 指向了下一个 基类型  
   p+n    //sizeof(基类型)*n

   p-1    
   p-n   
   
   p++
   p--
   ++p
   --p
   
   p+q  //p q 都是指针  ---两个指针不能相加 
   p-q  //可以相减 
        //要求,必须是同类型指针 
        //  表示 相差了几个 基类型 

   * / %  
         //指针不能做 * / % 

   
   int a = 10;
   short *p = (short *)&a; // &a --- 地址值类型 int *
                                         // int *p = &a;    
   p的类型 short * 

  int a = 0x12345678;
   short *p = (short *)&a; // &a --- 地址值类型 int *
                                      // int *p = &a;


   +-------+ <--- 0x1000小端
   | 0x78  |
   +-------+ <--- 0x1001 
   | 0x56  |
   +-------+ <--- 0x1002  
   | 0x34  |
   +-------+ <--- 0x1003
   | 0x12  |
   +-------+ <--- 0x1004
   |       |
   +-------+
   |       |
   +-------+
   | 0x1000|  p
   +-------+ 
   |       |
   +-------+      
   考点:
      请写程序判断你电脑大小端?

a = 1;

在十六进制中为0000 0001;

若为小端,则printf("%d\n",*p)输出为 1

反之为 0

关系运算  (看的就是指针的数值 地址编号大的 就大)
>      >=     <   <=    ==    !=
    p1 == &m

指针 + 整型一维

 int a[10] = {1,2,3,4,5,6,};
 
 //数组的特点:
   连续 有序 单一 
 
   操作数组 --- 只需要获得首元素的地址即可 
   
   p+1  //指针运算 
   p+2
   *(p+3)
   
   a[0]   //首元素 
   &a[0]      //首元素地址  ----啥类型 
                 // a[0] 是什么类型 --- int类型 
                 // &a[0] 地址就是 int * 

   int *p = &a[0];      //指针变量 指向了数组首元素 
                              //指向了数组 
            a 数组名 --- 数组名  
                                代表类型 --- 数组类型 
                                 代表的值 --- 首元素的地址 
                        
   int *p = a; //说 p 指向了 数组a 

 a[i] //数组下标的方式 --- 其实本质就是 指针的运算 


   i[a]  // *(i+p)

特殊的指针:
NULL   ---空指针 --- 地址编号为 0 的地址
野指针  --- 野指针 需要避免出现 
           指向不明确 

练习:
   准备一个数组,实现函数找出最大值 
   *(p+i)

练习:
     逆 序  


练习:
     排序 
     选择排序 //


练习:
     查找 
     返回? -- 找到元素的指针 
     NULL 


快速排序


  效果 
//1.函数
//2.指针 
//3.递归

         b         e
     0 1 2 3 4 5 6 7 8   //下标 
    [3 1 4 7 8 2 4 0 5 ] //数值 
   
step1: 找一个基准值 
                                       //数组的第一个元素 
step2: 从右往左 开始找 第一个比 基准值的值 
step3: 从左往右 开始找 第一个比 基准值的值
step4: 交换找到值,重复step2 到 step4 
       直到begin 和 end相遇 
step5: 相遇后,将相遇位置上的值 与 基准值 交换 
           e
           b 
     0 1 2 3 4 5 6 7 8   //下标 
    [2 1 0 3 8 7 4 4 5 ] //数值 
           -
step6: 对小的一部分 继续快速排序 
       对大的一部分 继续快速排序 

       
  void quickSort(int *begin,int *end)
  {
        int *p = begin;
        int *q = end;
        
        if (begin >= end)
        {
           return ;
        }
        
      //step1: 找一个基准值 
       int *k = begin;       
       while (begin < end)
       {
        //step2: 从右往左 开始找 第一个比 基准值 小 的值     
        //       *k 基准值 
               while (begin < end && *end >= *k)
               {
                   --end;
               }    
        //step3: 从左往右 开始找 第一个比 基准值 大 的值       
        //       *k 基准值 
               while (begin < end && *begin <= *k)
               {
                   ++begin;  
               }
        //step4: 交换找到值,重复step2 到 step4 
               直到begin 和 end相遇 
               swap(begin,end);
       }   
       //step5: 相遇后,将相遇位置上的值 与 基准值 交换 
       swap(begin,k);   
       //step6: 对小的一部分 继续快速排序 
       //对大的一部分 继续快速排序 
      quickSort(p,end-1); //小的一部分 
      quickSort(begin+1,q); //大的一部分 
    }

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐