C++ 中的复合类型

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;

int main()
{
short months[12] = {0}; // 第 1 个为 0,其他的也是 0
// short months[12]{0}; // 可以省略等号
// short months[] = {0, 1, 2, 3}; // 自动计算数组长度
// short months[12] = {1}; // 第一个元素为 1,其他为 0
cout << sizeof(months) << endl;
cout << sizeof(months[0]) << endl;
int i = 0;
for (; i < 12; i++)
{
cout << months[i] << "\t";
}
cout << endl;
return 0;
}

对数组进行赋值,除了使用下标逐个赋值,还可以使用大括号,在初始时赋值,提供的元素不够的话,未被提供的数组元素会被设置为0。

vector 和 array

字符串

C风格字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

using namespace std;

int main()
{
char cat[] = {'c', 'a', 't', '\0'};
char dog[] = {'d', 'o', 'g'};
// char dog[] = "dog"; // 不必如此麻烦的声明字符串,并且会自动加上 \0
// char dog[] = "do" "g"; // 拼接字符串
cout << dog << endl;
cout << cat << endl;
return 0;
}

计算字符串长度函数:strlen()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cstring>

using namespace std;

int main()
{
char name[] = "Sheng Wenzeng";
cout << "请输入您的姓名:" << endl;
cin >> name;
cout << strlen(name) << endl;
name[5] = '\0';
cout << name << endl;
return 0;
}

一个经典错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char name[initSize] = {};
char food[initSize] = {};
cout << "请输入您的姓名:" << endl;
cin >> name;
cout << "-----输入完成------" << endl;
cout << name << endl;
cout << "请输入您喜欢的食物:" << endl;
cin >> food;
cout << "-----输入完成------" << endl;
cout << food << endl;
return 0;
}

还没来得及输入食物,就输出了空格后的名:

1
2
3
4
5
6
7
请输入您的姓名:
Sheng Wenzeng
-----输入完成------
Sheng
请输入您喜欢的食物:
-----输入完成------
Wenzeng

cin使用空白(空格,制表符,换行符)来确定字符串的结束位置,所以只读取了一个单词,剩下的单词在输入队列中,并直接被下一个cin读取了。

解决方案是使用getline()函数,面向行的输入,它使用换行符来确定字符串的结束位置。

这样就解决了上面的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char name[initSize] = {};
char food[initSize] = {};
cout << "请输入您的姓名:" << endl;
cin.getline(name, initSize);
cout << "-----输入完成------" << endl;
cout << name << endl;
cout << "请输入您喜欢的食物:" << endl;
cin >> food;
cout << "-----输入完成------" << endl;
cout << food << endl;
return 0;
}
1
2
3
4
5
6
7
8
请输入您的姓名:
Sheng Wenzeng
-----输入完成------
Sheng Wenzeng
请输入您喜欢的食物:
rice
-----输入完成------
rice

cin.getline()有第三个参数,这将在第17章学到。

事实上,还有另一个函数,名为cin.get(),也可以解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char name[initSize] = {};
char food[initSize] = {};
cout << "请输入您的姓名:" << endl;
cin.get(name, initSize);
cout << "-----输入完成------" << endl;
cout << name << endl;
cout << "请输入您喜欢的食物:" << endl;
// cin >> food;
cin.get(food, initSize);
cout << "-----输入完成------" << endl;
cout << food << endl;
return 0;
}

但是随即出现了新问题:

1
2
3
4
5
6
7
请输入您的姓名:
Sheng Wenzeng
-----输入完成------
Sheng Wenzeng
请输入您喜欢的食物:
-----输入完成------

可以看到,第二个输入没有给我们输入的机会,直接回车为空。

这也是get()geiline()的区别,getline()会读取最后的换行符并抛弃,但是get不会读取换行符,而是会将换行符留在输入队列中。

解决方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char name[initSize] = {};
char food[initSize] = {};
cout << "请输入您的姓名:" << endl;
cin.get(name, initSize);
cin.get();
// cin.get(name, initSize).get(); // 或者使用连续调用
cout << "-----输入完成------" << endl;
cout << name << endl;
cout << "请输入您喜欢的食物:" << endl;
// cin >> food;
cin.get(food, initSize);
cout << "-----输入完成------" << endl;
cout << food << endl;
return 0;
}

也就是加了一个get()去读取留在输入队列中的换行符。

问题来了,既然get()这么麻烦,还要get()干什么?用getline()不就好了吗?

首先,老式实现没有getline(),其次get()是为了解决知道停止读取的原因,是已经读取了整行,还是因为数组已经被填满了?

如果是已经读取了整行,那么此时输入队列中还有一个换行符,否则,就是数组被填满了,这将在第17章详细讨论。

空行和其他问题

get()getline()读取空行,会发生什么?

会设置失效位,导致接下来的输入被阻断,此时可以使用cin.clear()来恢复输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char name[initSize] = {};
char food[initSize] = {};
cout << "请输入您的姓名:" << endl;
cin.get(name, initSize);
cin.clear();
cin.get();
cout << "-----输入完成------" << endl;
cout << name << endl;
cout << "请输入您喜欢的食物:" << endl;
cin.get(food, initSize);
cout << "-----输入完成------" << endl;
cout << food << endl;
return 0;
}

如果输入的长度长于给定的数组长度,会发生什么?

getline()get()会把剩下的字符留在输入队列中,getline()还会设置失效位。后面会介绍(5、6、17)

混合输入字符串和数字

混合输入数字和面向行的字符串会导致问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char year[initSize] = {};
char name[initSize] = {};
cout << "请输入出生年份:" << endl;
cin >> year;
cout << "-----输入完成------" << endl;
cout << year << endl;

cout << "请输入您的姓名:" << endl;
cin.get(name, initSize);
cout << "-----输入完成------" << endl;
cout << name << endl;
return 0;
}
1
2
3
4
5
6
7
请输入出生年份:
2001
-----输入完成------
2001
请输入您的姓名:
-----输入完成------

这段代码不会给用户输入姓名的机会,输入出生年份回车后就会直接完成全部的输入,原因是输入数字后,换行符被留在了输入队列。(cin()以空白(空格,制表符,换行符)来确定字符串的结束位置,所以只读取了一个单词,剩下的单词(包括这个空白)在输入队列中,并直接被下一个cin()读取了。)

解决方法也很简单,使用cin.get()读取掉这个空白符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;

int main()
{
const int initSize = 20;
char year[initSize] = {};
char name[initSize] = {};
cout << "请输入出生年份:" << endl;
(cin >> year).get();
cout << "-----输入完成------" << endl;
cout << year << endl;

cout << "请输入您的姓名:" << endl;
cin.get(name, initSize);
cout << "-----输入完成------" << endl;
cout << name << endl;
return 0;
}
1
2
3
4
5
6
7
8
请输入出生年份:
2001
-----输入完成------
2001
请输入您的姓名:
Sheng Wenzeng
-----输入完成------
Sheng Wenzeng

C++风格string

能够把一个string赋值给另一个string

一些方法

  • strcpy()
  • strcat()

结构

一个结构,存储多种类型的数据,如同时存储intfloat

结构声明及初始化示例一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;
// 一个名为直角三角形的结构
struct rightTriangle {
string name;
// 两个直角边长
float a{};
float b{};
};

int main() {
rightTriangle triangle;
triangle.name = "triangle";
triangle.a = 1;
triangle.b = 1;

rightTriangle rightTriangle{"rightTriangle", 1, 1};
return 0;
}

共用体

共用体可以存储不同的数据类型,但是同一时间只能存储一种。共用体的长度是最大成员的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <string>

using namespace std;
// 直角三角形的边
union rightTriangle_edge {
// 两个直角边长
int a_int;
float a_float;
// 不能初始化,因为同一时间只能有一种类型
// int a_int{};
// float a_float{};
};
// 直角三角形
struct rightTriangle {
string name;
rightTriangle_edge edge_1;
rightTriangle_edge edge_2;
};

int main() {
// 让 rightTriangle_edge 存储 float
rightTriangle_edge edge_1{10L};
// 让 rightTriangle_edge 存储 int
rightTriangle_edge edge_2{10};

rightTriangle triangle_1{"triangle_1", 10, 10};
rightTriangle triangle_2{"triangle_2", 10, 10};
return 0;
}

匿名共用体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string>


using namespace std;

// 直角三角形的边
union rightTriangle_edge {
// 两个直角边长
int a_int;
double a_double;
};

// 直角三角形
struct rightTriangle {
string name;
rightTriangle_edge edge_1;
rightTriangle_edge edge_2;
};

int main() {
// 让 rightTriangle_edge 存储 double
rightTriangle_edge edge_1{};
edge_1.a_double = 10.0;
// 让 rightTriangle_edge 存储 int
rightTriangle_edge edge_2{};
edge_2.a_int = 10;

cout << edge_1.a_double << endl << edge_2.a_int << endl;


rightTriangle triangle_1;
triangle_1.name = "triangle_1";
triangle_1.edge_1.a_int = 10;
triangle_1.edge_2.a_int = 10;
// 只能选择一个赋值,而不能直接初始化
// rightTriangle triangle_2{"triangle_2", 10L, 10L};
cout << triangle_1.edge_1.a_int << endl;
return 0;
}

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

using namespace std;

enum week {
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
};

int main() {
week week_begin;
week_begin = Sunday;
cout << week_begin;
return 0;
}

指针和自由存储空间

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×