• 读书笔记:C++ Primer系列(10)—— 数组与指针(2)


    题记:

    指针用于指向某个对象。与迭代器一样,指针提供对其所指向的对象的间接访问。与迭代器不同之处在于:指针用于指向单个对象,而迭代器只能用于访问容器内的元素。

    10.1 指针的定义与初始化

    事实上,指针保存的是某个对象的地址

    程序清单—01

    1     string str("Hello World !");
    2     string *pStr=&str;
    3     cout<<*pStr<<endl; //输出指向的对象
    4     cout<<pStr<<endl;//输出指向对象的地址

    第一行语句定义了一个字符串str;
    第二行定义了一个指向字符串类型的指针pStr,并将该指针初始化指向str

    程序结果:

    一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址(“&”,取地址符);指向某个对象后面的另一个对象;初始值为0值(不指向任何对象)

    程序清单—02

        int temp=10;
        int *pInt1=0; // ok,指针pInt1初始化为0值,不指向任何对象
        int *pInt2=&temp; //ok,指针pInt2初始化为整型temp的地址,即指向temp
        int *pInt3;//ok,但没有初始化,比较容易出错
        pInt=pInt2; //ok,指针pInt1和pInt2都指向变量temp
        pInt2=0;//此时,指针pInt2不指向任何对象

    10.2 指针操作

    10.2.1 指针的简单操作
                           string s1="Hello World !";                                             string s2=“China”;
                           string *sp1=&s1;    //sp1指向对象s1                               string sp2=&s2;//sp2指向对象s2

                                        

                                                                       sp1=sp2;//指针sp1与sp2均指向了对象s2

                                                          

    程序清单—03

    //修改指针的值
    #include <iostream> 
    using std::cin;  
    using std::cout;  
    using std::endl;  
    int main()  
    {  
        int val=10;  
        int *ip1=&val,*ip2=0;  
        ip2=ip1;  
        cout<<*ip2<<endl;       
        system("pause");
        return 0;  
    }  

    程序清单—04

    //修改指针所指向的对象
    #include <iostream> 
    using namespace std;
    int main()  
    {  
        int val=10;  
        int *ip1=&val;  
        *ip1=110;  
        cout<<*ip1<<endl;      
        system("pause");
        return 0;  
    } 

    程序清单—05

    //指向指针的指针
    #include <iostream> 
    using namespace std;
    int main()  
    {  
        int val=1024;  
        int *pi=&val;  
        int **ppi=&pi; 
        cout<<val<<endl<<*pi<<endl<<**ppi<<endl;    
        system("pause");
        return 0;  
    }  

    10.2.2 指针访问数组

                                        int  arr[]={1,2,3,4,5};

                                        int *ip=arr; //定义一个指向整型的指针,且指向整型数组arr的受地址,即等同于 int *ip=&arr[0];

                                        int *ipp=&arr[3];//指针ipp指向数组arr的第4个元素

                                        int *ip2=ip+3;//指针ip2指向arr[3],这里所加的整数不能超出数组长度

                                        ptrdiff_t n=ip2-ip;//结果为3

    注:两个指针相减的结果是标准库类型ptrdiff_t的数据类型,其定义在cstddef头文件中

                                      

                                        const size_t array_size=5;

                                        int arr[array_size]={1,2,3,4,5};

                                        int *ip1=arr; //ip1指向arr[0]

                                        int *ip2=ip1+array_size;//ip2指向arr数组的超出末端的位置

                                                       

    注:C++允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作。

    程序清单—06

    #include <iostream> 
    using namespace std;
    int main()  
    {  
        const size_t array_size=5;
        int arr[array_size]={1,2,3,4,5};
        for(int *pstart=arr,*pend=pstart+array_size;pstart!=pend;++pstart)
        {
            cout<<*pstart<<' ';
        }
        system("pause");
        return 0;  
    }  

    10.2.3 指针与const限定符
    1.const指针

                 int errNum=0;

                 int *const ip=&errNum; //这里定义了一个const指针ip

    注:const指针本身不能修改,即不能const指针指向其他对象;但const指针所指向的对象的值可以修改

    2.指向const对象的指针

                 const int *ip2 ;//这里定义了一个指向const对象的指针ip2

    • 指向const对象的指针定义中,const限定了指针所指向的对象类型,而并非指针本身,意味着,指针本身可以修改,而所指向的对象不可以修改。
    • 把一个const对象的地址赋给一个普通的、非const对象的指针是不合法的;
    • 不能使用void指针保存const对象的地址,而不许使用const void *类型的指针保存const对象的地址;
    • 允许将非const对象的地址赋给指向const对象的指针

                             const double pi=3.14;

                             double *pdu=&pi;//error,pdu是一个普通指针,不可以指向一个const对象

                             const double *pdu2=&pi;//ok

                             const int numb=30;

                             const void *ip1=&numb;//ok

                             void *ip2=&numb;//error,不能用void指针保存const对象的地址

    3.指向const对象的const指针

                             const double pi=3.14

                             const double  *const pdu3=&pi;

    注:指向const对象的const指针定义中,既不能修改指针所指向的对象的值,也不能修改指针的指向(即指针存放的地制止)

    10.3 C风格字符串标准库函数

     要使用C风格字符串的标准库函数,必须包含相应的C头文件:  #include<cstring> ,相当于C语言提供的#include<string.h>                     

                          表10-1 C风格字符串的标准库函数

    永远不要忘记字符串结束符null

                 char ca[]={'c','+','+'};

                 cout<<strlen(ca)<<endl;              //ca不是以null结束的,出现错误!!

     

    P117 习题4.25  编写程序比较两个string类型的字符串,然后编写另一个程序比较两个C风格字符串的值

    程序清单—07

    //两个string类型的字符串的比较
    #include <iostream> 
    #include <string> 
    using namespace std;
    int main()  
    {  
        string s1(10,'a'),s2(10,'b');
        if(s1>s2)
            cout<<"s1>s2"<<endl;
        else if(s1==s2)
            cout<<"s1=s2"<<endl;
        else
            cout<<"s1<s2"<<endl;
        
        system("pause");
        return 0;  
    }  

    程序清单—08

    //两个string类型的C风格字符串的比较
    #include <iostream> 
    #include <string> 
    using namespace std;
    int main()  
    {  
        const char *str1="I love Jiangsu";  
        const char *str2="I love China";  
        int temp=strcmp(str1,str2);  
        if(temp>0)  
            cout<<"第一个字符串大"<<endl;   
        else if(temp<0) 
            cout<<"第二个字符串大 ";  
        else 
            cout<<"同样大"<<endl;  
        system("pause");
        return 0;  
    }  

    10.4 动态数组

    数组类型的变量有三个重要限制:

    • 数组的长度是固定不变的;
    • 数组在编译时必须知道其长度;
    • 数组只有在定义它的语句块内存在。

    注1:实际程序往往需要在运行时动态地分配数组(动态分配的数组不必在编译时知道其长度,可以在运行时才确定其长度),并且动态分配的数组将一直存在,知道程序显式释放它为止。

    注2:每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区

    注3:C语言采用标准库函数malloc和free来创建和释放动态分配的对象,C++采用new和delete来创建和释放动态分配的对象。

    1.动态数组的定义

    动态分配数组只需指定类型和长度,不必为数组对象命名,new表达式返回指向新分配数组的第一个元素的指针。如:

                       int *ip = new int[10];

    上述语句动态分配了一个含有10个整型元素的数组,并返回指向该数组的第一个元素的指针,此返回值初始化了指针ip

    2.初始化动态数组

    动态分配数组时,如果数组元素是类类型,将使用该类的默认构造函数实现初始化;如果数组元素是内置类型,则无初始化。如:

                      int *ip = new int[10];

                      string *pstr=new string[10];

    上述两条语句都分配了含有10个对象的数组,其中第一个数组是整型(术语内置类型),无初始化;第二个数组是string类型,分配了保存对象的内存空间后,将调用string类型的默认构造函数来初始化数组的每一个元素。

    也可以使用跟在数组长度后的一对圆括号,对数组进行初始化

                      int *ip = new int[10]();//圆括号要求编译器对数组进行初始化,这里将数组元素都设置为0

    3.const对象的动态数组

    如果程序在自由存储区中创建了内置类型的const对象,则必须为这个数组提供初始化

                      const int *ip2 = new const int[10];//error,未初始化const数组

                      const int *ip3= new const int[10]();//ok,待圆括号的初始化

                      const string *pstr1=new const string[10];//ok,调用string类型的默认构造函数进行初始化

    4.动态空间的释放

    动态分配的内存最后必须进行释放,否则,内存会被逐渐耗尽。

    C++使用delete[]来释放指针所指向的动态分配的数组。如:delete[] ip;

    P138 习题4.28: 编写程序由标准输入设备读入的元素数据建立一个int型vector对象,然后动态的创建一个与该vector对象大小一致的数组,将vector对象所有元素都赋值给新的数组。

    程序清单—09

    #include <iostream> 
    #include <vector>
    using namespace std;
    int main()  
    {  
        vector<int> ivec;  
        int val;  
        cout<<"请输入一些数字"<<endl;   
        cin>>val;  
        while(cin>>val)
        {  
            ivec.push_back(val); 
            if(val==-1)
                break;
        }  
        int *ip=new int[ivec.size()];  
        int *op=ip;  
        for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();iter++,op++)
        {  
            *op=*iter;  
        }  
    
        delete [] ip;  
        system("pause");
        return 0;  
    }  

    P122 习题4.32:编写程序用int型数组初始化vector对象

    程序清单—10

    #include <iostream> 
    #include <vector>
    using namespace std;
    int main()  
    {  
    
        const size_t arr_size=10;  
        int arr_int[arr_size];  
        cout<<"input "<<arr_size<<" numbers"<<endl;  
        for(size_t ix=0;ix<arr_size;ix++)
        {  
            cin>>arr_int[ix];  
        }   
        cout<<"vector对象元素如下:"<<endl;
        vector<int> ivec(arr_int,arr_int+arr_size);  
        for(vector<int>::iterator iter=ivec.begin();iter<ivec.end();iter++)
        {  
            cout<<*iter<<' ';  
        }  
    
        system("pause");
        return 0;  
    }  

     

     

     

     

     

     

                            

  • 相关阅读:
    服务器上传大小限制 --- 来自 FastAdmin 项目开发的引发的问题 (TODO)
    英语中的各种“破坏”
    PADS Layout CAM 的中高级焊盘选项
    FastAdmin 推荐 Git 在线学习教程
    Vue 将样式绑定到一个对象让模板更清晰
    jQuery动态的给页面中添加一条样式表的链接
    页面根据不同的情况添加不同的样式表
    jQuery屏蔽浏览器的滚动事件,定义自己的滚轮事件
    如何判断自己的浏览器支持的是javascript的那个版本
    ie下 iframe在页面中显示白色背景 如何去掉的问题
  • 原文地址:https://www.cnblogs.com/kkdd-2013/p/3498089.html
Copyright © 2020-2023  润新知