zoukankan      html  css  js  c++  java
  • C++数组与指针

    指向数组元素的指针

    一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。
        int a[10];   //定义一个整型数组a,它有10个元素
        int *p;  //定义一个基类型为整型的指针变量p
        p=&a[0];  //将元素a[0]的地址赋给指针变量p,使p指向a[0]
    在C++中,数组名代表数组中第一个元素(即序号为0的元素)的地址。因此,下面两个语句等价:
        p=&a[0];
        p=a;
    在定义指针变量时可以给它赋初值:
        int *p=&a[0];  //p的初值为a[0]的地址
    也可以写成
        int *p=a;  //作用与前一行相同
    可以通过指针引用数组元素。假设p已定义为一个基类型为整型的指针变量,并已将一个整型数组元素的地址赋给了它,使它指向某一个数组元素。如果有以下赋值语句:
        *p=1;  //对p当前所指向的数组元素赋予数值1
    如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

    如果p的初值为&a[0],则:
    1) p+i和a+i就是a[i]的地址,或者说,它们指向a数组的第i个元素,见图6.12。


    图6.12


    2) *(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。

    可以看出,[]实际上是变址运算符。对a[i]的求解过程是: 先按a+i×d计算数组元素的地址,然后找出此地址所指向的单元中的值。

    3) 指向数组元素的指针变量也可以带下标,如p[i]与*(p+i)等价。

    根据以上叙述,引用一个数组元素,可用以下方法:

    • 下标法,如a[i]形式;
    • 指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量。如果已使p的值为a,则*(p+i)就是a[i]。可以通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高。


    【例6.5】输出数组中的全部元素。假设有一个整型数组a,有10个元素。要输出各元素的值有3种方法:

    1) 下标法。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. int a[10];
    6. int i;
    7. for(i=0;i<10;i++)
    8. cin>>a[i]; //引用数组元素a[i]
    9. cout<<endl;
    10. for(i=0;i<10;i++)
    11. cout<<a[i]<<" "; //引用数组元素a[i]
    12. cout<<endl;
    13. return 0;
    14. }

    运行情况如下:
    9 8 7 6 5 4 3 2 1 0↙            (输入10个元素的值)
    9 8 7 6 5 4 3 2 1 0              (输出10个元素的值)

    2) 指针法。
    将上面程序第7行和第10行的“a[i]”改为“*(a+i)”,运行情况与(1)相同。

    3) 用指针变量指向数组元素。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. int a[10];
    6. int i,*p=a; //指针变量p指向数组a的首元素a[0]
    7. for(i=0;i<10;i++)
    8. cin>>*(p+i); //输入a[0]~a[9]共10个元素
    9. cout<<endl;
    10. for(p=a;p<(a+10);p++)
    11. cout<<*p<<" "; //p先后指向a[0]~a[9]
    12. cout<<endl;
    13. return 0;
    14. }

    运行情况与前相同。请仔细分析p值的变化和*p的值。

    对3种方法的比较:
    方法(1)和(2)的执行效率是相同的。第(3)种方法比方法(1)、(2)快。这种方法能提高执行效率。

    用下标法比较直观,能直接知道是第几个元素。用地址法或指针变量的方法都不太直观,难以很快地判断出当前处理的是哪一个元素。在用指针变量指向数组元素时要注意: 指针变量p可以指向有效的数组元素,实际上也可以指向数组以后的内存单元。如果有
       int a[10], *p=a;    //指针变量p的初值为&a[0]
       cout<<*(p+10);    //要输出a[10]的值
    在使用指针变量指向数组元素时,应切实保证指向数组中有效的元素。

    指向数组元素的指针的运算比较灵活,务必小心谨慎。下面举几个例子。

    如果先使p指向数组a的首元素(即p=a),则:
    1) p++(或p+=1)。使p指向下一元素,即a[1]。如果用*p,得到下一个元素a[1]的值。

    2) *p++。由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++)。作用是: 先得到p指向的变量的值(即*p),然后再使p的值加1。例6.5(3)程序中最后一个for语句:
        for(p=a;p<a+10;p++)
        cout<<*p;
    可以改写为
        for(p=a;p<a+10;)
        cout<<*p++;

    3) *(p++)与*(++p)作用不同。前者是先取*p值,然后使p加1。后者是先使p加1,再取*p。若p的初值为a(即&a[0]),输出*(p++)得到a[0]的值,而输出*(++p)则得到a[1]的值。

    4) (*p)++表示p所指向的元素值加1,即(a[0])++,如果a[0]=3,则(a[0])++的值为4。注意: 是元素值加1,而不是指针值加1。

    5) 如果p当前指向a[i],则
        *(p--)    先对p进行“*”运算,得到a[i],再使p减1,p指向a[i-1]。
        *(++p)   先使p自加1,再作*运算,得到a[i+1]。
        *(--p)   先使p自减1,再作*运算,得到a[i-1]。
    将++和--运算符用于指向数组元素的指针变量十分有效,可以使指针变量自动向前或向后移动,指向下一个或上一个数组元素。例如,想输出a数组100个元素,可以用以下语句:
        p=a;
        while(p<a+100)
        cout<<*p++;

        p=a;
        while(p<a+100)
        {
            cout<<*p;
            p++;
        }
    在用*p++形式的运算时,很容易弄错,一定要十分小心,弄清楚先取p值还是先使p加1。

    用指针变量作函数参数接收数组地址

    在前面介绍过可以用数组名作函数的参数。前面已经多次强调: 数组名代表数组首元素的地址。用数组名作函数的参数,传递的是数组首元素的地址。很容易推想: 用指针变量作函数形参,同样可以接收从实参传递来的数组首元素的地址(此时,实参是数组名)。下面将第5章5.4节中的例5.7程序改写,用指针变量作函数形参。

    【例6.6】将10个整数按由小到大的顺序排列。在例5.7程序的基础上,将形参改为指针变量。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. void select_sort(int *p,int n); //函数声明
    6. int a[10],i;
    7. cout<<"enter the originl array:"<<endl;
    8. for(i=0;i<10;i++) //输入10个数
    9. cin>>a[i];
    10. cout<<endl;
    11. select_sort(a,10); //函数调用,数组名作实参
    12. cout<<"the sorted array:"<<endl;
    13. for(i=0;i<10;i++) //输出10个已排好序的数
    14. cout<<a[i]<<" ";
    15. cout<<endl;
    16. return 0;
    17. }
    18. void select_sort(int *p,int n) //用指针变量作形参
    19. {
    20. int i,j,k,t;
    21. for(i=0;i<n-1;i++)
    22. {
    23. k=i;
    24. for(j=i+1;j<n;j++)
    25. if(*(p+j)<*(p+k)) k=j; //用指针法访问数组元素
    26. t=*(p+k);*(p+k)=*(p+i);*(p+i)=t;
    27. }
    28. }

    运行情况与例5.7相同。


    图 6.13


    本例与例5.7在程序的表现形式上虽然有不同,但实际上,两个程序在编译以后是完全相同的。C++编译系统将形参数组名一律作为指针变量来处理。

    实际上在函数调用时并不存在一个占有存储空间的形参数组,只有指针变量。

    实参与形参的结合,有以下4种形式:
    实  参                 形  参
    数组名              数组名       (如例5.7)
    数组名            指针变量     (如例6.6)
    指针变量          数组名
    指针变量        指针变量

    在此基础上,还要说明一个问题: 实参数组名a代表一个固定的地址,或者说是指针型常量,因此要改变a的值是不可能的。如:
        a++;  //语法错误,a是常量,不能改变
    而形参数组名是指针变量,并不是一个固定的地址值。它的值是可以改变的。在函数调用开始时,它接收了实参数组首元素的地址,但在函数执行期间,它可以再被赋值。如:

    1. f(array[], int n)
    2. {
    3. cout<<array; //输出array[0]的值
    4. array=array+3; //指针变量array的值改变了,指向array[3]
    5. cout<<*arr<<endl; //输出array[3]的值
    6. }

    多维数组与指针

    用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。

    1) 多维数组元素的地址
    设有一个二维数组a,它有3行4列。它的定义为:
        int a[3][4]={{1,3,5,7},{9,11,13,15},{17,18,21,23}};
    a是一个数组名。a数组包含3行,即3个元素:a[0],a[1],a[2]。而每一元素又是一个一维数组,它包含4图6.14个元素(即4个列元素),例如,a[0]所代表的一维数组又包含4个元素: a[0][0], a[0][1], a[0][2], a[0][3],见图6.14。可以认为二维数组是“数组的数组”,即数组a是由3个一维数组所组成的。


    图6.14


    从二维数组的角度来看,a代表二维数组首元素的地址,现在的首元素不是一个整型变量,而是由4个整型元素所组成的一维数组,因此a代表的是首行的起始地址(即第0行的起始地址,&a[0]),a+1代表a[1]行的首地址,即&a[1]。

    a[0],a[1],a[2]既然是一维数组名,而C++又规定了数组名代表数组首元素地址,因此a[0]代表一维数组a[0]中0列元素的地址,即&a[0][0]。a[1]的值是&a[1][0],a[2]的值是&a[2][0]。


    图6.15


    0行1列元素的地址可以直接写为&a[0][1],也可以用指针法表示。a[0]为一维数组名,该一维数组中序号为1的元素显然可以用a[0]+1来表示,见图6.16。

    欲得到a[0][1]的值,用地址法怎么表示呢?既然a[0]+1是a[0][1]元素的地址,那么,*(a[0]+1) 就是a[0][1]元素的值。而a[0]又是和*(a+0)无条件等价的,因此也可以用*(*(a+0)+1)表示a[0][1]元素的值。依此类推,*(a[i]+j)或*(*(a+i)+j)是a[i][j]的值。


    图6.16


    2) 指向多维数组元素的指针变量

    ① 指向数组元素的指针变量
    【例6.7】输出二维数组各元素的值。这里采用的方法是用基类型为整型的指针变量先后指向各元素,逐个输出它们的值。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    6. int *p; //p是基类型为整型的指针变量
    7. for(p=a[0];p<a[0]+12;p++)
    8. cout<<*p<<" ";
    9. cout<<endl;
    10. return 0;
    11. }

    运行结果如下:
    1 3 5 7 9 11 13 15 17 19 21 23

    关于指向数组元素的指针变量的几点说明:

    • p是指向整型数据的指针变量,在for语句中对p赋初值a[0],也可以写成“p=&a[0][0]”。
    • 循环结束的条件是“p<a[0]+12”,只要满足p<a[0]+12,就继续执行循环体。
    • 执行“cout<<*p;”输出p当前所指的列元素的值,然后执行p++,使p指向下一个列元素。


    ②指向由m个元素组成的一维数组的指针变量
    可以定义一个指针变量,它不是指向一个整型元素,而是指向一个包含m个元素的一维数组。这时,如果指针变量p先指向a[0](即p=&a[0]),则p+1不是指向a[0][1],而是指向a[1],p的增值以一维数组的长度为单位,见图6.17。


    图6.17


    【例6.8】输出二维数组任一行任一列元素的值。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    6. int (*p)[4],i,j;
    7. cin>>i>>j;
    8. p=a;
    9. cout<<*(*(p+i)+j)<<endl;
    10. return 0;
    11. }

    运行情况如下:
    2 3↙
    23

    由于执行了“p=a”,使p指向a[0]。因此p+2是二维数组a中序号为2的行的起始地址(由于p是指向一维数组的指针变量,因此p加1,就指向下一个一维数组),见图6.18。*(p+2)+3是a数组2行3列元素地址。*(*(p+2)+3)是a[2][3]的值。


    图6.18


    3) 用指向数组的指针作函数参数
    一维数组名可以作为函数参数传递,多维数组名也可作函数参数传递。

    【例6.9】输出二维数组各元素的值。题目与例6.7相同,但本题用一个函数实现输出,用多维数组名作函数参数。

    1. #include <iostream>
    2. using namespace std;
    3. int main( )
    4. {
    5. void output(int (*p)[4]); //函数声明
    6. int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    7. output(a); //多维数组名作函数参数
    8. return 0;
    9. }
    10. void output(int (*p)[4]) //形参是指向一维数组的指针变量
    11. {
    12. int i,j;
    13. for(i=0;i<3;i++)
    14. for(j=0;j<4;j++)
    15. cout<<*(*(p+i)+j)<<" ";
    16. cout<<endl;
    17. }

    运行情况如下:
    1 3 5 7 9 11 13 15 17 19 21 23

  • 相关阅读:
    html+css基础
    Jquery初级学习-实例3--视频网站视频展示效果
    Jquery初级学习-实例3--网站超链接和图片提示效果
    kali优化配置(3)--工具箱
    Raven2
    kali优化配置(2)
    kali优化配置(1)
    实验(1)
    sqli(7)
    CtfStudying之SSH私钥泄露
  • 原文地址:https://www.cnblogs.com/fenghuan/p/4772870.html
Copyright © 2011-2022 走看看