(一)数组
1.概念:
- 具有一定顺序关系的若干相同变量的集合体(数组的顺序信息,与循环语句配合,依次处理批量数据)
- 数组元素的地址是连续的,与逻辑上的次序相邻
- 数组名字是数组元素的内存地址,数组名是一个常量,不能被赋值
2.定义&使用:类型说明符 数组名[常量表达式][常量表达式] :
- 先定义后使用,逐个引用数组元素
- 一维数组的初始化:列出全部元素的初始值;只给一部分元素指定初始值 ;列出全部数组元素初值,不指定数组长度
- 二维数组的初始化:列出所有的初值,按顺序进行初始化;只对部分元素进行初始化;列出全部初始值,一维下标的个数可以省略;
【小bug,cout.width()需要直接在main函数里使用,不然会报错error: 'cout' does not name a type 】 eg: 循环从键盘读入若干选择题答案,计算并输出每个答案的正确率,直到输入ctrl+z为止 每组连续输入5个答案,每个答案可以是a,b,c,d
# include<iostream>
using namespace std;
int main(){
const char key[] = {'a','b','c','d','a'};
const int Num_question = 5;
char c;
int question = 0, Num_correct =0;
cout<<"Enter the"<<Num_question<<"question tests:"<<endl;
while(cin.get(c)){
if (c!='\n')
{
if (c == key[question])
{
Num_correct++;
cout<<"-";
}
else
{
cout<<"*";
}
question++;
}
else
{
cout<<"Score"<<static_cast<float>(Num_correct)/Num_question*100<<"%";
}
}
return 0;
}
3.数组作为函数的参数:
- 数组作实参,与单个变量一样;;
- 数组名作参数,形、实参数都应是数组名,类型要一致,传送的是数组的首地址;
- 对形参数组的改变会影响到实参数组(希望改变和不希望改变)
a.定义:类名 数组名[元素个数] b.访问:通过下标访问:数组名[下标].成员名 c.构造和析构:
- 构造数组时,元素所属的类未声明构造函数,则采用默认构造函数
- 各元素对象的初值要求为相同的值,可以声明具有默认形参值的构造函数
- 各元素对象的初值要求为不同的值,需要声明带形参的构造函数
- 数组中每一个对象被删除时,系统都有调用一次析构函数
5.基于范围的for循环
a.背景:自动遍历整个容器 b.使用:
for (dataType rangeVariable : array)
statement;
6.Vector对象
a.背景:使用动态数组时的操作过于繁琐,希望能够自动创建和删除对数组进行下标越界检查 b.定义:vector<元素类型>数组对象名(数组长度) vector5 c.使用
- 对数组元素的引用:vector 对象名[下标表达式]
- 获得数组长度,用size函数 vector 对象名.size()
- 需要定义头文件
(二)指针
1.内存空间的访问
2.指针的概念
- 内存地址,用于间接访问内存单元
- 指针变量:用于存放地址的变量
3.定义与使用
a.初始化:存储类型 数据类型 *指针名 = 初始地址 int*pa = &a
- 不仅要说明该变量是指针,还要说明他指向的对象是什么类型(取数据的多少字节)
- 可以用一个合法的指针去初始化另一个指针变量
- 不能用一个内部非静态变量去初始化static指针
b.赋值:指针名 = 地址 - “地址”中存放的数据类型与指针类型必须相符
- 向指针变量赋的值必须使地址常量或变量,不能是普通整数(0例外,可以赋给指针,表示空指针nullptr更安全的空指针)
- 允许定义void类型的指针,只能用来存放地址,而不能用来访问地址。
- "*“指针运算符;”&"地址运算符
4.常量
【牛客网经常有的概念辨析】 a.指向常量的指针 【牛客网经常有的概念辨析】
- 不能通过指向常量的指针改变所指对象的值,但是指针本身可以改变指向另外的对象
int a;
const int*p1 = &a;
int b;
p1 = &b;
*p1 = 1 ;
b.指针类型的常量 若声明为指针常量,则指针本身的值不能被改变
int a;
int *const p2 = &a;
p2 = &b;
5.指针运算
【牛客网中有考察二维数组的地址运算,然后求最后输出的结果】 a.算术运算: (总是指向数据的完整起始位置,指针指向连续存储的同类型数据时,指针与整数的加减法和自增自减运算才有意义)
- 与整数的加减运算
- 指针++、–运算
b.关系运算: - 指向相同数据类型数据指针之间可以进行关系运算
- 指针可以和0进行关系运算
6.指针与数组的关系
a. 指向数组元素的指针 【牛客网上是题目通常会有好几层*从数组的第一层往外分析】 *pa 就是a[0], (pa+1)就是a[1],…,(pa+i)就是a[i] b.指针类型:数组的元素是指针类型 eg. 二维数组就相当于由一维数组构成的数组
7.指针作为参数
a.优点:
- 需要数据双向传递
- 需要传递一组数据,只传首地址运行效率比较高
eg:传递一个数的整数部分和小数部分 【浮点数在计算机里是近似存储的,两个数相减满足某个精度就能视为相等】
8.指针类型的函数
函数的返回值是指针,该函数就是指针类型的函数 a.定义形式
存储类型 数据类型 *函数名()
{}
b.注意
- 不要将非静态的局部地址用作函数的返回值(非静态的地址,离开后地址就失效了)
- 返回的指针在主调函数中依然合法有效的地址
- 子函数中通过动态内存分配new操作取得的内存地址返回给主函数是合法有效的
9.指向函数的指针
a.容纳的是指向函数代码的起始地址
存储类型 数据类型(*函数指针名)();
函数类型的指针 存储类型 数据类型 *函数指针名(); b.典型用途——实现函数回调
- 通过函数指针调用函数,可以在相似时间灵活使用不同的方法
- 调用者不关心谁是被调用者,需要知道存在一个具有特定原型和限制条件的被调用函数
eg 函数指针,编写一个compute,对两个整数进行各种计算,有一个形参为指向具体算法函数的指针,根据不同的实参函数,用不同的算法(最大值、最小值、和)进行计算。
# include<iostream>
using namespace std;
int compute (int a,int b,int(*func)(int,int))
{return func(a,b);}
int max(int a,int b)
{return((a>b)?a:b);}
int min(int a,int b)
{return((a>b)?b:a);}
int sum(int a, int b)
{return a+b;}
int main(){
int a,b,res;
cout<<"请输入整数a"<<endl;
cin>>a;
cout<<"请输入整数b"<<endl;
cin>>b;
res = compute(a,b,&max);
cout<<"Max of"<<a<<"and"<<b<<"is"<<res<<endl;
res = compute(a,b,&min);
cout<<"Min of"<<a<<"and"<<b<<"is"<<res<<endl;
res = compute(a,b,&sum);
cout<<"Sum of"<<a<<"and"<<b<<"is"<<res<<endl;
}
10.对象指针
a.定义形式:类名 *对象指针名 b.通过指针访问对象成员:对象指针名—>成员名 ptr->get() 相当于(*ptr).getx() c.this指针:指向当前对象自己的指针
- 隐含于类的每一个非静态成员函数中
- 指出成员函数所操作的对象
当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作,就隐含使用了this指针 11.智能指针 背景:垃圾回收技术
智能指针类型 | 特点 |
---|
unique_ptr | 不允许多个指针共享资源,可以用标准库中的move函数转移指针 | shared_ptr | 多个指针共享资源 | weak_ptr | 可复制shared_ptr,但其构造或者释放对资源不产生影响 |
(三)字符串
1.C风格字符串
a.具体说明:各个字符连续、顺序存放,每个字符占一个字节,以’\0’结尾,相当于一个隐含创建的字符串常量数组。 b.缺点:
- 执行连接、拷贝、比较等操作,都需要显式调用库函数
- 字符串长度不确定时,需要new和delete比较繁琐
- 容易发生下标越界的问题
2.string类
a.有常用的操作函数
(比较浮点数的大小端)
(四)动态分配与释放内存
1.动态申请操作符 new
new 类型名T(初始化参数列表) 功能:在程序执行期间,申请用于存放T类型对象的内存空间,并依据初始列表赋以初值
2.释放内存操作符 delete
功能:释放指针p所指的内存,p必须是new操作的返回值
3.申请和释放动态数组
分配:new 类型名T [数组长度] 数组长度可以是任何整数类型的表达式,在运行时计算
- 一个二维数组的首地址就是指向一维数组的指针
释放:delete[ ] 数组名 p - 释放指针p所指向的数组(不写[]就会只释放元素对应的这一个)
- p必须用new 分配得到的数组首地址
4.将动态数组封装成类
优点:可以在访问数组元素前检查下标是否越界
(五)复制构造
1.浅层复制
实现对相减数据元素的一一对应复制
2.深层复制
当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指对象进行复制
3.移动构造
有些复制构造是不必要的,只需要移动对象即可,将源对象资源的控制权全部交给目标对象(省去了构造和删除临时对象的过程)
|