0%

C++ Primer personal answer chapter03

《C++ Primer》第五版习题个人答案

练习3.1

使用恰当的using 声明重做 1.4.1节和2.6.2节的练习。

1.4.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  #include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int a=0,b=0;
cout<<"please input two numbers:"<<endl;
cin>>a>>b;
int min = std::min(a,b);
int max = std::max(a,b);
while (max>=min)
{
cout<<max<<endl;
max--;
}
return 0;
}

2.6.2

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
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;

};

int main()
{
Sales_data data1,data2;
double price=0;
cin>>data1.bookNo>>data1.units_sold>>price;
data1.revenue=data1.units_sold*price;
cin>>data2.bookNo>>data2.units_sold>>price;
data2.revenue=data2.units_sold*price;

if (data1.bookNo==data2.bookNo)
{
unsigned totalCnt=data1.units_sold+data2.units_sold;
double totalRevenue=data1.revenue+data2.revenue;
cout<<data1.bookNo<<" "<<totalCnt<<" "<<totalRevenue<<" ";
return 0;
}
else
{
cerr<<"Data must refer to the same ISBN"<<endl;
return -1;
}
return 0;
}

练习3.2

编写一段程序从标准输入中一次读入一行,然后修改该程序使其一次读入一个词。

一次读入一行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{ string line;
while (getline(cin,line))
{
cout<<line<<endl;
}
return 0;
}

一次读入一个词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{ string line;
while (cin>>line)
{
cout<<line<<endl;
}
return 0;
}

练习3.3

请说明string类的输入运算符和getline函数分别是如何处理空白字符的。

>>运算符在读取std::string时会跳过前导空白字符,并在遇到下一个空白字符时停止读取。
std::getline函数会读取整行数据,包括空格,直到遇到换行符为止。

练习3.4

编写一段程序读取两个字符串,比较其是否相等并输出结果。如果不相等,输出比较大的那个字符串。改写上述程序,比较输入的两个字符串是否等长,如果不等长,输出长度较大的那个字符串。

输出比较大的

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
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string str1,str2;
while (cin>>str1>>str2)
{
if (str1 == str2)
{
cout<< "两字符串相等" <<endl;
}
if (str1 > str2)
{
cout<<str1<<endl;
}
if (str2 > str1)
{
cout<<str2<<endl;
}



}
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
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string str1,str2;
while (cin>>str1>>str2)
{
if (str1.size() == str2.size())
{
cout<< "两字符串等长" <<endl;
}
if (str1.size() > str2.size())
{
cout<<str1<<endl;
}
if (str2.size() > str1.size())
{
cout<<str2<<endl;
}



}
return 0;
}

练习3.5

编写一段程序从标准输入中读入多个字符串并将他们连接起来,输出连接成的大字符串。然后修改上述程序,用空格把输入的多个字符串分割开来。

未隔开的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{
string input,result;
while (cin>>input)
{
result+=input;
}
cout<<result<<endl;
return 0;
}

隔开的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{
string input,result;
while (cin>>input)
{
result += input +" ";
}
cout<<result<<endl;
return 0;
}

练习3.6

编写一段程序,使用范围for语句将字符串内所有字符用X代替。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
main()
{
string s("EastWinters");
for (auto &c : s)
{
c = 'X';
}
cout<<s<<endl;
return 0;
}

练习3.7

就上一题完成的程序而言,如果将循环控制的变量设置为char将发生什么?先估计一下结果,然后实际编程进行验证。

在使用 char 的情况下,循环变量 c 被显式声明为 char 类型,因此在循环体内可以直接修改字符的值。修改为char不会对程序有影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
main()
{
string s("EastWinters");
for (char &c : s)
{
c = 'X';
}
cout<<s<<endl;
return 0;
}

练习3.8

分别用while循环和传统for循环重写第一题的程序,你觉得哪种形式更好呢?为什么?

3.8.1(使用下标执行迭代)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
main()
{
string s("EastWinters");
decltype(s.size()) index = 0;
while (index != s.size() && !isspace(s[index]))
{
s[index] = 'X';
++index;
}
cout<<s<<endl;
return 0;
}

3.8.2(使用下标执行迭代)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
main()
{
string s("EastWinters");
for (decltype(s.size()) index = 0;index != s.size() && !isspace(s[index]); ++index)
{
s[index] = 'X';
}
cout<<s<<endl;
return 0;
}

for循环相较于while循环更为简洁。

练习3.9

下面的程序有何作用?它合法吗?如果不合法?为什么?

1
2
string s;
cout << s[0] << endl;

不合法。如果string s是一个空字符串且没有进行初始化,那么访问s[0]将会导致未定义行为。因为在这种情况下,字符串s是空的,没有任何字符可供访问,所以访问s[0]将超出字符串的有效索引范围。

练习3.10

编写一段程序,读入一个包含标点符号的字符串,将标点符号去除后输出字符串剩余的部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
#include <cctype>
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string s("East,Winters!");
string str;
for (auto a:s )
{
if (!ispunct(a))
{
str += a;
}
}
cout<<str<<endl;
return 0;
}

练习3.11

下面的范围for语句合法吗?如果合法,c的类型是什么?

1
2
const string s = "Keep out!";
for(auto &c : s){ /* ... */ }

要根据for循环中的代码来看是否合法,c是string 对象中字符的引用,s是常量。因此如果for循环中的代码重新给c赋值就会非法,如果不改变c的值,那么合法。

练习3.12

下列vector对象的定义有不正确的吗?如果有,请指出来。对于正确的,描述其执行结果;对于不正确的,说明其错误的原因。

1
2
3
vector<vector<int>> ivec;         // 在C++11当中合法
vector<string> svec = ivec; // 不合法,类型不一样
vector<string> svec(10, "null"); // 合法(花括号为C++11中引入的统一列表初始化标准)

练习3.13

下列的vector对象各包含多少个元素?这些元素的值分别是多少?

1
2
3
4
5
6
7
vector<int> v1;         // 0个元素
vector<int> v2(10); // 10个元素,值为0
vector<int> v3(10, 42); // 10个元素,值为42
vector<int> v4{ 10 }; // 1个元素,值为10
vector<int> v5{ 10, 42 }; // 2个元素,值为10、42
vector<string> v6{ 10 }; // 10个元素,空字符串
vector<string> v7{ 10, "hi" }; // 10个元素,值为“hi”

练习3.14

编写一段程序,用cin读入一组整数并把它们存入一个vector对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include<vector>
using std::cin;
using std::vector;
int main()
{
vector<int> numbers;
int num;
while (cin >> num)
{
numbers.push_back(num);
}
return 0;
}

练习3.15

改写上题程序,不过这次读入的是字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include<string>
#include<vector>
using std::cin;
using std::string;
using std::vector;
int main()
{
string word;
vector<string> text;
while (cin>>word)
{
text.push_back(word);
}
return 0;

}

练习3.16

编写一段程序,把练习3.13中vector对象的容量和具体内容输出出来

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;

int main()
{
vector<int> v1; // size:0, no values.
vector<int> v2(10); // size:10, value:0
vector<int> v3(10, 42); // size:10, value:42
vector<int> v4{ 10 }; // size:1, value:10
vector<int> v5{ 10, 42 }; // size:2, value:10, 42
vector<string> v6{ 10 }; // size:10, value:""
vector<string> v7{ 10, "hi" }; // size:10, value:"hi"
cout<<"v1容量为:"<<v1.size()<<endl;
cout<<"v2容量为:"<<v2.size()<<endl;
cout<<"v3容量为:"<<v3.size()<<endl;
cout<<"v4容量为:"<<v4.size()<<endl;
cout<<"v5容量为:"<<v5.size()<<endl;
cout<<"v6容量为:"<<v6.size()<<endl;
cout<<"v7容量为:"<<v7.size()<<endl;

cout<<"v1的内容为:";
for (auto a : v1)
{
cout << a << " ";
}
cout<<endl;

cout<<"v2的内容为:";
for (auto a : v2)
{
cout << a << " ";
}
cout<<endl;

cout<<"v3的内容为:";
for (auto a : v3)
{
cout << a << " ";
}
cout<<endl;

cout<<"v4的内容为:";
for (auto a : v4)
{
cout << a << " ";
}
cout<<endl;

cout<<"v5的内容为:";
for (auto a : v5)
{
cout << a << " ";
}
cout<<endl;

cout<<"v6的内容为:";
for (auto a : v6)
{
cout << a << " ";
}
cout<<endl;

cout<<"v7的内容为:";
for (auto a : v7)
{
cout << a << " ";
}
cout<<endl;

return 0;
}

练习3.17

从cin读入一组词并把它们存入一个vector对象,然后设法把所有词都改为大写形式。输出改变后的结果,每个词占一行。

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
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;
int main()
{
string word;
vector<string> words;
while (cin>>word)
{
words.push_back(word);
}
for (auto & w1 : words)
{
for (auto & w2 : w1)
{
w2=toupper(w2);

}
}
for (const auto w:words)
{
cout<<w<<endl;
}
return 0;
}

练习3.18

下面的程序合法吗?如果不合法,你准备如何修改?

1
2
vector<int> ivec;
ivec[0] = 42;

不合法。应改为:

1
ivec.push_back(42);

ivec还是一个空的vector,没有任何元素。使用下标访问时,必须确保该位置已经存在元素,否则会导致未定义行为。
在使用下标访问 vector 的元素之前,必须确保 vector 中已经包含足够的元素。可以通过 resizepush_back 方法来添加元素。这样可以避免未定义行为,并确保程序的合法性和正确性。

练习3.19

如果想定义一个含有10个元素的vector对象,所有元素的值都是42,请例举三种不同的实现方法,哪种方式更好呢?

如下三种:

1
2
3
4
5
std::vector<int> ivec(10, 42);  // 定义一个大小为10的vector,每个元素值为42
ivec.assign(10, 42); // 使用assign方法将vector大小设为10,每个元素值为42
vector<int> ivec3;
for (int i = 0; i < 10; ++i)
ivec3.push_back(42);// 使用循环和push_back方法向vector添加10个元素,值为42

第一种方式最好,代码简洁明了,而且执行效率高,因为它一次性分配所需的内存,并且不需要额外的操作。

练习3.20

读入一组整数并把他们存入一个vector对象,将每对相邻整数的和输出出来。改写你的程序,这次要求先输出第一个和最后一个元素的和,接着输入第二个和倒数第二个元素的和,以此类推。

输出相邻整数的和

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
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;

int main()
{
vector<int> numbers;
int num;
cout<<"请输入一组整数:"<<endl;
while (cin>>num)
{
numbers.push_back(num);
}
cout<<"相邻整数的和分别为:"<<endl;
for (size_t i = 0; i < numbers.size()-1; ++i)
{
cout<<numbers[i]+numbers[i+1]<<endl;
}
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
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;

int main()
{
vector<int> numbers;
int num;
cout<<"请输入一组整数:"<<endl;
while (cin>>num)
{
numbers.push_back(num);
}
cout<<"首尾对应元素的和分别为:"<<endl;
for (size_t i = 0; i < numbers.size()/2; ++i)
{
cout<<numbers[i]+numbers[numbers.size()-1-i]<<endl;
}
//如果数量是奇数,则输出中间的值
if (numbers.size()%2 !=0)
{
cout<<numbers[numbers.size()/2]<<endl;
}

return 0;

}

练习3.21

请使用迭代器重做3.3.3节的第一个练习。

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;

int main()
{
vector<int> v1; // size:0, no values.
vector<int> v2(10); // size:10, value:0
vector<int> v3(10, 42); // size:10, value:42
vector<int> v4{ 10 }; // size:1, value:10
vector<int> v5{ 10, 42 }; // size:2, value:10, 42
vector<string> v6{ 10 }; // size:10, value:""
vector<string> v7{ 10, "hi" }; // size:10, value:"hi"
cout<<"v1容量为:"<<v1.size()<<endl;
cout<<"v2容量为:"<<v2.size()<<endl;
cout<<"v3容量为:"<<v3.size()<<endl;
cout<<"v4容量为:"<<v4.size()<<endl;
cout<<"v5容量为:"<<v5.size()<<endl;
cout<<"v6容量为:"<<v6.size()<<endl;
cout<<"v7容量为:"<<v7.size()<<endl;

cout<<"v1的内容为:";
for (auto it = v1.begin();it != v1.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v2的内容为:";
for (auto it = v2.begin();it != v2.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v3的内容为:";
for (auto it = v3.begin();it != v3.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v4的内容为:";
for (auto it = v4.begin();it != v4.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v5的内容为:";
for (auto it = v5.begin();it != v5.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v6的内容为:";
for (auto it = v6.begin();it != v6.end();++it)
{
cout << *it << " ";
}
cout<<endl;

cout<<"v7的内容为:";
for (auto it = v7.begin();it != v7.end();++it)
{
cout << *it << " ";
}
cout<<endl;

return 0;
}

练习3.22

修改之前那个输出text第一段的程序,首先把text的第一段全部改成大写形式,然后输出它。

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
#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::string;
int main()
{
string word;
vector<string> words;
while (cin>>word)
{
words.push_back(word);
}
for (auto it = words.begin();it != words.end();++it)//遍历vector<string>中的字符串
{
if (!it->empty())
{
for (auto char_it = it->begin(); char_it != it-> end();++char_it)//遍历字符串中的每一个字符
{
*char_it = toupper(*char_it);
}
}

}
for (auto it = words.begin();it != words.end();++it)
{
cout<<*it<<endl;
}
return 0;
}

练习3.23

编写一段程序,创建一个含有10个整数的vector对象,然后使用迭代器将所有元素的值都变成原来的两倍。输出vector对象的内容,检验程序是否正确。

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

using std::cout;
using std::endl;
using std::vector;
int main()
{

vector<int> numbers = {0,1,2,3,4,5,6,7,8,9};
for (auto num = numbers.begin();num !=numbers.end();++num)
{
*num *=2;
}
for (auto num = numbers.begin();num !=numbers.end();++num)
{
cout<<*num<<" ";
}
cout<<endl;
return 0;
}

练习3.24

请使用迭代器重做3.3.3节的最后一个练习。

输出相邻整数的和

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

using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::vector;

int main()
{
vector<int> numbers;
int num;
while (cin >> num)
{
numbers.push_back(num);
}
for (auto it = numbers.begin();it !=numbers.end()-1;++it)
{
cout<<(*it+*(it+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
#include<iostream>
#include<string>
#include<vector>

using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::vector;

int main()
{
vector<int> numbers;
int num;
while (cin >> num)
{
numbers.push_back(num);
}
auto front_it = numbers.begin();
auto back_it = numbers.end()-1;
while (front_it <= back_it)
{
cout<<(*front_it+*back_it)<<" ";
++front_it;
--back_it;
}

return 0;
}

练习3.25

3.3.3节划分分数段的程序是使用下标运算符实现的,请利用迭代器改写该程序实现完全相同的功能。

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
#include<iostream>
#include<vector>
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main()
{
vector<unsigned>scores(11,0);
unsigned grade;
while (cin >> grade)
{
if (grade <= 100)
{
++*(scores.begin()+grade/10);
}

}
for (auto a : scores)
{
cout << a <<" ";
}
cout << endl;
return 0;
}

练习3.26

在100页的二分搜索程序中,为什么用的是 mid = beg + (end - beg) / 2, 而非 mid = (beg + end) / 2 ; ?
迭代器是一种抽象的指针,用于遍历容器中的元素。即使对于随机访问迭代器,beginend是迭代器对象,而非数值类型,不能直接相加。begin + end 这种操作在语法和语义上都不成立。

练习3.27

假设txt_size 是一个无参函数,它的返回值是int。请回答下列哪个定义是非法的,为什么?

1
2
3
4
5
unsigned buf_size = 1024;
(a) int ia[buf_size];
(b) int ia[4 * 7 - 14];
(c) int ia[txt_size()];
(d) char st[11] = "fundamental";
  • (a) 不合法,因为buf_size不是常量表达式。
  • (b) 合法,4 * 7 - 14计算结果是14,这是一个常量表达式。
  • (c) 不合法,因为txt_size()返回的值在编译时未知,不是常量表达式。
  • (d) 非法。数组的大小应该是12。

练习3.28

下列数组中元素的值是什么?

1
2
3
4
5
6
string sa[10];
int ia[10];
int main() {
string sa2[10];
int ia2[10];
}
1
2
3
4
5
6
string sa[10];  // 全局变量,std::string 类型,自动初始化为空字符串
int ia[10]; // 全局变量,int 类型,自动初始化为 0
int main() {
string sa2[10]; // 局部变量,std::string 类型,自动调用默认构造函数,初始化为空字符串
int ia2[10]; // 局部变量,int 类型,未初始化,包含未定义值
}

练习3.29

相比于vector 来说,数组有哪些缺点,请例举一些。

  • 大小在定义时必须确定且不可改变。数组的大小一旦声明,就不能动态调整。这会导致内存浪费或空间不足的问题。
  • 没有内置的边界检查,访问数组时越界会导致未定义行为,可能引发严重的错误和安全漏洞。
  • 需要手动管理内存,使用动态数组时必须显式地分配和释放内存,这容易引起内存泄漏和其他管理问题。
  • 无法直接获取数组的大小,必须通过其他变量记录或者显式计算。
  • 不保证自动初始化,未初始化的数组元素会包含未定义的值。

练习3.30

指出下面代码中的索引错误。

1
2
3
4
constexpr size_t array_size = 10;
int ia[array_size];
for (size_t ix = 1; ix <= array_size; ++ix)
ia[ix] = ix;

错误出现在 for 循环的条件部分 ix <= array_size。C++ 数组的索引是从 0 开始的,因此有效的索引范围是 0array_size - 1。但是,当前循环条件会导致索引 ix1array_size,即 110。当 ix 等于 array_size (即 10) 时,ia[ix] 会超出数组的范围(ia[10]),导致越界访问。

练习3.31

编写一段程序,定义一个含有10个int的数组,令每个元素的值就是其下标值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
int main()
{
int ia[]={0,1,2,3,4,5,6,7,8,9};
for (size_t i = 0; i < 10; i++)
{
ia[i] = i ;
}
for (size_t i = 0; i < 10; i++)
{
std::cout << ia[i] << " ";
}
return 0;
}

练习3.32

将上一题刚刚创建的数组拷贝给另一数组。利用vector重写程序,实现类似的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<vector>
using std::vector;
using std::cout;
int main()
{
int ia[]={0,1,2,3,4,5,6,7,8,9};
vector<int> vector1(10);
for (int i = 0; i < 10; i++)
{
vector1[i] = i ;
}
vector<int> vector2 = vector1;
for (int i = 0; i < 10; i++)
{
cout << vector2[i] << " ";
}
return 0;
}

练习3.33

对于104页的程序来说,如果不初始化scores将会发生什么?
未初始化的 unsigned 变量在 C++ 中会包含一个未定义的值(未定义行为)。这意味着该变量的内容是不可预测的,并且在不同的运行环境或不同的编译器设置下可能会有不同的结果。

练习3.34

假定p1 和 p2 都指向同一个数组中的元素,则下面程序的功能是什么?什么情况下该程序是非法的?

1
p1 += p2 - p1;

这段代码的功能是“将 p1 移动 p2 - p1 个位置”,也就是将 p1 移动到 p2 所指向的位置。
非法情况 :
1.未定义行为:如果 p1p2 不指向同一个数组中的元素,或者计算 p2 - p1 导致 p1 指向数组范围之外的位置。
2.跨越数组边界:如果 p1p2 的操作结果超出了数组的边界,程序也会出现未定义行为。

练习3.35

编写一段程序,利用指针将数组中的元素置为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
using std::cout;
using std::endl;
int main()
{
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr;
for ( int i = 0; i < 10; ++i)
{
cout<< arr[i] <<" ";
}
cout << endl;
for (int i = 0; i < 10; ++i)
{
*(p+i) = 0;
cout<< arr[i] <<" ";
}
cout << endl;
return 0;
}

练习3.36

编写一段程序,比较两个数组是否相等。再写一段程序,比较两个vector对象是否相等。

比较两个数组

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>
using std::cout;
using std::endl;
bool compareArrays(const int* arr1,const int* arr2,size_t size)
{
for (size_t i = 0; i < size; ++i)
{
if (arr1[i] != arr2[i])
{
return false;
}

}
return true;
}
int main()
{
constexpr size_t arraySize = 5;
int arr1[arraySize] = {1,2,3,4,5};
int arr2[arraySize] = {1,2,3,4,5};
if (compareArrays(arr1,arr2,arraySize))
{
std::cout << "arr1 and arr2 are equal." << std::endl;
}
else
{
std::cout << "arr1 and arr2 are not equal." << std::endl;
}
return 0;
}

比较两个vector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<vector>
using std::vector;
using std::cout;
using std::endl;
int main()
{ vector<int> vec1 = {1,2,3,4,5};
vector<int> vec2 = {1,2,3,4,5};
if (vec1 ==vec2)
{
std::cout << "vec1 and vec2 are equal." << std::endl;
}
else
{
std::cout << "vec1 and vec2 are equal." << std::endl;
}
return 0;
}

练习3.37

下面的程序是何含义,程序的输出结果是什么?

1
2
3
4
5
6
const char ca[] = { 'h', 'e', 'l', 'l', 'o' };
const char *cp = ca;
while (*cp) {
cout << *cp << endl;
++cp;
}

这个程序的含义是遍历一个字符数组并输出其中的每个字符。
由于数组 ca 没有以空字符 \0 结束,while (*cp) 条件不会在 o 之后立即终止,程序可能会继续读取并输出数组之后的内存内容,导致未定义行为。这种情况下,程序的行为可能是不确定的,可能会输出垃圾字符或导致程序崩溃。

练习3.38

在本节中我们提到,将两个指针相加不但是非法的,而且也没有什么意义。请问为什么两个指针相加没有意义?
两个指针相加没有意义且是非法的,因为指针本质上是内存地址的表示,加法操作在这个上下文中没有定义明确的结果和用途。这种操作既没有逻辑基础,也不符合编程语言的规范和约束。

练习3.39

编写一段程序,比较两个string对象。再编写一段程序,比较两个C风格字符串的内容。

比较两个string

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

using std::string;
using std::cout;
using std::endl;

int main()
{
string s1 = "aaaaa";
string s2 = "bbbbb";
if (s1 == s2)
{
cout<<"equal"<<endl;
}
else
{
cout<<"not equal"<<endl;
}
return 0;
}

比较两个C风格字符串

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

using std::cout;
using std::endl;

int main()
{
char* str1 = "aaaaa";
char* str2 = "bbbbb";
int result = strcmp(str1,str2);
if (result == 0)
{
cout<<"equal"<<endl;
}
else
{
cout<<"not equal"<<endl;
}
return 0;
}

练习3.40

编写一段程序,定义两个字符数组并用字符串字面值初始化它们;接着再定义一个字符数组存放前面两个数组连接后的结果。使用strcpy和strcat把前两个数组的内容拷贝到第三个数组当中。

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

using std::cout;
using std::endl;

const char ca1[] = "aaa";
const char ca2[] = "bbb";
char ca3[10];
int main()
{
strcpy(ca3,ca1);
strcat(ca3," ");
strcat(ca3,ca2);
cout << ca3 << endl;
return 0;
}

练习3.41

编写一段程序,用整型数组初始化一个vector对象。

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

using std::cout;
using std::endl;
using std::vector;
using std::begin;
using std::end;

int main()
{
int int_arr[] = {0,1,2,3,4,5};
vector<int> ivec(begin(int_arr), end(int_arr));
for ( auto i : ivec )
{
cout << i << " ";
}
return 0;
}

练习3.42

编写一段程序,将含有整数元素的vector对象拷贝给一个整型数组。

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

using std::cout;
using std::endl;
using std::vector;

int main()
{
vector<int> ivec = {0,1,2,3,4,5};
int arr[ivec.size()];
std::copy(ivec.begin(), ivec.end(), arr);
for (size_t i = 0; i < ivec.size(); ++i)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}

练习3.43

编写3个不同版本的程序,令其均能输出ia的元素。版本1使用范围for语句管理迭代过程;版本2和版本3都使用普通for语句,其中版本2要求使用下标运算符,版本3要求使用指针。此外,在所有3个版本的程序中都要直接写出数据类型,而不能使用类型别名、auto关键字和decltype关键字。

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
41
42
43
#include<iostream>

using std::cout;
using std::endl;
int main()
{
int ia[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
for (int (&row)[4] : ia)
{
for(int & elem : row)
{
cout << elem << " ";
}

}
cout << endl;

for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
cout << ia[i][j] << " ";
}

}
cout << endl;

int (*p)[4] = ia;
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
cout << *(*(p + i) +j) << " ";
}

}
cout << endl;
return 0;
}

练习3.44

改写上一个练习中的程序,使用类型别名来代替循环控制变量的类型。

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
41
42
43
44
#include<iostream>

using std::cout;
using std::endl;
int main()
{
int ia[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
using int_array = int[4];
for (int_array&row : ia)
{
for(int & elem : row)
{
cout << elem << " ";
}

}
cout << endl;

for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
cout << ia[i][j] << " ";
}

}
cout << endl;

int_array *p = ia;
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
cout << *(*(p + i) +j) << " ";
}

}
cout << endl;
return 0;
}

练习3.45

再一次改写程序,这次使用auto关键字。

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
41
42
43
44
#include<iostream>

using std::cout;
using std::endl;
int main()
{
int ia[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
using int_array = int[4];
for (auto &row : ia)
{
for(auto & elem : row)
{
cout << elem << " ";
}

}
cout << endl;

for (auto i = 0; i < 3; ++i)
{
for (auto j = 0; j < 4; ++j)
{
cout << ia[i][j] << " ";
}

}
cout << endl;

int_array *p = ia;
for (auto i = 0; i < 3; ++i)
{
for (auto j = 0; j < 4; ++j)
{
cout << *(*(p + i) +j) << " ";
}

}
cout << endl;
return 0;
}