文章目录
#include <iostream>
using namespace std;
int result(int, int); // 函数原型声明
const in k = 2;
struct Point { // 结构体
int x, y;
};
int main() {
int z(0), b(50); // 初始化,相当于int z = 0; int b = 50;
Point a;
cout<< "输入两个整数(以空格区分):"; // 注意:在cout中的字符串不能加空格,否则会编译失败;<< 之间可以有空格
cin>>a.x>>a.y;
z = (a.x + a.y) * k;
z = result(z, b);
cout<<"result:"<<z;
return 0;
}
int result(int x, int y) {
return x + y;
}
1 混合型语言
C++程序以 .cpp
作为文件扩展名
2 使用输出和输入对象
当程序需要执行键盘输入时,可以使用提取操作符 ">>"
从cin输入流中提取字符;当程序需要在屏幕上显示输出时,可以使用插入操作符 "<<"
向cout输出流中插入字符。
语句 cout<<endl
和 cout<<"\n"
的功能都是换行。
3 使用命名空间
C语言一直使用扩展名 ".h"
标识头文件,新的C++标准引入新的标准类库的头文件载入方式,即省略".h"。不过,这时必须同时使用下述语句:
using namespace std;
如果仍然使用C库中的头文件,则需要使用扩展名".h"形式,例如 <math.h>
和 <stdio.h>
。如果使用C++提供的头文件,则不需要使用扩展名".h",例如 <string>
。
4 对象的定义及初始化
int z(0); // 等同于int z = 0;
int b(50); // 等同于int b = 50;
5 函数原型及返回值
函数都需要有类型说明。C++程序使用变量的基本规则是:必须先声明,后使用,对函数调用也是如此。
int result(int, int); // 函数原型声明
int result(int a, int b) { // 函数定义
return a + b;
}
z = result(z, b); // 函数使用
6 const修饰符和预处理程序
在C++中,建议使用const代替宏定义。用关键字 const
修饰的标识符是一类特殊的常量,称为符号常量,或const变量。
因为被const修饰的变量的值在程序中不能被修改,所以在声明符号常量时,必须对符号常量进行初始化,除非这个变量是用extern修饰的外部变量:
const int i = 8; // 不可变常量,必须初始化
const int d; // 错误
extern const int d; // 可以
引入头文件是使用双引号还是尖括号,其含义并不一样。
-
采用尖括号引用系统提供的包含文件,C++编译系统将首先在C++语言系统设定的目录中寻找包含文件,如果没有找到,就到指定的目录中去寻找。
-
采用双引号引用自己定义的包含文件(一般都放在自己指定的目录中),这将通知C++编译器在用户当前目录下或指定目录下寻找包含文件。
#include "e:\prog\myfile.h" // 通知编译器在指定目录查找头文件
#includ <iostream> // 通知编译器在系统设定目录先查找头文件
using namespace std;
7 使用函数重载
C++允许为同一个函数定义几个版本,从而使一个函数名具有多种功能,这成为函数重载。
#include <iostream>
using namespace std;
int max(int, int); // 2个整型参数的函数原型
int max(int, int, int); // 3个整型参数的函数原型
int main() {
cout << max(35, 25) << "," << max(25, 39, 35) < endl;
}
int max(int m1, int m2) {
return (m1 > m2) ? m1 : m2;
}
int max(int m1, int m2, int m3) {
int t = max(m1, m2);
return max(t, m3);
}
8 动态分配内存
在使用指针时,如果不使用对象地址初始化指针,可以自己给它分配地址。申请方式如下:
new 类型名[size]; // 申请可以存储size个该数据类型的对象
不再使用时,"delete 指针名"即可释放已经申请的存储空间。
#include <iostream>
using namespace std;
int main() {
double* p;
p = new double[3]; // 分配内存
for (int i = 0; i < 3; i++) {
cin >> *(p + i);
}
for (int i = 0; i < 3; i++) {
cout << *(p + i);
}
delete p; // 释放内存
return 0;
}
Point结构指针分配内存:
指针名 = new 结构名; // 分配内存
delete 指针名 // 释放内存
p = new Point;
delete p;
9 引用
C++语言支持引用。简单地讲,就是为现有的对象起个“别名”。别名的地址就是原来对象的地址,选定命名时使用“引用”运算符 "&"
,再选用数据类型与之匹配。
数据类型& 别名 = 对象名;
int& a = x; // 注意:对象x必须先初始化,声明中的符号"&"的位置无关紧要
#include <iostream>
using namespace std;
int main() {
int x = 56;
int& a = x; // 声明a是x的引用,a和x的地址相同
int& r = a; // 声明r是a的引用,r和a的地址相同,即和x的地址也相同
cout<< "x = " << x
<< ", &x = " << &x
<< ", a = " << a
<< ", &a = " << &a
<< ", r = " << r
<< ", &r = " << &r << endl;
r = 25;
cout<< "x = " << x
<< ", &x = " << &x
<< ", a = " << a
<< ", &a = " << &a
<< ", r = " << r
<< ", &r = " << &r << endl;
return 0;
}
"int& a = x;"
是声明不是定义,不需要为a分配内存,别名和正名所代表的是同一个地址。既然引用作为正名的别名而使用,所以对别名的改动实际上就是对正名的改动,输出结果:
x = 56, &x = 006FFD60, a = 56, &a = 006FFD60, r = 56, &r = 006FFD60
x = 25, &x = 006FFD60, a = 25, &a = 006FFD60, r = 25, &r = 006FFD60
所谓“引用”就是将一个新标识符和一块已经存在的存储区相关联。
不能有空引用。在程序中必须要确保引用是和一块正确的存储区域关联。
引用通常用于函数的参数表中或者作为函数的返回值。
- 引用只是作为一种标识对象的手段,不能直接声明对数组的引用,也不能声明引用的引用:
int& &r = x; // 错误
虽然不能直接定义对数组的引用,但可以间接地建立对数组的引用:
// 该例子使用array会编译出错
#include <iostream>
using namespaece std;
typedef double array[4]; // 定义了一个double数组类型array标识符,可以用它来定义数组的引用
int main() {
array a = {12, 34, 56, 78};
array& b = a;
a[2] = 100;
for (int i = 0; i < 4; i++) {
cout << b[i] << " ";
}
return 0;
}
- 引用的作用与指针有相似之处,它会对内存地址上存在的变量进行修改,但它不占用新的地址,从而节省开销。引用与指针除了使用形式上的不同外,在本质上也有所区别:指针是低级的直接操作内存地址的机制,指针功能强大但使用不慎极易产生错误。在C++语言中,引用则是较高级地封装了指针的特性,它不直接操作内存地址,不可以由强类型转换而得,因而具有较高的安全性,也不容易产生由于使用指针而常常产生的那些不易察觉的错误。
10 对指针使用const限定符
- 指向常量的指针
// *p是常量,不能将*p的值更改
const int *p;
- 常量指针
int x = 5;
int* const p = &x; // 指针地址p不可变
- 指向常量的常量指针
int x = 2;
const int* const p = &x; // *P和p都不可变
11 泛型算法应用于普通数组
要输出数组的内容、对数组进行升幂排序、反转数组的内容、复制数组的内容等操作,需要包含头文件 <algorithm>
。要对数组进行降幂排序和检索,需要包含头文件 <functional>
。有用到ostream_iterator的函数,要添加头文件 <iterator>
。
11.1 数组内容反转
reverse(a, a + Len); // 数组元素反转排列
11.2 复制数组的内容
copy(a, a + Len, b); // 将数组a的内容原样复制到数组b
reverse_copy(a, a + Len, b); // 将数组a的内容以逆向方式复制到数组b
11.3 数组升幂排序
sort(a, a + Len); // 默认排序方式是升幂排序
11.4 数组降幂排序
sort(b, b + Len, greater<Type>()); // 数组降幂排序
11.5 查找数组内容
find(a, a + Len, value); // 查找数组a内是否存在值为value的元素,这个函数返回的是位置指针
Type* x = find(a, a + Len, value);
if (x == a + Len) {
cout << "没有value";
} else {
cout << "有值为value的数组元素";
}
11.6 输出数组的内容
// 可将ostream_iterator简单的理解为输出流操作符,<Type>表示数组元素的数据类型,例如int或char等。
// 本语句将数组内容按正向方式送往屏幕,输出方式是将每个元素与“字符串”的内容组合在一起输出
copy(a, a + Len, ostream_iterator<Type>(cout, "字符串"));
// 逆向输出
reverse_copy(a, a + Len, ostream_iterator<Type>(cout, "字符串"));
algorithm例子
#include <iostream>
// 输出数组内容、对数组进行升幂排序、反转数组的内容、复制数组的内容等操作
#include <algorithm>
#include <iterator>
using namespace std;
int main() {
double a[] = {1.1, 4.4, 3.3, 2.2}, b[4];
// 正向输出数组
copy(a, a + 4, ostream_iterator<double>(cout, " "));
cout << endl;
// 反向输出数组
reverse_copy(a, a + 4, ostream_iterator<double>(cout, " "));
cout << endl;
// 将数组a复制到数组b
copy(a, a + 4, b);
copy(b, b + 4, ostream_iterator<double>(cout, " "));
cout << endl;
// 升幂排序
sort(a, a + 4);
copy(a, a + 4, ostream_iterator<double>(cout, " "));
cout << endl;
reverse_copy(a, a + 4, b);
copy(b, b + 4, ostream_iterator<double>(cout, " "));
cout << endl;
return 0;
}
functional例子
#include <iostream>
#include <algorithm>
// 数组升降幂排序和检索
#include <functional>
#include <iterator>
using namespace std;
int main() {
double a[] = {1.1, 4.4, 3.3, 2.2};
// 升幂排序后输出
sort(a, a + 4);
copy(a, a + 4, ostream_iterator<double>(cout, " "));
cout << endl;
// 降幂排序后输出
sort(a, a + 4, greater<double>());
copy(a, a + 4, ostream_iterator<double>(cout, " "));
cout << endl;
double* x = find(a, a + 4, 4.4);
if (x == a + 4) {
cout << "not found 4.4";
} else {
cout << "found it";
}
cout << endl;
x = find(a, a + 4, 4.8);
if (x == a + 4) {
cout << "not found 4.8";
} else {
cout << "found it";
}
return 0;
}
注意:在操作字符串数组时要注意尾部还有一个结束符"\0",正向复制copy()不需要复制结束符,但逆向复制reverse_copy()不能将这个结束符逆向复制,否则字符串的第一位变成结束标志,使其称为空字符串。
12 输出数组的内容
C++提供了两种格式控制方式:一种是使用 iso_base
类提供的接口;另一种是使用一种称为操控符的特殊函数,它的特点是可直接包含在输出和输入表达式中,因此更为方便。不带形式参数的操控符定义在头文件 <iostream>
中,带形式参数的操控符定义在头文件 <iomanip>
中。使用它们时,一是要正确包含它们,二是只有与符号"<<“或”>>"连接时才起作用,三是无参数的操控符函数不能带有 "()"
号。