【C++】《C++ Primer Plus》笔记(3)——数组

来源:互联网 发布:c读取txt文件存入数组 编辑:程序博客网 时间:2024/05/19 22:25
使用new来创建动态数组
int *psome=new int [10];     // get a block of 10 ints
new运算符返回第一个元素的地址

当程序使用完new分配的内存块后,应当释放整个数组,而不仅仅是指针所指的元素
所以:
delete [  ]  psome;//free a dynamic array
及一定要遵从:如果是new [  ] 为数组分配内存,务必使用delete [  ]来释放

使用动态数组
灰常简单,只需要将指针名当做数组名来用就可以啦

(1)但是指针同数组名还是有本质的区别:数组名的值是不可修改的,而指针名则是可以修改的
例如,psome=psome+1;//这样,psome从原来所指的第一个元素,后移一位,指向第二个元素。为了delete能够正确地释放内存,delete之前,应当将指针指向最初指向的元素

指针和数组基本等价在于指针运算和C++内部处理数组的方式。整数变量加1,其值将会加1;而指针变量加1后,增加的量为其指向类型的字节数。
C++将数组名解析为地址,多数情况下是数组第一个元素的地址。
C++编译器将ArrayName[i]视作*(ArrayName+i),二者等价。

(2)另一个区别:对数组应用sizeof运算符得到的将是数组的长度,而对指针运用sizeof运算符得到的将是指针的长度,即使指针指向的是一个数组,这种情况下,C++不会将数组名解析为地址

Tip:数组名和数组的地址的关系
数组名被解析为数组第一个元素的地址,而对数组名应用地址运算符时得到的是整个数组的地址
short tell[10];//tell a array of 20 bytes
cout<<tell<<endl;//displays &tell[0]
cout<<&tell<<endl;//displays address of whole array
数字上说,二者相同;但从概念上 &tell[0]是一个2字节的内存块地址,而&tell是一个20字节内存块的地址。换句话说,tell是一个short型的指针(* short),而&tell是指向包含10个元素(原书写成20个,应该错了)的short数组(short(*) [10]).

Tip:使用数组来创建数组时,采用的时静态联编,即数组的长度在编译时设置;
使用new运算符来创建数组时,将采用动态联编,即在运行时为数组分配空间,其长度也在运行时设定,使用完这种数组后,应使用delete[  ]释放其占用的内存


指针和字符串
数组和指针有着特殊的关系,从一个简单不过的例子来分析:
char h[10]="I love";
cout<<h<<"C++"<<endl;
数组名是是第一个元素的地址,因此cout语句中的h是包含字符I的char元素地址。cout对象认为char的地址是字符串的地址,因此它打印改地址处的字符,然后继续打印后面的字符,直到遇到空字符为止。总之,给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。
h是字符串第一个字符的地址,表达式“C++”是什么呢?事实上,用括号引起来的也是其第一个元素的地址,就想数组名一样。上述的代码不会讲整个字符串发给cout,而只是发送字符串的地址。
对于数组中的字符串、用引号括起来的字符串常量以及指针所描述的字符串,处理的方式是一样的,都将传递它们的地址。与逐个传递字符串中的所以字符相比,这样的工作量的确少很多。

Tip:不要使用字符串常量或者没有初始化的指针来接收输入

将字符串赋值给数组
初始化数组时,要使用 = 赋值运算符,否则使用strcpy( )或者strncpy( )
char food[20]="tomato";//初始化数组
strcpy(food,"potato");
这样是没问题的
但是,有时会遇到这种情况
strcpy(food,"hot dry nuddle is my favoriate breakfest");
函数将字符串剩余部分复制到数组后面的内存字节中,可能会覆盖掉程序正在使用的其他内存,要避免这种情况,请使用strncpy(),该函数还支持第三个参数——要复制的最大字符数


使用new创建动态结构(也适用于类)

一张图搞定:



如果标识符是结构名,则使用句点运算符;如果标识符是指向结构的指针,则使用箭头运算符

*p是一个结构,(*p).price则是该结构的price成员,C++的运算符优先规则要求使用括号。


类型组合

程序实例:
#include<iostream>

using namespace std;

struct date
{
    int year;
    int month;
    int day;   
};

int main()
{
    date d1,d2,d3;
    d1.year=1995;
    date *pd=&d2;
    pd->year=1996;
    date D[3];
    D[0].year=2016;

    cout<<D->year<<endl;
    const date *arp[3]={&d1,&d2,&d3};
    cout<<arp[1]->year<<endl;

    const date **ppa=arp;
    auto ppb=arp;//c++11 automatic type deduction
    //or else use const date **ppb=arp

    cout<<(*ppa)->year<<endl;
    cout<<(*(ppb+1))->year<<endl;

    return 0;
}




数组的替代品
1     模版类vector
vector是一种动态数组,可以在运行阶段设置vector 的长度,可以在末尾附加新数据,还可以在中间插入新数据。
基本上是使用new创建动态数组的替代品,实际上vector的确是使用new 和delete来管理内存的,只是这种工作是自动完成的。
必须了解的几点:
  •      #include<vector>//使用vector之前必须包含这个头文件
  •      vector包含在名称空间std中,可以使用using编译指令、using声明或者std::vector
  •      模版来指定它存储的类型
  •      vector使用不同的语法来指定元素数
示例:
#include<vector>
...
using namespace std;
vector<int> vi;//create a zero-size array of int
int n;
cin>>n;
vector<double> vd(n);//create an array of n doubles



2     模版类array(c++11)

与数组一样,array对象的长度也是固定的,也使用栈而不是自由存储区,因此效率同数组一样,但是比数组更加安全更方便

#include<array>
...
using namespace std;
array<int, 5> ai;//create array object of 5 ints
array<double, 4> ad={ 1.2, 2.1, 3.43, 4.3 };

创建一个声明为arr的array对象,它包含n_elem个类型为typename的元素:
array<typeName, n_elem> arr;
与创建vector不同的是,n_elem不能是变量
0 0
原创粉丝点击