C++期末复习
1、选择题考察的知识点(40分)
C++在C的基础上多了什么新特性
- 类和对象
- 继承
- 多态、虚函数和RTT1(运行阶段类型识别)
- 函数重载
- 引用变量
- 泛型(独立于类型的)编程,这种技术是由模版和标准模版库(STL)提供的
- 处理错误条件的异常机制
- 管理函数、类和变量名的名称空间
编写C++程序的步骤
一、用C++语言编写程序
用高级语言编写的程序称为“源程序”(source program)。C++的源程序是以.cpp做为后缀的(cpp是c plus plus 的缩写)。
二、对源程序进行编译
为了使计算机能执行高级语言源程序,必须先用一种称为“编译器(complier)”的软件(也称编译程序或编译系统),把源程序翻译成二进制形式的“目标程序(object program)”。
编译是以源程序文件为单位分别编译的。目标程序通常以.obj或.o做为后缀(object 的缩写)。编译的做用是对源程序进行词法检查和语法检查。编译时对文件中的所有内容进行检查,编译结束后会显示出全部的编译出错信息。通常编译系统给出的出错信息分为两种,一种是错误(error);一种是警告(warning) 。
三、将目标文件链接
在改正全部的错误并所有经过编译后,获得一个或多个目标文件。此时要用系统提供的“链接程序(linker)”将一个程序的全部目标程序和系统的库文件以及系统提供的其余信息链接起来,最终造成一个可执行的二进制文件,它的后缀是.exe,是能够直接执行的。
四、运行程序
运行最终造成的可执行的二进制文件(.exe文件),获得运行结果。
五、分析运行结果
若是运行结果不正确,应检查程序或算法是否有问题。
C++中合法标识符的特征
第一个字符必须是字母(不分大小写)或下划线(_);
后跟字母(不分大小写)、下划线(_)或数字组成;
标识符中的大小写字母有区别;
不能与c编译系统已经预约义的、具备特殊用途的保留标识符(即关键字)同名。好比,不能将标识符命名为float,auto,break,case,this,try,for,while,int,char,short, unsigned,等等;html
算符优先级(重点考察算术运算符、逻辑运算符和赋值运算符)
算术表达式、逻辑表达式
下表显示了 C++ 支持的算术运算符。c++
假设变量 A 的值为 10,变量 B 的值为 20,则:算法
运算符 |
描述 |
实例 |
+ |
把两个操做数相加 |
A + B 将获得 30 |
- |
从第一个操做数中减去第二个操做数 |
A - B 将获得 -10 |
* |
把两个操做数相乘 |
A * B 将获得 200 |
/ |
分子除以分母 |
B / A 将获得 2 |
% |
取模运算符,整除后的余数 |
B % A 将获得 0 |
++ |
自增运算符,整数值增长 1 |
A++ 将获得 11 |
-- |
自减运算符,整数值减小 1 |
A-- 将获得 9 |
下表显示了 C++ 支持的关系逻辑运算符。编程
假设变量 A 的值为 1,变量 B 的值为 0,则:小程序
运算符 |
描述 |
实例 |
&& |
称为逻辑与运算符。若是两个操做数都非零,则条件为真。 |
(A && B) 为假。 |
|| |
称为逻辑或运算符。若是两个操做数中有任意一个非零,则条件为真。 |
(A || B) 为真。 |
! |
称为逻辑非运算符。用来逆转操做数的逻辑状态。若是条件为真则逻辑非运算符将使其为假。 |
!(A && B) 为真。 |
条件判断语句if的使用方法

循环语句(while, for)的使用方法
C++ 中 while 循环的语法:数组
while(condition)
{
statement(s);
}
在这里,statement(s) 能够是一个单独的语句,也能够是几个语句组成的代码块。condition 能够是任意的表达式,当为任意非零值时都为真。当条件为真时执行循环。编程语言
当条件为假时,程序流将继续执行紧接着循环的下一条语句。函数

在这里,while 循环的关键点是循环可能一次都不会执行。当条件被测试且结果为假时,会跳过循环主体,直接执行紧接着 while 循环的下一条语句。post
C++ 中 for 循环的语法:性能
for ( init; condition; increment )
{
statement(s);
}
下面是 for 循环的控制流:
- init 会首先被执行,且只会执行一次。这一步容许您声明并初始化任何循环控制变量。您也能够不在这里写任何语句,只要有一个分号出现便可。
- 接下来,会判断 condition。若是为真,则执行循环主体。若是为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
- 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句容许您更新循环控制变量。该语句能够留空,只要在条件后有一个分号出现便可。
- 条件再次被判断。若是为真,则执行循环,这个过程会不断重复(循环主体,而后增长步值,再而后从新判断条件)。在条件变为假时,for 循环终止。

函数默认参数的使用方法(注意默认参数和非默认参数的顺序)
① 有函数声明(原型)时,默认参数能够放在函数声明或者定义中,但只能放在两者之一
double sqrt(double f = 1.0); //函数声明
double sqrt(double f) //函数定义
{
// ....
}
② 没有函数(原型)时,默认参数在函数定义时指定.
//没有 函数声明
double sqrt(double f = 1.0) //函数定义
③ 在具备多个参数的函数中指定默认值时,默认参数都必须出如今不默认参数的右边,一旦某个参数开始指定默认值,它右边的全部参数都必须指定默认值.
int f (int i1, int i2 = 2, int i3 = 3); // 正确
int g (int i1, int i2 = 2, int i3); // 错误, i3未指定默认值
int h (int i1 = 1, int i2, int i3 = 3); // 错误, i2未指定默认值
④ 在调用具备默认参数的函数时, 若某个实参默认,其右边的全部实参都应该默认。
//例如, 一个函数声明以下
int f(int i1 = 1, int i2 =2, int i3 = 3);
//调用函数 f()
f(); //正确, i1=1, i2=2, i3=3
f(3); //正确, i1=3, i2=2, i3=3
f(2, 3); //正确, i1=2, i2=3, i3=3
f(4, 5, 6); //正确, i1=4, i2=5, i3=6
f(, 2, 3); //错误, i1默认,其右边的i2和i3没有默认
重载函数的定义
一.重载函数的定义
函数的重载是一种特殊状况,C++容许在同一做用域中声明几个相似的同名函数,这些同名函数的形参列表
(参数个数,类型,顺序)必须不一样,经常使用来处理实现功能相似数据类型不一样的问题。
在C++中不只函数能够重载,运算符也能够重载。
运算符<<>>。既能够作移位运算符,也能够作输出,输入运算符。
注意:重载函数的参数个数,参数类型或参数顺序三者中必须有一个不一样。
函数重载的规则:
*函数名称必须相同。
*参数列表必须不一样(个数不一样,类型不一样,参数排列顺序不一样等)。
*函数的返回类型也能够相同也能够不相同。
*仅仅返回类型不一样不足以成为函数的重载。
二.函数重载的做用
重载函数一般用来在同一做用域内 用同一个函数名 命名一组功能类似的函数,
这样作减小了函数名的数量,避免了名字空间的污染,也大大方便了代码的书写,可读性很强。
三.重载底层编译的原理
由于函数名同样,咱们根据参数列表对函数进行重命名,
这样的话底层编译就能够识别不一样功能的重载函数了。
例:
void Swap(int a , int b);
Swap_int_int;
void Swap(float a, float b);
Swap_float_float;
void Swap(float a, float b);
Swap_float_float;
咱们能够这样去理解,先重命名函数,再去调用函数。
数组的定义,数组下标的范围,数组元素的使用方法(下标引用,指针引用)
菜鸟教程(数组) https://www.runoob.com/cplusplus/cpp-arrays.html
初始化字符数组的方法(注意字符串以’\0’结尾,多占一个字符)
发现了一个字符数组初始化的误区,而这个每每能致使比较严重的性能问题,分析介绍以下:
每每咱们在初始化一个字符 数组,大概有以下几种写法:
char array1[1024] = "";
char array2[1024] = {0};
char array3[1024] = {'\0'};
char array4[1024];
array4[0] = '\0';
但这四种写法,其实表明含义不一样,看起来前三种写法只是将array的第一个字符置为0,其实前三种在gcc编译时,都是调用了memset来将整个array置为0,若是这个array很长,其实也会致使性能问题。我写了一个简单的小程序编译生成test,objdump了一 下,执行“objdump -S test”能够看下面的代码:
1 int main() { 2 400698: 55 push %rbp 3 400699: 48 89 e5 mov %rsp,%rbp 4 40069c: 48 81 ec 00 10 00 00 sub $0x1000,%rsp 5 char array1[1024] = ""; 6 4006a3: 0f b6 05 42 01 00 00 movzbl 322(%rip),%eax # 4007ec <_IO_stdin_used+0x4> 7 4006aa: 88 85 00 fc ff ff mov %al,0xfffffffffffffc00(%rbp) 8 4006b0: 48 8d bd 01 fc ff ff lea 0xfffffffffffffc01(%rbp),%rdi 9 4006b7: ba ff 03 00 00 mov $0x3ff,%edx 10 4006bc: be 00 00 00 00 mov $0x0,%esi 11 4006c1: e8 fa fe ff ff callq 4005c0 <memset@plt> //调用了memset 12 13 char array2[1024] = {0}; 14 4006c6: 48 8d bd 00 f8 ff ff lea 0xfffffffffffff800(%rbp),%rdi 15 4006cd: ba 00 04 00 00 mov $0x400,%edx 16 4006d2: be 00 00 00 00 mov $0x0,%esi 17 4006d7: e8 e4 fe ff ff callq 4005c0 <memset@plt> //调用了memset 18 19 char array3[1024] = {'\0'}; 20 4006dc: 48 8d bd 00 f4 ff ff lea 0xfffffffffffff400(%rbp),%rdi 21 4006e3: ba 00 04 00 00 mov $0x400,%edx 22 4006e8: be 00 00 00 00 mov $0x0,%esi 23 4006ed: e8 ce fe ff ff callq 4005c0 <memset@plt> //调用了memset 24 25 char array4[1024]; 26 array4[0] = '\0'; 27 4006f2: c6 85 00 f0 ff ff 00 movb $0x0,0xfffffffffffff000(%rbp) 28 29 return 0; 30 4006f9: b8 00 00 00 00 mov $0x0,%eax 31 }
因此,对这四种写法,实际执行的代码解释以下:
char array1[1024] = ""; //第11行,调用memset将1023个字符置为0
char array2[1024] = {0}; //第17行,调用memset将1024个字符置为0
char array3[1024] = {'\0'}; //第23行,调用memset将1024个字符置为0
char array4[1024];
array4[0] = '\0'; //只是将第一个字符置为0
而对于字符数组,每每只是做为一个字符串的临时缓冲区使用,没有必要将整个数组置为0,因此第四种写法每每就能达到初始化的目的。建议使用第四种写法来初始化一个字符数组,这样能节约不少性能消耗。
转载需注明来源:http://www.cnblogs.com/yczcc/p/7595099.html
引用的创建方法
1. 引用基本用法
引用是c++对c的重要扩充。在c/c++中指针的做用基本都是同样的,可是c++增长了另一种给函数传递地址的途径,这就是按引用传递(pass-by-reference),它也存在于其余一些编程语言中,并非c++的发明。
变量名实质上是一段连续内存空间的别名,是一个标号(门牌号)
程序中经过变量来申请并命名内存空间
经过变量的名字可使用存储空间
对一段连续的内存空间只能取一个别名吗? c++中新增了引用的概念,引用能够做为一个已定义变量的别名。 |
基本语法:
注意事项:
&在此不是求地址运算,而是起标识做用。
类型标识符是指目标变量的类型
必须在声明引用变量时进行初始化。
引用初始化以后不能改变。
不能有NULL引用。必须确保引用是和一块合法的存储单元关联。
能够创建对数组的引用。
//1. 认识引用
void test01(){
int a = 10;
//给变量a取一个别名b
int& b = a;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "------------" << endl;
//操做b就至关于操做a自己
b = 100;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "------------" << endl;
//一个变量能够有n个别名
int& c = a;
c = 200;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "c:" << c << endl;
cout << "------------" << endl;
//a,b,c的地址都是相同的
cout << "a:" << &a << endl;
cout << "b:" << &b << endl;
cout << "c:" << &c << endl;
}
//2. 使用引用注意事项
void test02(){
//1) 引用必须初始化
//int& ref; //报错:必须初始化引用
//2) 引用一旦初始化,不能改变引用
int a = 10;
int b = 20;
int& ref = a;
ref = b; //不能改变引用
//3) 不能对数组创建引用
int arr[10];
//int& ref3[10] = arr;
}
//1. 创建数组引用方法一
typedef int ArrRef[10];
int arr[10];
ArrRef& aRef = arr;
for (int i = 0; i < 10;i ++){
aRef[i] = i+1;
}
for (int i = 0; i < 10;i++){
cout << arr[i] << " ";
}
cout << endl;
//2. 创建数组引用方法二
int(&f)[10] = arr;
for (int i = 0; i < 10; i++){
f[i] = i+10;
}
for (int i = 0; i < 10; i++){
cout << arr[i] << " ";
}
cout << endl;
2. 函数中的引用
最多见看见引用的地方是在函数参数和返回值中。当引用被用做函数参数的时,在函数内对任何引用的修改,将对还函数外的参数产生改变。固然,能够经过传递一个指针来作相同的事情,但引用具备更清晰的语法。
若是从函数中返回一个引用,必须像从函数中返回一个指针同样对待。当函数返回值时,引用关联的内存必定要存在。
//值传递
void ValueSwap(int m,int n){
int temp = m;
m = n;
n = temp;
}
//地址传递
void PointerSwap(int* m,int* n){
int temp = *m;
*m = *n;
*n = temp;
}
//引用传递
void ReferenceSwap(int& m,int& n){
int temp = m;
m = n;
n = temp;
}
void test(){
int a = 10;
int b = 20;
//值传递
ValueSwap(a, b);
cout << "a:" << a << " b:" << b << endl;
//地址传递
PointerSwap(&a, &b);
cout << "a:" << a << " b:" << b << endl;
//引用传递
ReferenceSwap(a, b);
cout << "a:" << a << " b:" << b << endl;
}
经过引用参数产生的效果同按地址传递是同样的。引用的语法更清楚简单:
1) 函数调用时传递的实参没必要加“&”符
2) 在被调函数中没必要在参数前加“*”符
引用做为其它变量的别名而存在,所以在一些场合能够代替指针。C++主张用引用传递取代地址传递的方式,由于引用语法容易且不易出错。
不能返回局部变量的引用。
函数当左值,必须返回引用。
//返回局部变量引用
int& TestFun01(){
int a = 10; //局部变量
return a;
}
//返回静态变量引用
int& TestFunc02(){
static int a = 20;
cout << "static int a : " << a << endl;
return a;
}
int main(){
//不能返回局部变量的引用
int& ret01 = TestFun01();
//若是函数作左值,那么必须返回引用
TestFunc02();
TestFunc02() = 100;
TestFunc02();
return EXIT_SUCCESS;
}
3. 引用的本质
引用的本质在c++内部实现是一个指针常量.
Type& ref = val; // Type* const ref = &val; |
c++编译器在编译过程当中使用常指针做为引用的内部实现,所以引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见。
//发现是引用,转换为 int* const ref = &a;
void testFunc(int& ref){
ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
int a = 10;
int& aRef = a; //自动转换为 int* const aRef = &a;这也能说明引用为何必须初始化
aRef = 20; //内部发现aRef是引用,自动帮咱们转换为: *aRef = 20;
cout << "a:" << a << endl;
cout << "aRef:" << aRef << endl;
testFunc(a);
return EXIT_SUCCESS;
}
4. 指针引用
在c语言中若是想改变一个指针的指向而不是它所指向的内容,函数声明可能这样:
给指针变量取一个别名。
Type* pointer = NULL; Type*& = pointer; |
Type* pointer = NULL; Type*& = pointer;
struct Teacher{
int mAge;
};
//指针间接修改teacher的年龄
void AllocateAndInitByPointer(Teacher** teacher){
*teacher = (Teacher*)malloc(sizeof(Teacher));
(*teacher)->mAge = 200;
}
//引用修改teacher年龄
void AllocateAndInitByReference(Teacher*& teacher){
teacher->mAge = 300;
}
void test(){
//建立Teacher
Teacher* teacher = NULL;
//指针间接赋值
AllocateAndInitByPointer(&teacher);
cout << "AllocateAndInitByPointer:" << teacher->mAge << endl;
//引用赋值,将teacher自己传到ChangeAgeByReference函数中
AllocateAndInitByReference(teacher);
cout << "AllocateAndInitByReference:" << teacher->mAge << endl;
free(teacher);
}
对于c++中的定义那个,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。
5. 常量引用
常量引用的定义格式:
常量引用注意:
1.字面量不能赋给引用,可是能够赋给const引用
2.const修饰的引用,不能修改。
void test01(){
int a = 100;
const int& aRef = a; //此时aRef就是a
//aRef = 200; 不能经过aRef的值
a = 100; //OK
cout << "a:" << a << endl;
cout << "aRef:" << aRef << endl;
}
void test02(){
//不能把一个字面量赋给引用
//int& ref = 100;
//可是能够把一个字面量赋给常引用
const int& ref = 100; //int temp = 200; const int& ret = temp;
}
[const引用使用场景]
常量引用主要用在函数的形参,尤为是类的拷贝/复制构造函数。
将函数的形参定义为常量引用的好处:
- 引用不产生新的变量,减小形参与实参传递时的开销。
- 因为引用可能致使实参随形参改变而改变,将其定义为常量引用能够消除这种反作用。
若是但愿实参随着形参的改变而改变,那么使用通常的引用,若是不但愿实参随着形参改变,那么使用常引用。
//const int& param防止函数中意外修改数据
void ShowVal(const int& param){
cout << "param:" << param << endl;
}
面向对象中成员访问标签的使用方法:公有,私有,保护,注意三者的区别
C++中 public,protected, private 访问标号小结
第一:private, public, protected 访问标号的访问范围。
private:只能由1.该类中的函数、2.其友元函数访问。
不能被任何其余访问,该类的对象也不能访问。
protected:能够被1.该类中的函数、2.子类的函数、以及3.其友元函数访问。
但不能被该类的对象访问。
public:能够被1.该类中的函数、2.子类的函数、3.其友元函数访问,也能够由4.该类的对象访问。
注:友元函数包括3种:设为友元的普通的非成员函数;设为友元的其余类的成员函数;设为友元类中的全部成员函数。
第二:类的继承后方法属性变化。
private 属性不可以被继承。
使用private继承,父类的protected和public属性在子类中变为private;
使用protected继承,父类的protected和public属性在子类中变为protected;
使用public继承,父类中的protected和public属性不发生改变;
静态数据成员初始化方法(注意,若是定义时没赋初值,对于静态成员会初始化为0)
静态成员的初始化:
与全局对象同样对于静态数据成员在程序中也只能提供一个定义,这意味着静态数据成员的初始化不该该被放在头文件中而应该放在含有类的非inline函数定义的文件中。
能在类中初始化的成员只有一种,那就是静态常量成员。
class A
{
private:
static const int count = 0; // 静态常量成员能够在类内初始化
};
结论:
- 静态常量数据成员能够在类内初始化(即类内声明的同时初始化),也能够在类外,即类的实现文件中初始化,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化;
- 静态很是量数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化;
- 非静态的常量数据成员不能在类内初始化,也不能在构造函数中初始化,而只能且必须在构造函数的初始化列表中初始化;
- 非静态的很是量数据成员不能在类内初始化,能够在构造函数中初始化,也能够在构造函数的初始化列表中初始化;
构造函数、拷贝构造函数、析构函数的使用方法
菜鸟教程(构造&析构) https://www.runoob.com/cplusplus/cpp-constructor-destructor.html
虚函数的定义及使用方法(搞清楚虚函数的使用场景)
在某基类中声明为 virtual 并在一个或多个派生类中被从新定 义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,经过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
虚函数定义:简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的做用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差别,而采用不一样的策略。
虚函数的做用:用同一个调用形式,既能调用派生类又能调用基类的同名函数。
虚函数的使用方法是:
1. 在基类用virtual声明成员函数为虚函数。
这样就能够在派生类中从新定义此函数,为它赋予新的功能,并能方便地被调用。在类外定义虚函数时,没必要再加virtual。
2. 在派生类中从新定义此函数,要求函数名、函数类型、函数参数个数和类型所有与基类的虚函数相同,并根据派生类的须要从新定义函数体。
C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。所以在派生类从新声明该虚函数时,能够加virtual,也能够不加,但习惯上通常在每一层声明该函数时都加virtual,使程序更加清晰。若是在派生类中没有对基类的虚函数从新定义,则派生类简单地继承其直接基类的虚函数。
3. 定义一个指向基类对象的指针变量,并使它指向同一类族中须要调用该函数的对象。
4. 经过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。
经过虚函数与指向基类对象的指针变量的配合使用,就能方便地调用同一类族中不一样类的同名函数,只要先用基类指针指向便可。若是指针不断地指向同一类族中不一样类的对象,就能不断地调用这些对象中的同名函数。这就如同前面说的,不断地告诉出租车司机要去的目的地,而后司机把你送到你要去的地方。
虚基类的使用方法,为何要使用虚基类
在类的继承中,若是咱们遇到这种状况:
“B和C同时继承A,而B和C都被D继承”
在此时,假如A中有一个函数fun()固然同时被B和C继承,而D按理说继承了B和C,同时也应该能调用fun()函数。这一调用就有问题了,究竟是要调用B中的fun()函数仍是调用C中的fun()函数呢?在C++中,有两种方法实现调用:
(注意:这两种方法效果是不一样的)
- 使用做用域标识符来惟一表示它们好比:B::fun()
- 另外一种方法是定义虚基类,使派生类中只保留一份拷贝。
继承有哪几种方式,每种方式的特色是什么?


若是在定义派生类时在基类前没有指定访问标签,默认状况下是哪一种继承的方式?
private 私有继承
输入输出流对象的使用方法
new, delete语句的使用方法
对于计算机程序设计而言,变量和对象在内存中的分配都是编译器在编译程序时安排好的,这带来了极大的不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象。对于不能肯定须要占用多少内存的状况,动态内存分配解决了这个问题。
new和delete运算符是用于动态分配和撤销内存的运算符。
1、new用法
1.开辟单变量地址空间
使用new运算符时必须已知数据类型,new运算符会向系统堆区申请足够的存储空间,若是申请成功,就返回该内存块的首地址,若是申请不成功,则返回零值。
new运算符返回的是一个指向所分配类型变量(对象)的指针。对所建立的变量或对象,都是经过该指针来间接操做的,而动态建立的对象自己没有标识符名。
通常使用格式:
格式1:指针变量名=new 类型标识符;
格式2:指针变量名=new 类型标识符(初始值);
格式3:指针变量名=new 类型标识符 [内存单元个数];
说明:格式1和格式2都是申请分配某一数据类型所占字节数的内存空间;可是格式2在内存分配成功后,同时将一初值存放到该内存单元中;而格式3可同时分配若干个内存单元,至关于造成一个动态数组。例如:
1)new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址。int *a = new int 即为将一个int类型的地址赋值给整型指针a
2)int *a = new int(5) 做用同上,可是同时将整数空间赋值为5
2.开辟数组空间
对于数组进行动态分配的格式为:
指针变量名=new 类型名[下标表达式];
delete [ ] 指向该数组的指针变量名;
两式中的方括号是很是重要的,二者必须配对使用,若是delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不完全的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。
delete []的方括号中不须要填数组元素数,系统自知。即便写了,编译器也忽略。
请注意“下标表达式”没必要是常量表达式,即它的值没必要在编译时肯定,能够在运行时肯定。
一维: int *a = new int[100]; //开辟一个大小为100的整型数组空间
二维: int **a = new int[5][6]
三维及其以上:依此类推.
通常用法: new 类型 (初值)
2、delete用法
1. 删除单变量地址空间
int *a = new int;
delete a; //释放单个int的空间
2. 删除数组空间
int *a = new int[5];
delete []a; //释放int数组空间
3、使用注意事项
1. new 和delete都是内建的操做符,语言自己所固定了,没法从新定制,想要定制new和delete的行为,徒劳无功的行为。
2. 动态分配失败,则返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
3. 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p自己(指针p自己并无撤销,它本身仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针。
4. 内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。若是new返回的指针值丢失,则所分配的堆空间没法回收,称内存泄漏,同一空间重复释放也是危险的,由于该空间可能已另分配,因此必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
5. 动态分配的变量或对象的生命期。咱们也称堆空间为自由空间(free store),但必须记住释放该对象所占堆空间,并只能释放一次,在函数内创建,而在函数外释放,每每会出错。
6. 要访问new所开辟的结构体空间,没法直接经过变量名进行,只能经过赋值的指针进行访问。
用new和delete能够动态开辟和撤销地址空间。在编程序时,若用完一个变量(通常是暂时存储的数据),下次须要再用,但却又想省去从新初始化的功夫,能够在每次开始使用时开辟一个空间,在用完后撤销它。
什么函数会有this指针?友元函数是成员函数吗?友元的做用是什么?
2、编程题(60分)
基本循环(1题)
编写程序,计算下式的值 1-3+5-7….-99
编写程序,计算并输出半径r = 1到r = 20之间半径为整数的圆形的面积,直到面积大于100为止
水仙花数怎么计算,完数怎么计算等,具体看一下循环章节的练习题
数组使用方法(1题)
有以下矩阵,编写三个函数,分别计算每行的和、每列的和,矩阵中最大元素所在的位置
编写函数,求矩阵Y的值
字符串操做(1题)
给定一个字符串,写函数判断字符串中每一个数字字符出现的频率
给定一个字符串,写函数判断字符串中是否包含另外一个字符串
给定一个字符串,写函数判断该字符串是否为回文字串(正读反读均相同)
面向对象编程(1题) ---- 多态章节