zoukankan      html  css  js  c++  java
  • 指针概念

    一、地址与指针的概念

      为了说清楚什么是指针,必须清楚数据在内存中是如何存储的,又是如何读取的。

      如果在程序中定义了一个变量,在对程序进行编译时,系统会给这个变量分配内存单元,编译系统根据程序中定义的变量类型分配一定长度的空间(整型变量分配4个字节,单精度浮点型4个字节,字符型变量1个字节)。内存区的每一个字节都有一个编号,这就是“地址”。

      内存单元的地址与内存单元的内容这两个概念的区别,假设程序已定义了3个整型变量i、j、k,编译时系统分配2000和2001两个字节给变量i,2002、2003字节给j,2004、2005给k。在程序中般是通过变量名来对内存单元进行存取操作的。其实程序经过编译以后已经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。假如有输出语句:printf("%d",i),它是这样执行的:根据变量名与地址的对应关系(这个对应关系是在编译时确定的),找到变量i的地址2000,然后从由2000开始的两个字节中取出数据(即变量的值),把它输出。假如有输人语句:scanf("%d",&i); 在执行时,把从键盘输人的值送到地址为2000开始的整型存储单元中。如果有语句:k=i+j;则从2000、2001字节取出i的值(3),再从2002、2003字节取出j的值(6),将它们相加后再将其和(9)送到k所占用的2004、2005字节单元中。这种按变量地址存取变量值的方式称为“直接访问”方式。

      还可以采用另一种称之为“间接访问”的方式,将变量i的地址存放在另一个变量中。按C语言的规定,可以在程序中定义整型变量、实型变量、字符变量等,也可以定义这样一种特殊的变量,它是存放地址的。 假设我们定义了一个变量i_pointer, 用来存放整型变量的地址,它被分配为3010 3011两个字节。 可以通过下面语句将i的地址(2000)存放到i_ pointer中。 —> i_pointer=&i;  打个比方,为了开一个A抽屉,有两种办法,一种是将A钥匙带在身上,需要时直接找出该钥匙打开抽屉,取出所需的东西。另一种办法是:为安全起见,将该A钥匙放到另一抽屉B中锁起来。如果需要打开A抽屉,就需要先找出B钥匙,打开B抽屉,取出A钥匙,再打开A抽屉,取出A抽屉中之物,这就是“间接访问”。

      一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即 指针),则它称为“指针变量”。上述的i_pointer就是一个指针变量。指针变量的值(即指针变量中存放的值)是地址(即指针)。请区分“指针 ”和“指针变量”这两个概念。 例如,可以说变量i的指针是 2000,而不能说i的指 针变量是2000。指针是一个地址,而指针变量是存放地址的变量。

    二、变量的指针和指向变量的指针变量

      1、定义一个指针变量

      变量的指针就是变量的地址,存放变量地址的变量是指针变量,为了表示指针变量和它所指向的变量之间的联系,在程序中用“*”符号表示“指向”的对象。所有变量必须有定义,指针变量不同于整型或其他类型,它是用来专门存放地址的,必须将它定义为指针类型

     int i,j;
     int *pointer_1,*pointer_2;
      第1行定义了两个整型变量i和j,第2行定义了两个指针变量:pointer_ 1和pointer_2,它们是指向整型变量的指针变量。左端的int是在定义指针变量时必须指定的“基类型”。指针变量的基类型用来指定该指针变量可以指向的变量的类型。例如,上面定义的基类型为int的指针变量pointer_ 1和pointer_ 2,可以用来指向整型的变量i和j,但不能指向浮点型变量a和b。
     float *pointer_3;   //pointer_3是指向float型变量的指针变量
     char *pointer_4;   //pointer_4是指向字符型变量的指针变量
      那么,怎样使一个指针变量指向另一个变量呢?可以用赋值语句使个指针变量特一个变量的地址 .从而使它指向 一个该变量。例如: 
     pointer_1=&i;//将变量i的地址存放到指针变量pointer_1中,因此pointer_1就指向了变量i
     pointer_2=&j;//将变量j的地址存放到指针变量pointer_2中,因此pointer_2就指向了变量j

       定义指针变量时要注意两点:

       (1)、指针变最前面的“*”表示该变量的类型为指针型变量。指针变量名是pointer 1、pointer 2, 而不是* pointer 1、* pointer_2。这是与定义整型或浮点型变量的形式不同的。

       (2)、在定义指针变量时必须指定基类型。有的读者认为既然指针变量是存放地址的,那么只需要指定其为“指针型变量”即可,为什么还要指定基类型呢?要知道不同类型的数据在内存中所古的字节数是不相同的(例如整型数据占2字节,字符型数据占1字节),例如“使指针移动1个位置”或“使指针值加1”,这个1代表什么呢?如果指针是指向一个整型变量的,那么“使指针移动1个位置”意味着移动2个字节,“使指针加1”意味着使地址值加2个字节。如果指针是指向一个浮点型变量的,则增加的不是2而是4。因此必须指定指针变量所指向的变量的类型,即基类型。一个指针变量只能指向同一个类型的变量,不能忽而指向一个整型变量,忽而指向一个实型变量。在前面定义的pointer_1和pointer_2只能指向整型数据。

      对上述指针变量的定义也可以这样理解:“int * pointer_ 1,* pointer_ 2;”定义了* pointer_1和,* pointer 2是整型变量,如同:“int a,b;”定义了a和b是整型变量一样。而* pointer_1和* pointer_2是pointer_1和pointer_2所指向的变量,pointer_ 1和pointer_ 2是指针变量。

      需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的:

    float a;//定义a为float类型
    int *pointer_1; //定义pointer_1为基类型为int的指针变量
    pointer_1=&a;//将float型变量的地址放到指向整型变量的指针变量中,错误

      2、指针变量的引用

        请牢记,指针变量中只能存放地址(指针),不要将一个整数(或其他非地址类型的数据)赋给一个指针变量,“*”具有指向的意思

    // &: 取地址运算符
    // *: 指针运算符
    //以下程序通过指针变量访问整型变量
    #include<stdio.h>
    int main(){
        int a,b;
        int *pointer_1,*pointer_2;
        a=100;
        b=10;
        pointer_1=&a;//a的地址赋给pointer_1
        pointer_2=&b;//b的地址赋给pointer_2
        printf("%d,%d
    ",a,b);
        printf("%d,%d
    ",*pointer_1,*pointer_2);
        return 0; 
    } 

      对“&”和“*”补充说明:

      (1)、& *pointer_1的含义是什么?“&”和“*”两个运算符的优先级别相同,但按自右向左方向结合,因此先进行*pointer_1的运算,它就是变量a,再执行&运算。因此& *pointer_1与&a相同,即变量a的地址。如果有:pointer_2=& *pointer_1;  它的作用将a的地址赋给pointer_2,如果原来pointer_2指向b,重新赋值后不再指向b了,而指向了a。

      (2)、*&a的含义是什么?先进行&a运算得到a的地址,再进行*运算,即&a所指向的变量,也就是变量a。

      (3)、(*pointer_1)++相当于a++。注意括号是必须的,如果没有括号就相当于*(pointer++),由于++是后加,所以先对pointer_1原值进行*运算,得到a的值,然后是pointer_1的值改变,这样pointer_1不再指向a了。

    //输入a,b两个整数,按先后大后小的顺序输出a和b
    #include<stdio.h>
    int main(){
        int a=45,b=90;
        printf("a=%d,b=%d
    ",a,b);
        int *pa,*pb;
        pa=&a;
        pb=&b;
        if(a<b){
            pa=&b;
            pb=&a;
        }
        printf("max=%d,min=%d
    ",*pa,*pb);
        return 0;
    } 

      请注意:a和b并未交换,它们仍保持原值,但pa和pb的值变了。pa的值原来是&a后来变成&b,pb的值原来是&b后来变成&a。这样在输出*pa和*pb时实际上输出的是b和a的值,所以先输出90,然后再输出45。整个过程中并没有交换a、b的值,而是交换了两个指针变量的值。(a、b的地址)

      3、指针变量作为函数参数

      函数的参数不仅可以是整型、浮点型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。

    //实现对输入的两个整数按大小顺序输出,用函数处理,而且用指针类型的数据作为函数参数 
    #include<stdio.h>
    void swap(int *p1,int *p2){
        int temp;
        temp=*p1;
        *p1=*p2;
        *p2=temp;
    }
    int main(){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("a=%d,b=%d
    
    ",a,b);
        int *p_1,*p_2;
        p_1=&a;
        p_2=&b;
        if(a<b){
            swap(p_1,p_2);
        }
        printf("a=max=%d,b=min=%d
    ",a,b);
        return 0;
    }

      对程序的说明swap是用户定义的函数,它的作用是交换两个变量(a和b)的值。swap函数的两个形参p1、p2是指针变量。程序运行时,先执行main函数,输人a和b的值(现输人5和9)。然后将a和b的地址分别赋给指针变量p_1和p_2,使p_ 1指向a,p_ 2指向b。接着执行if语句,由于a<b,因此执行swap函数。注意实参p_ 1和p_ 2是指针变量,在函数调用时,将实参变量的值传送给形参变量,采取的依然是“值传递”方式。  因此虚实结合后形参p1的值为&a,p2的值为&b。 这时p1和p_ 1都指向变量a,p2和p _2都指向b。接着执行swap函数的函数体,使*p1和*p2的值互换,也就是使a和b的值互换。函数调用结束后,形参p1和p2不复存在(已释放),最后在main函数中输出的a和b的值已是经过交换的值(a=9,b=5)。

    //注意*p1和*P2的交换是如何实现的,如果写成下面这样就出错了
    void swap(int *p1,int *p2){
        int *temp;
        *temp=*p1;//此语句有问题 
        *p1=*p2;
        *p2=*temp;
    }  

       *p1就是a,是整型变量。而*temp是指针变量。但temp中无确定的值(它的值是不可预见的),因此temp所指向的单元也是不可预见的。所以,对temp 赋值有可能给一个存储着重要 数据的存储单元赋值,这样就会破坏系统的正常 工优状况。应该将* pl的值赋给一个整型变量,用整型变量作为临时辅助变量实现*p1和* p2的交换。注意:本例采取的方法是交换a和b的值,而p1和p2的值不变。可以看到,在执行swap函数后.变量a和b的值改变了。请仔细分析,这个改变是怎么实现的。这个改变不是通过将形参值传回实参来实现的。请读者考虑一下能否通过下面的函数实现a和b互换。

    void swap(int x,int y){
        int temp;
        temp=x;
        x=y;
        y=temp;
    }

        如果在main()函数调用以上swap(a,b)函数,会有什么样的结果呢?在函数调用时,a的值传送给x,b 的值传送给y,执行完swap函数后,x和y的值是互换了,但并未影响到a和b的值。在函数结束时,变量x和y释放了,main函数中的a和b并未互换,也就是说,由于“单向传送”的“值传递”方式,形参值的改变不能使实参的值随之改变。

    //请注意,不能企图通过改变指针形参的值而使指针实参的值改变,比如下面的程序
    #include<stdio.h>
    void swap(int *p1,int *p2){
        int *temp;
        temp=p1;
        p1=p2;
        p2=temp;
    }
    int main(){
        int a,b,*pointer_1,*pointer_2;
        scanf("%d%d",&a,&b);
        pointer_1=&a;
        pointer_2=&b;
        if(a<b)
            swap(pointer_1,pointer_2);
        printf("%d,%d",*pointer_1,*pointer_2);
        return 0;
    }

      以上程序想要实现,改变主调函数中pointer_1和pointer_2值,但是这是办不到的,当输人为“5,9”后,程序实际输出为“5,9”。C语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式。指针变量作函数参数也要遵循这一规则。不可能通过调用函数来改变实参指针变量的值,但可以改变实参指针变量所指变量的值。我们知道,函数的调用可以(而且只可以)得到一个返回值(即函数值),而运用指针变量作参数,可以得到多个变化了的值。如果不用指针变量是难以做到这一点的。

    //输入a,b,c三个整数,按大小顺序输出
    #include<stdio.h>
    void swap(int *p,int *q){
        int temp;
        temp=*p;
        *p=*q;
        *q=temp;
    }
    void exchange(int *p1,int *p2,int *p3){
        if(*p1<*p2)
            swap(p1,p2);
        if(*p1<*p3)
            swap(p1,p3);
        if(*p2<*p3)
            swap(p2,p3);
    }
    int main(){
        int a,b,c,*p1,*p2,*p3;
        scanf("%d%d%d",&a,&b,&c);
        p1=&a;
        p2=&b;
        p3=&c;
        exchange(p1,p2,p3);
        printf("%d  %d  %d
    ",a,b,c);
        return 0;
    } 
  • 相关阅读:
    微信小程序 checkbox 组件
    微信小程序 button 组件
    h5视频标签 video
    h5离线缓存
    ECharts插件介绍(图表库)
    rich-text 副文本组件 text文本组件
    progress组件(进度条)
    icon组件
    movable-view组件
    android 双击图片变大,缩放功能
  • 原文地址:https://www.cnblogs.com/geziyu/p/9629697.html
Copyright © 2011-2022 走看看