`

(二)数组与指针

阅读更多

  数组

    数组也是存储单一数据类型对象的容器,与vector相比,它的长度固定,也没有获取长度的操作。现代C++多用vector代替数组。

数组的维数必须用常量表达式定义。非const变量以及运行阶段才能知道值的const变量都不能定义数组的维数。例如:

    const unsigned buf_size=512,max_files=50;

    int staff_size=27;

    const unsigned sz=get_size();    //直到运行get_size()才能获得sz的值

    char buffer[buf_size];          //OK

    string fileTable[max_file+1];    //OK

    double salaries[staff_size];      //NO

    int score[get_size()];           //NO,非常量表达式

    int val[sz];                   //NOsz直到运行时才能知道

初始化时可以进行显示初始化,例如:

    const unsigned sz=3;

    int ia[]={0,1,2,4};             //默认长度为4

    int ib[sz]={1,2,3};

    sting ic[sz]={hi,boy};      //默认为{hi,boy,””}

如果没有显示初始化,那么数组元素会像普通变量一样初始化:在函数体外,元素默认为0;在函数体内,无初始化;如果元素类型为类类型,无论数组在什么位置,元素都会自动调用默认构造函数进行初始化,如果类没有默认构造函数,那么就必须显示初始化。

字符数组即可以用用花括号进行初始化,还可以用字符串字面值。

    char ca1[]={C,+,+};        //长度为3

    char ca2[]={C,+,+,\0};     //长度为4

    char ca3[]=C++;             //长度为4

    char ca4[3]=C++;            //错误

vector不同,数组不能用别的数组初始化,也不能将一个数组赋值给另外一个数组。

    int ia[]={1,2,3};

    int ib[]={0,1,2};

    ib=ia;                //错误

用下标访问元素时,vector使用vector<>::size_type作为下标的类型,而数组的下标类型为size_t

    int main(){

    const size_t array_size=10;

    int arr[array_size];

    for(size_t ix=0;ix!=array_size;++ix)

    return 0;

}

 

指针

vector的遍历可以用下标或者迭代器实现,而数组的遍历可以用下标或者指针实现。指针用于指向对象,与迭代器一样,提供对所致的对象的间接访问,只是指针结构更通用一些。

与迭代器不同的是,指针指向单个对象,迭代器只能访问容器里面的元素。

指针保存的是对象的地址。每个指针都有一个与之关联的数据类型,这个类型决定了指针所指向对象的类型。

    vector<int> *vec;  //vec指向了一个vector<int>类型的数据。

    int* ip;          //ip指向了一个int型数据

    string* sp;       //sp指向了一个string类型的数据。

    double da,*db;    //dadouble型,dbdouble型指针

一个有效的指针必然是以下三个状态之一:保存一个特定对象的地址、指向某个对象后面的另一个对象、0值。没有初始化的指针是无效的,直到指针赋值以后才能够使用它。

    int ival=1204;

    int *pi=0;        //pi赋给了0值,等价于pi=NULL,有效。

    int *p1=&ival;    //有效

    int *p2;         //没有初始化

    int *p3=p1;      //有效

    p3=0;          //现在p3不指向任何对象

避免使用没有初始化的指针。指针的赋值情况有:0值常量(0或者0值的const量)、类型匹配的对象的地址、另一对象之后的下一个地址、同类型的另一个有效地址。

void*指针可以保存任何对象的地址。void*表明该指针与一地址值相关,但不清楚存储在该地址上的对象的类型。void*指针只支持几种有限的操作:与另一指针进行比较、像函数传递void*指针、函数返回void*指针、给另一个void*指针赋值。不允许使用void*指针操纵它所指向的对象。

可以使用指针访问数组元素。

    int ia[]={0,2,4,6,8};

    int *ip=ia;

    ip=&ia[4];

    int *ip2=ia+2;

    std::ptrdiff_t=ip2-ip;    //两个指针之间的距离:-2

使用下标访问数组时,只要下标操作指向的是数组元素就可以进行。

    int ia[]={0,2,4,6,8};

    int *p=&ia[2];

    int j=p[1];    //ok,p[1]等价于*(p+1), *(ia+3),ia[3] 

    int k=p[-2];   //ok,p[-2]即为ia[0]

指针是数组的迭代器。以下pend指针超出了数组的范围,它不能进行引用运算,但是可以进行比较。这个循环非常类似于vector中的迭代器的操作:for(vector<int>::iterator iter=vec.begin;iter!=vec.end();iter++)

    const size_t sz=5;

    int arr[sz]={0,2,4,6,8};

    for(int *pbegin=arr,*pend=arr+sz;pbegin!=pend;pbegin++)

        cout<<*pbegin<<endl;

const与指针限定符有两种形式:const double *ptrdouble * const ptr

第一种的含义是不可用指针修改对象的内容。但是可以改变指针本身的内容,即指针可以赋给一个新的地址。如果所指对象不是const类型,那么不能通过指针修改这个对象,但可以用其它途径修改。如果指针所指内容是const,那么这个指针必须声明成第一种形式,否则不能通过编译。

    const double pi=3.14;

    double *ptr=π  //error,ptr is a plain pointer

    const double *ptr=π  //ok,a pointer to const

    const void *pv=π    //ok

    void * ppv=π    //error

    double dal=3.14;

    const *dptr=&dal;    //ok,but cannot change dal through dptr

    *dptr=3;     //error

    dptr=ptr;    //ok

第二种是const指针,它的值不能改变,即不能再使它指向其它对象。

    int a=5;    

    int * const pa=&a;

    pa=pa;    //error

    *pa=6;    //ok

还可以定义不可用指针修改所指内容的const对象。

        int a=9;

    const intconst pa=&a;

typedef中使用指针往往带来意外的结果。例如:

    typedef string *pstring; //将指向string的指针定义为pstring

    const pstring cstr;

那么这里定义的cstr是什么类型?非常容易误解为const string* cstr,事实上,const修饰的是cstr,

这个定义等价于string * const cstr。与string const s等价于const string s一样,这个语句也定价于pstring constcstr。

 

c风格字符串

以下中,cst1cst2外,其余都是c风格字符串。

    char cst1[]={C,+,+};

    char *cst2=cst1;

    char cst3[]={C,+,+,\0};

    char *cst4=cst3;

    char *cst5=C++;

    char cst6[]=C++;

    const char *cst7=C++;

事实上,c风格字符串的类型为const char *类型。

       char *cp="C++";

       cp[1]='-';   //错误,内容是不可改变的

  char cal[]={'C','+','+'};

  cp=cal;

  cp[1]='-';   //正确

   C++中用const char*类型来处理C风格字符串。可以用如下方式遍历字符串:

       const char *cp=what a great day!;

       while(*cp)

           {do sth whith *cp; cp++;}

处理C风格字符串的头文件为<cstring>。传入库中函数的指针必须非空且指向以null结束的字符串中。char ca[]={C,+,+};调用strlen(ca)将发生错误。

库函数有:strlen(s)——s的长度,不包含null;strcmp(s1,s2)——比较s1与s2的大小,s1大于s2时返回正数;strcat(s1,s2)——s2链接到s1并返回s1;strcpy(s1,s2)——s2复制到s1并且返回s1;strncat(s1,s2,n)——s2的前n个连接到s1并返回s1,注意要包含null;strncpy(s1,s2,n)——s2的前n个复制到s1并且返回s1。当然C++中提供简单的字符串比较方式:p1>p2。

尽管C++支持C风格字符串,但是应避免使用这种类型。

 

创建动态数组

虽然数组的长度是固定的,但是动态分配的数组不必在编译时知道其长度,可以在运行时才确定其长度。用于动态分配的对象的存储空间称为自由存储区或者堆。

    int *pia=new int[10]; //new分配了含有10int的数组,并将第一个指针返回

    delete[] pia; //将分配的内存返回给自由存储区

动态分配数组时,如果是类类型,数组元素调用默认构造函数,如果是内置类型,不初始化,但可以添加括号进行默认初始化,int *p=new int[10]()

     动态数组是允许运行时才确定长度的。

         size_t n=getSize(); //即使n=0,任然可以运行,new返回一个非0指针

         int *p=new int[n];

         for(int* q=p;q!=p+n;q++)

    

多维数组

    C++中没有多维数组,多维数组指的是数组的数组。int ia[3][4]={{1,2,3,4},{5,6,7,8},{9}}

多维数组名是一个指针,它指向了一个内层数组。int (*ip)[4]ip是一个指针,指向了int[4]

        int ia[3][4];

        typedef int arr[4];//arrint[4]类型,即arrint *const

        arr *p=ia;       //等价于int (*p)[4]=ia;p指向的数据是int *const

                  //那么p[0]不能被赋值,而p可以

        arr m=&ia[2];    //error,等价于int m[4]=ia[2];m被赋值不能

        p[0]=ia[0];      //errorpia是指向同一对象,但是p[0]不能赋值

分享到:
评论

相关推荐

    数组与指针的艺术.doc

    例如,常见的误解包括将一维数组视为一级指针,二维数组视为二级指针,以及将数组名视为常量指针。实际上,这些说法并不准确。文章强调,数组名本身不是指针,而是代表了数组的首地址,这一概念会在后续章节详细解释...

    数组与指针区别(很全面)

    #### 二、数组与指针的基本概念 1. **数组**: - 数组是一系列相同类型的数据项的集合。 - 数组名代表该数组首元素的地址。 - 数组的大小是固定的,在定义时就已经确定。 2. **指针**: - 指针是一个变量,其...

    数组的指针和指向数组的指针变量

    数组的指针和指向数组的指针变量的定义方法与普通变量的指针变量的定义方法相同,例如 int array[10], *pointer=array; 或者 int array[10], *pointer; pointer=array;。 在编程中,数组的指针和指向数组的指针变量...

    指向二维数组的指针

    在 Turbo C 中,可以定义指向一个由 n 个元素所组成的数组指针,例如 int (*p)[3];。这种数组指针不同于整型指针,进行地址加 1 运算时,地址值增加了 6(放大因子为 2x3=6)。 对于指向二维数组的指针,需要了解...

    二维数组与指针关系剖析

    因此,对于二维数组,我们可以获得其首元素的一维数组指针,这是一维数组指针的指针,也称为二级指针。 二维数组的声明通常如下所示: ```cpp int arr[3][4]; ``` 这个声明创建了一个3行4列的二维数组。数组`arr`...

    数组与指针的艺术 pdf

    #### 四、指针与数组的混淆 文档中提到的一些常见的错误观点包括: - “一维数组是一级指针”、“二维数组是二级指针”等说法。这些说法忽略了数组名和指针之间的本质区别。 - “数组名是一个常量指针”、“数组名...

    C\C++ 数组与指针彻底总结

    二、数组指针 数组指针是一个指向一维或者多维数组的指针。例如,int *b; b=new int[m]; 分配的数组大小为 m,在函数执行时才分配,所以叫“动态”。释放空间时,需要使用 delete [],因为是数组指针,释放时不要漏...

    C++数组与指针深入剖析

    ### C++数组与指针深入剖析 #### 一、引言 C++作为一种广泛使用的编程语言,其强大的功能和灵活性很大程度上得益于数组和指针的支持。数组和指针是C++编程的基础,也是理解更复杂数据结构的关键。本文将深入探讨...

    C++之数组与指针的异同 pdf

    ### 数组与指针的基本概念 #### 数组 数组是一种容器型数据结构,用于存储固定数量的同类型数据。数组在内存中以连续的方式存储其元素,这意味着数组中的每个元素都占据着一块连续的内存空间。数组名通常被视为指向...

    数组与指针应用详解,区别

    第二点,数组名可以作为指针常量。数组名可以直接赋值给指针变量,例如 char str[10]; char *pStr = str; 也可以作为指针形参,例如 strcpy(str1, str2);。 第三点,数组名的内涵在于其指代实体是一种数据结构,而...

    C++数组与指针对象数组对象指针

    C++数组与指针对象数组对象指针C++数组与指针对象数组对象指针

    二维数组与指针详解

    详细讲述了二维数组与指针之间的联系,对于学习C语言,理解指针数组吗,数组指针,数组与指针之间的关系有重要的帮助。仔细学习完该文档,详细你不会再为指针和数据而困惑。

    数组和指针练习题目(精选)

    因为 `P` 指向数组 `a` 的第二个元素 `20`。 [8.6] 表达式 `*++P` 的值是 `30`。因为 `++P` 将指针 `P` 移动到数组 `a` 的第三个元素 `30`,然后 `*` 将其解引用得到 `30`。 [8.7] 表达式 `++*P` 的值是 `21`。...

    C++第4章_数组与指针(C++课件,中南大学)

    指针与数组的关系紧密,指针可以用来操作数组,尤其是在函数参数传递和动态内存管理中。在函数中,通过传入数组的指针,可以避免复制整个数组,提高效率。此外,指针也可以用于多维数组,如二维数组,它们在内存中按...

    \数组与指针.doc

    同时,我们还强调了区分指针与地址的重要性,并探讨了如何正确地在C语言中使用数组与指针。正确理解和运用这些概念,不仅能帮助我们编写出更高效的代码,还能有效避免常见的编程错误。希望本文能帮助读者在学习C语言...

    C语言数组与指针代码精选

    在C语言中,数组和指针是编程的基础概念,它们紧密相连,经常一起使用。本章节将深入探讨这两个核心主题,结合"常东超、吕宝志...记住,实践是检验真理的唯一标准,多写代码,多思考,才能真正掌握C语言的数组与指针。

    彻底理解指针,指针数组和数组指针,指针函数和函数指针

    2. **数组指针**:可以用来处理二维或更高维度的数组,简化数组操作。 3. **函数指针**:在实现回调函数、策略模式等设计模式时非常有用。 4. **指针函数**:通常用于返回动态分配的数组或其他复杂数据结构。 通过...

    易语言数组转指针

    易语言数组转指针源码,数组转指针,子程序1,子程序2,子程序3,数组_整数转指针,数组_指针转整数,数组_文本转指针,数组_指针转文本,数组_字节集转指针,数组_指针转字节集,内存_申请,内存_释放,内存_取长度,内存_写入,...

    C++习题 6数组与指针

    ### C++习题 6数组与指针知识点详解 #### 一、基本概念与基础知识自测题解析 ##### 5.1 填充题 **5.1.1 数组定义时有三个要素:** - **数组名**:数组的名字,用来标识这个数组。 - **数组元素的类型**:数组中...

    数组与指针运算

    数组与指针运算 指针深度讲解教程

Global site tag (gtag.js) - Google Analytics