C++编程基础
1. 简单的C++程序实例
1.1. 第一个C++程序 输出Hello world
1
2
3 #include
4 using namespace std;
5 int main() {
6 cout << "hello world!\n";
7 return 0;
8 }
1.2. 第1.5个C++程序 输入名字,输出招呼
1 #include
2 #include
3 using namespace std;
4 int main()
5 {
6 string user_name;
7 cout << "Please enter your first name: ";
8 cin >> user_name;
9 cout << '\n"
10 << "Hello, "
11 << user_name
12 << " ... and goodbye!\n";
13 return 0;
14 }
1.3. 第二个C++程序 求两数之和
1
2 #include
3 using namespace std;
4 int main() {
5 int a, b;
6 cin >> a >> b;
7 cout << a + b << endl;
8 }
1.4. 第三个C++程序 求两个数中较大的一个
1
2 #include
3 using namespace std;
4
5 int max(int, int);
6
7 int main() {
8 int a, b;
9
10 cin >> a >> b;
11 cout << max(a, b) << endl;
12 }
13
14 int max(int x, int y) {
15 if(x>y)
16 return x;
17 else
18 return y;
19 }
3. 注释
C++支持两种风格的注释(Comment):C风格/*…*/和C++风格//
1
2 int main() {
3 int i = 0;
4 }
注意:C风格的注释不能嵌套(比如:/* …/*…*/…*/)
1
2 int main() {
3 int age;
4 }
注意:不要在注释和字符串以外输入中文,尤其是中文标点
CategoryCpp
5. 名字空间
在大型程序(尤其是由很多人一起撰写的程序)中,常常遇到不同的变量、函数等取了同样的名字而造成名字的冲突。例如:
1
2 extern int inflag;
3 main() {
4 inflag = 30;
5 }
这个问题在C++中,可以使用名字空间(namespace)来解决冲突:
1 namespace mfc {
2 int inflag;
3
4 }
5
1 namespace owl {
2 int inflag;
3
4 }
1 int main() {
2 mfc::inflag = 3;
3 owl::inflag = -823;
4 }
::被称作域操作符,可以用来访问某个名字空间中的成员。此外还可以用来访问与局部变量同名的全局变量,比如
1 int i;
2 int main() {
3 int i = 0;
4 i = i +1;
5 ::i = i;
6 }
更多名字空间的例子:
1 namespace mfc {
2 int inflag;
3 void function(int a) {
4
5 }
6 typedef unsigned short WORD;
7 struct Teacher{
8
9 };
10 class Student {
11
12 };
13 #define PI 3.14159
14 }
注意:宏定义不受名字空间限制
访问名字空间中的成员:
1 int main() {
2 mfc::inflag = 10;
3 mfc::function(mfc::inflag);
4 mfc::WORD w;
5 struct mfc::Teacher t;
6 class mfc::Student s;
7 double p = PI;
8 }
简化名字空间成员的访问:using declaration
1 int main() {
2 using mfc::inflag;
3 inflag = 3;
4 mfc::function( inflag );
5 }
更多的简化访问:using direction
1 int main() {
2 using namespace mfc;
3 inflag = 3;
4 function(inflag);
5 WORD w;
6 owl::inflag = 10;
7 }
CategoryCpp
6. C++的头文件
C语言中的标准头文件有.h,在C++中仍然可以使用
C语言的头文件在C++中有另一种方式:前面加c后面去掉.h
C++中增加的标准头文件没有.h
所有C++中新增的标准库,都放在名字空间std中。比如
1 #include
2 int main() {
3 std::cout << "hello, world!";
4 using namespace std;
5 cout << "hello, world!";
6 }
使用.h头文件包含的C语言标准库不在std名字空间中
1 #include
2 int main() {
3 printf("hello, world!");
4 }
使用没有.h的头文件包含的C语言库,在std名字空间中
1 #include
2 int main() {
3 std::printf("hello world!");
4 using namespace std;
5 printf("hello world!");
6 }
7. C++输入输出
- C语言输入输出(printf/scanf)在C++中仍然可以使用
- C++输入输出新增了一种输入输出方式,它更容易使用、可扩展输入输出系统,不需要格式化串。它包括:
- C++流:cin, cout , cerr
C++输入输出操作符:<<和>>
用法:
1 #include
2 int main() {
3 int i, j;
4 std::cin >> i >> j;
5 std::cout << "say hello " << i << " times!";
6 }
更多例子:
1 #include
2 using namespace std;
3 int main() {
4 int val, sum = 0;
5 cout << "Enter next number: ";
6 while ( cin >> val) {
7 sum += val;
8 cout << "Enter next number: ";
9 }
10 cout << "Sum of all values: " << sum << '\n';
11 return 0;
12 }
格式控制:使用操纵符
- 输出控制:
- 控制进制dec, hex, oct
- 刷新流endl, flush
- 对齐left, right
- 精度setprecision(n)
- 宽度setw(n)
- 输入控制:
例子:
1 int main() {
2 int i = 4, j = 6, k = 8;
3 char c = '!';
4 cout << i << c << endl
5 << j << c << '\n'<<flush
6 << k << c <<endl;
7 }
1 int main() {
2 int i = 92;
3 cout << "i = " << i << " (decimal)\n";
4 cout << "i = " << oct << i << "(octal)\n";
5 cout << "i = " << hex << i << " (hexadecimal)\n";
6 cout << "i = " << dec << i << " (decimal)\n";
7 }
如果最后一句改为这样,输出会怎样?
cout << "i = " << i << " (hexadecimal)\n";
1 int main() {
2 int i;
3 for( i = 1; i <= 1000; i *= 10)
4 cout << setw(6) << i << '\n';
5 cout << setw(6);
6 for( i = 1; i <= 1000; i *=10)
7 cout << i << '\n';
8 }
1 int main() {
2 int a = 5, b = 43, c = 104;
3 cout << left << setw(10) << “Karen”
4 << right << setw(6) << a << '\n';
5 cout << left << setw(10) << “Ben”
6 << right << setw(6) << b << '\n';
7 cout << left << setw(10) << “Patricia”
8 << right << setw(6) << c << '\n';
9 }
1 #include
2 using namespace std;
3 int main() {
4 char c;
5 cin >> noskipws;
6 while( cin >> c )
7 cout << c;
8 return 0;
9 }
注意:不要同时使用C和C++输入输出库
8. 定义常量
C语言定义常量的办法
1 #define PI 3.14
2 #define MAX 100
3 float a[ MAX ];
这种宏定义的方法容易带来一些错误。
在C++中新增的了代替宏的一些语法。包括C++定义常量的办法:
1 const double PI = 3.14;
2 const int MAX = 100;
3 float a[ MAX ];
const变量必须在定义时初始化,不能赋值
1 const int a = 5;
2 const int b;
3 a = 10;
4
注:const在C语言中也可以使用,但是C++中对const的用法作了扩充。
用const修饰指针的时候,可以放在指针定义的两个不同位置:
1 int main() {
2 int i = 10;
3 int j = 11;
4 const int *p = &i;
5 p = &j;
6 (*p)++;
7 int * const q = &i;
8 (*q)++;
9 q = &j;
10 const int * const r = &i;
11 (*r)++;
12 r = &j;
13 }
10. 强制类型转换
在C语言中,使用如下风格的类型转换。这种C语言风格的转换方式在C++中仍然可以使用。
1 int m = 1, n = 3;
2 cout << (double)m / (double)n
在C++中,有一种新的转换方式:
1 int m = 1, n = 3;
2 cout << double(1)/double(3);
这种风格只能做简单类型的类型转换,不能进行复合类型的转换(比如指针类型)
在C++中,还有一种新的转换方式:
static_cast<>() 静态转换
const_cast<>() 去掉指针的常数性
reinterpret_cast<>() 指针类型强制转换
dynamic_cast<>() 多态类型强制转换
1 int hits = 10, at_bats = 78;
2 double average = static_cast<double>(hits) / static_cast<double>(at_bats);
const_cast去除指针指向对象的const性
1 const int a = 0;
2 const int *p = &a;
3 *p = 3;
4 *(int *)p = 5;
5 *const_cast<int *>(p) = 5;
6 const_cast<int>(a) = 5;
7
reinterpret_cast将一个类型的指针转换成另一个类型
1 char array[] = "hello world";
2 char *p1 = array;
3 int *p2 = (int *)p1;
4 int *p2 = reinterpret_cast<int *>(p1);
5 const char *p3 = "hello world;
6 int *p4 = reinterpret_cast<int *>(p3);
7 int *p4 = reinterpret_cast<int *> ( const_cast<char *>(p3) );
dynamic_cast在多态中使用,后面再介绍。
练习,在下面x的地方填入适当的转换运算:
1 int hits = 315, at_bats = 13;
2 float average = x_cast<float>(hits) / x_cast<float>(at_bats);
3
4 const int * find(int val, const int * t, int n);
5 int a[] = {2, 4, 6};
6 int *ptr = x_cast<int *>(find(4, a, 3));
7
8 float f = -6.9072;
9 unsigned char *p = x_cast<unsigned char*>(&f);
CategoryCpp
11. 定义变量
C语言只能在一个语句块开始的地方定义变量
1 void function(int x) {
2 int n;
3 if(x) {
4 float d;
5 d= PI*3;
6 }
7 n = 5;
8 int y = 3;
9 }
而在C++中没有这样的没有限制,而且还可以在for初始化部分定义变量。比如
1 void reverse_and_print(int a[], int size) {
2 for(int i = 0; i < size; i++)
3 a[i] = 2*i;
4 int temp;
5 for(int i = 0; i < size/2; i++) {
6 temp = a[i];
7 a[i] = a[size-1-i];
8 a[size-1-i] = temp;
9 }
10 for(int i = 0; i < size; i++)
11 cout << a[i] << '\n';
12 }
12. 结构体
定义结构体变量时可以省略关键字struct
struct point {
double x, y;
};
struct point p1; // C/C++
point p2; // C++
此外,C++的结构体内部可以包含函数,这样的结构体就变成了类。在后面会详细介绍。
13. C++内存分配
C++中可以使用C语言内存分配malloc/free/realloc/calloc等,最常用的是malloc和free。
1 #include
2 int main() {
3 int * p = (int *) malloc(sizeof(int));
4 *p = 10;
5 free(p);
6 p = (int *) malloc(sizeof(int) * 5);
7 *p = 5;
8 p[1] = 6;
9 p[4] = 9
10 free(p);
11 }
C++中还可以用特有的内存分配方法:new/delete。比如:
1 int main() {
2 int *p1 = new int;
3 int *p2 = new int [5];
4 int *p3 = new int (5);
5 delete p1;
6 delete[] p2;
7 delete p3;
8 }
注意:
注意:
1 int *p1 = new int;
2 int *p2 = new int;
3 delete p1, p2;
4
C++中的一些新类型
2. bool类型
C语言用int表示布尔型,非0为真,0为假。为了方便使用,C程序中常常定义如下的宏:
1 #define BOOL int
2 #define FALSE 0
3 #define TRUE 1
4
在C++语言中,新增了布尔型作为内置的基本类型。bool、true、false是三个新增的关键字。
1 bool flag = false;
2 if(flag)
3 cout << "flag is true";
4 else
5 cout << "flag is false";
C++中所有的关系运算和逻辑运算的结果都是bool类型的。逻辑运算的操作数需要bool类型的,if、while、for等循环控制语句中的条件表达式也要求是bool类型的。
为了保证与C语言兼容性,在C++中int与bool的可以自动相互转换:
int型 => bool型 => int型
0 => false => 0
非0 => true => 1
比如
if(1) { // int型的1自动转换为bool型的true
cout << (0 || 3>4) << endl; // 参与||运算的操作数0被自动转换为false
cout << true + false << endl; // 参与+运算的操作数true和false自动被转换为1和0
}
指针类型可以自动转换成bool类型:
指针 => bool型
空指针 => false
非空指针 => true
比如
int *p = (int*)malloc(sizeof(int));
if(p) {
cout << "malloc succeeded!";
}
CategoryCpp
3. string类型
在C语言中,用char* 和char[ ]表示字符串。用string.h头文件中定义的strlen, strcpy, strcat, strstr等函数来对字符串进行操作。
1 #include
2 int main() {
3 char s1[20] = "";
4 char s2[20] = "hello world";
5 strcpy(s1, s2);
6 strcat(s2, "!!!");
7 scanf("%s", s1);
8 printf("%d", strlen(s1));
9 printf("%s", s2);
10 }
C语言的字符串的缺点是内存需要手动管理,容易出错。比如
1 #include
2 int main() {
3 char s1[10] = "hello";
4 char s2[10] = "world"
5 strcat(s1, s2);
6 strcpy(s1, "hello world");
7 scanf("%s", s1);
8 }
为避免使用字符串的麻烦和潜在的错误,在C++中,用string类来存放和操作字符串。它定义在string头文件中。
1 #include
2 using namespace std;
3 int main() {
4 string s1;
5 string s2 = "Bravo";
6 string s3 = s2;
7 string s4 (10, 'x');
8 s1 = "Bravo";
9 cout << s1 << s1.length() << endl;
10 cout << s1[0];
11 cin >> s1;
12 s3 = s1 + s2;
13 }
4. vector向量
在c语言中表示多个相同的东西,使用数组,比如:
1 #include
2 int main() {
3 int array[10];
4 int i = 0;
5 int x;
6 while(1) {
7 scanf("%d", &x);
8 if( x == 0)
9 break;
10 array[i++] = x;
11 }
12 }
但是C语言中的数组存在的问题是:
- 数组的大小是编译时确定的,不能动态变化;
- 对数组的下标没有越界检查,常常导致内存错误。
在C++中可以使用vector代替数组。
1 #include
2 #include
3 using namespace std;
4 int main() {
5 vector<int> array(10);
6 int i = 0;
7 int x;
8 while(1) {
9 cin >> x;
10 if( x == 0)
11 break;
12 array[i++] = x;
13 }
14 }
但是上面这个程序和C语言的版本一样,由于vector的大小是一开始就确定的,所以还是有可能发生数组溢出。我们可以进一步改写:
1 #include
2 #include
3 using namespace std;
4
5 int main() {
6 int x;
7 vector<int> array;
8 while(1) {
9 cin >> x;
10 if(x == 0)
11 break;
12 array.push_back(x);
13 }
14 for(int i = 0; i < array.size(); i++)
15 cout << array[i] << '\t';
16 }
此处,array的大小是动态变化的,一开始是0,随着append不断的增大。
5. 文件
将内容写到一个文件:
1 #include
2 #include
3 using namespace std;
4 int main() {
5 string name;
6 cin >> name;
7 ofstream outfile("data.txt");
8 if(outfile)
9 outfile << "hello" << name;
10
11 else
12 cerr << "Oops! File cannot be opened!";
13
14 }
从某个文件读数据:
1 #include
2 #include
3 #include
4 using namespace std;
5 int main() {
6 char c;
7 ifstream infile("in.txt");
8 ofstream outfile("out.txt");
9 while(infile >> c) {
10 outfile << toupper(c);
11 }
12 }
CategoryCpp