C++ Primer 笔记+习题解答(三)

来源:互联网 发布:开淘宝母婴店流程 编辑:程序博客网 时间:2024/06/08 03:17

今天是第三篇笔记,其实写这个着实比较为难。一方面抄书没意思,但是另一方面感觉自己不总结怕学不好。今天是我回家第十天,但是才看了160页的书,进度的确比较慢。如果单纯的看书,一天30页没有问题,但是如果作总结,写习题,那么时间却显得那么仓促,加油自勉。

若有错误 请指正 谢谢

1.使用命名空间中的成员:

    格式: using namespace:: name;  其中name 是你要使用对象的名称。

using namespace::cout;using namespace::cin;
    使用命名空间中的每个名字都需要声明,不然哪来的cout,cin。

   tips: 头文件中不应该包含using 声明,不然会导致重复包含。

2.使用标准库类型:

    1.包含头文件,2.使用using 声明,3.可变长的字符序列.

     解释下2:

std::string str;//声明一个str 对象,但是string 是标准库中的,所以要用string 需要加上std::

  2.1 string 的初始化:

    书上介绍7种方式,无非就是直接初始化,拷贝初始化。圆括号,花括号,函数。

    举一个不常见的例子:

string str(10,'c')
    我把上面这个归结为函数初始化方法。10个字符c初始化str.

   概念:直接初始化(direct initialization),拷贝初始化(copy initialization)

   区分:看看是否使用等号。一般来说,单值初始化可以同用,多值初始化的时候一般用直接初始化。

例外:

string str=string(n,’c')
这个虽然是多值,但用的是拷贝初始化。

2.2 string 上进行的操作:

    1.[n]返回是引用,以前一直没仔细区分,今天提一下吧。

    2.cin>> 的截止符号是空白(空格,制表符,换行符)也称为白空格。

    3.getline(cin,s)函数的使用。函数的返回值是cin对象本身。函数读取的截止符号是换行符,故经常用getline 函数读取一行。而cin只是读取一个单词。

cin>>s;这个操作会忽略第一个有效字符前面的所以空白,并且以下一个空白作为截止标志。
读取不定律的string 对象:

while(cin>>str)//按词读取,以空白截止。while(getline(cin,s)) 因为getline 函数的返回值是一个对象,故可以在while循环的判读体内如此使用。//getline 是按行读取,结束标志是换行符,但是字符串中不包括换行符的。尤其的在后面的文件操作中会经常涉及。
    string::size_type 类型。vs2013中用typdeid函数检测出来的结果是unsigned int .

    string 和其他几个标准库类型都定义几种配套类型,便于使用。体现了标准库类型与机器无关的特性。也就是不依赖于平台吧。所以我上面检测到的是无符号整形,     但 是你的说不定是别的了,但一定是无符号的。

    用auto 或者decltype 进行类型推断,无需直接去声明。

    tips 不要混用带符号的和无符号的。比如:str.size()<-1 条件永远为成立。因为size函数的返回值类型是size_type.无符号的。那么带符号的的会进行转化。

    设计原则:在涉及标准库类型的时候目标就是像内置类型一样好用。

    string 相加。一个原则,+两侧至少 要有一个string 对象。关于运算符的更多知识下一节会具体介绍。

举个例子:

string str=str1+" a"+"b";//这个符号刚刚说的规则嘛?符合的。因为加好的结合性规定了从左到右结合,所以等价于:(str1+" a")+"b";
反面示例:

string str="a"+"b"+str1;//这个是嘛?不要用数学的想法来理解这个。刚刚上面说过了结合律。
字符串字面值无法直接相加!!字符串字面值的默认类型不是string!!

  2.3

    C++ 标准库中的头文件。如果由c继承而来,则在前面加前缀c,不存在.h

    cctype 中定义了一些库函数,用来配套处理字符。比如检测大小写,大小写转换。

    处理的关键是取出字符。可以用迭代器和下标运算符。

 1 .处理每个字符,使用 range for 语句处理每个字符,需要修改的请用引用类型.

    range for 语句格式: for(declaration: expression){statements}

   expression :用于表示一个对象,对象应该是一个序列。

   declaration :用于访问序列中的基础元素,循环中进行迭代。

   强调一点,注意越界问题!尤其是数组!

   防止越界的好习惯:用string::size_type 类型,首先保证没负数了,其次只要!.strsize()就可以了。

3 vector 向量:

    1.对象集合,头文件包含,可变长。

vector 属于类模版。使用的时候需要提供额外信息,表明vector 的类型。其中额外信息是可以嵌套的。

vector<int> v_int;vector<vector<int>> vv_int; 关于嵌套的一个小细节忽略。//其中vector<int>才是类型,vector 只是模版。我们用的时候多需要的是类型名。 

  3.3.1 vector 的定义和初始化:

    书上给了7种方式初始化,包括空向量。一般也就是前面介绍的那几种方式。

初始化的时候可以指定元素个数和值,一般用花括号进行列表初始化。一般来说,采用花括号时是不好指定元素个数大,但是类型不匹配的时候,也能这么干。具体的解释看书就好了。

  3.3.2 添加元素:

    不要使用下标运算符对vector 进行添加元素。一般我们声明的是空vector,所以不存在运算,调用下标运算符也没用。

vector能高速增长,所以不需要进行过多的初始化操作。

不能使用range for 语句想vector 添加语句。我猜测的原因是range for 是基于固定大小的序列遍历的,一旦你动态添加元素,那么range for 语句的使用条件就不成立了。

3.4 迭代器简介:

    现代C++提倡使用新特性编写程序,推荐使用迭代器,推荐使用向量。不推荐使用数组,指针。

     string 不是容器,但是有迭代器。

     有返回迭代器的成员函数,begin 和 end 函数,只要有迭代器的,一般都有这两个成员函数。其实标准库中也定义了这两个函数,返回的是指针,下面会介绍下。

尾后迭代器指向的是最后一个元素的下一个位置。

若容器为空,那么都是都是尾后迭代器。既然尾后迭代器指向的位置没东西或者有东西却不是我们想要的。那么解引用尾后迭代器就是非法行为。

一般来说迭代器的位置有两个位置,一是容器中的某一成员,而是尾后位置了,其余位置都是非法的。

迭代器类型:iterator and const_iterator(书上讲是指针常量,我理解是指向常量的指针)因为const_iterator 是无法修改它所指向的值的,但是迭代器自身的值却是可以修改的。

begin and end 函数的返回值类型由容器的类型决定。容器是常量,那么返回的就是const_iterator,否则返回的就是正常的迭代器。

为了简化操作,可以用cbegin and cend 函数,不管容器的类型,返回的都是指向常量的迭代器。

箭头操作符(->)简化了解引用操作和.操作符,二合一。

当使用了迭代器的时候,不要改变容器的大小,因为你一旦改了大小,那么尾后迭代器的位置怎么办?其次就是range for 语句中的序列大小应该是在运行时要求固定容量的,那么你在语句内部修改容量,从而影响range for 语句的使用。

3.5 数组:

不推荐使用了啦,推荐使用向量。

介绍下字符数组的特殊性。关于数组和指针的那点事情就不说了

讲一下字符数组初始化的小问题:

char c1[]={'a','b'};char c2[]={'a','b','\0'}; //带有空字符。char c3[]="c++"; //带有结束标志字符。char c4[3]=c3;  //可以嘛?不可以!因为c风格字符串带了结束标志。
c_str函数的使用。string到c风格的转换函数。

数组元素的下标类型是size_t,这个类型是一种与机器相关的无符号类型。

编译器拓展允许数组之间直接赋值。

strcmp 函数的返回值有三种,+ - 0 。

用数组初始化vector ,反过来不成立。

int array[5]={1,2,3,4,5};vector<int> v_int(begin(array),end(array));

4. 习题解答:

3.1

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){int sum = 0, var = 50;while (var < 101){sum += var;++var;}cout << "The sum is " << sum << endl;system("pause");return 0;}
其余略。

3.2

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string line;while (getline(cin, line))cout << line << endl;  //以换行符作为标志,但换行符不包含在line中。输入一行,按下回车的时候就输出了,不同于cin.system("pause");return 0;}
#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string word;while (cin>>word)cout << word << endl;  //以空白作为截止。带输入完毕后输入文件结束符。system("pause");return 0;}
3.3

//输入运算符是把空白当作分隔符,并且换行也是包含在其中。其中会忽略第一个有效字符前的所有空白字符。//getline 函数是把换行符当作分隔符被读取进来,但是并不包含在此行中。换忽略其他空白符。
3.4
#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str1, str2;cout << "Enter two strings ";cin >> str1 >> str2;if (str1 > str2)cout << str1 << endl;else if (str1 == str2)cout << "Two strings are equal " << endl;elsecout << str2 << endl;system("pause");return 0;}
#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str1, str2;cout << "Enter two strings ";cin >> str1 >> str2;if (str1.size() > str2.size())cout << str1 << endl;else if (str1.size() == str2.size())cout << "Two strings's size are equal " << endl;elsecout << str2 << endl;system("pause");return 0;}
3.5

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string line, str;cout << "Enter str and use the space to seprate the string " << endl;while (cin >> str)line += str;cout << line;system("pause");return 0;}
#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string line, str;cout << "Enter str and use the space to seprate the string " << endl;while (cin >> str){if (line.empty())line += str;elseline = line + " " + str;}cout << line;system("pause");return 0;}
3.6

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str = "0123456789ABCDEF";for (auto &var : str)var = 'X';cout << str << endl;system("pause");return 0;}
3.7

//设置成char 由于不是引用类型,故修改不会影响源字符串。#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){    string str = "0123456789ABCDEF";    for (char var : str)        var = 'X';    cout << str << endl;    system("pause");    return 0;}
3.8

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str = "0123456789ABCDEF";decltype(str.size()) index = 0;while (index != str.size()){str[index] = 'X';++index;}cout << str << endl;system("pause");return 0;}#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){    string str = "0123456789ABCDEF";    decltype(str.size()) index = 0;    for (index = 0; index != str.size();index++){        str[index] = 'X';    }    cout << str << endl;    system("pause");    return 0;}
//个人感觉for循环更舒服点吧,写在一起比较紧凑。while显的有点零散。
3.9

//不合法,此时s 是空串,不存在第0个元素。
3.10

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str = "Hello,Wo!rl.d";decltype(str.size()) index = 0;for (index = 0; index != str.size();index++){if (!ispunct(str[index])) //关于这个地方为什么不写遇到标点符号时的处理原则,因为我参考书上的cout << str[index];//代码,不处理的情况不写是最简洁的。要坚持这个原则!}system("pause");return 0;}
或者range for 处理,因为肯定要涉及到处理全部字符。

#include <string>#include <iostream>using std::string;using std::cin;using std::cout;using std::endl;int main(){string str = "Hello,Wo!rl.d";decltype(str.size()) index = 0;for (auto var : str){if (!ispunct(var))cout << var;}system("pause");return 0;}
3.11

是否合法取决于注释里面的操作。就本题而言是合法的。c的类型char& 。
3.12
b不合法,因为容器类型不匹配,不可以采用赋值初始化。
3.13

a: 0个。 b:10个0值。 c:10个42。 d:1个10。 e:2个值,10,42 。f:10个空字符串 g:10 “hi”字符串。
3.14

#include <string>#include <iostream>#include <vector>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){string str;int var;vector<string> svec;vector<int> ivec;while (cin >> var)ivec.push_back(var);for (auto x : ivec)cout << x << endl;system("pause");return 0;}
3.15

#include <string>#include <iostream>#include <vector>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){string str;        // int var;vector<string> svec;//vector<int> ivec;while (cin >> str)    //输入完毕按Ctrl +Z 。svec.push_back(str);for (auto x : svec)cout << x << endl;system("pause");return 0;}
3.16

#include <string>#include <iostream>#include <vector>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){vector <string> svec;string str;cout << "Enter numbers of strings and use Ctrl Z to stop " << endl;while (cin >> str)svec.push_back(str);for (auto &x : svec){for (auto &y : x){y = toupper(y);}}for (auto x : svec)cout << x << endl;system("pause");return 0;}
3.18

不合法。修改方案一: vector<int> ivec(1);ivec[0]=1; 因直接声明的是空向量,使用下标就会越界。
3.19
1.vector<int> ivec(10,42);2.vector<int> ivec={42,42....42}//10个42;3.vector<int> ivec;for(int i=0;i<10;i++)    ivec.push_back(42);
1最好。因为最简便。

3.20

#include <string>#include <iostream>#include <vector>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){    vector <int> ivec;    int var;    while (cin >> var)        ivec.push_back(var);    int temp_sum = 0;    for (decltype(ivec.size()) index = 0; index !=ivec.size()-1; index++){        temp_sum = ivec[index] + ivec[index+1];        cout << temp_sum << endl;    }    system("pause");    return 0;}-----------------------------------#include <string>#include <iostream>#include <vector>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){vector <int> ivec;int var;while (cin >> var)ivec.push_back(var);int temp_sum = 0;for (decltype(ivec.size()) index = 0; index <(ivec.size()+1)/2; index++){temp_sum = ivec[index] + ivec[ivec.size()-1-index];cout << temp_sum << endl;}system("pause");return 0;}
3.21

#include <string>#include <iostream>#include <vector>#include <iterator>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;int main(){vector<int> ivec;int var;while (cin >> var)ivec.push_back(var);int temp_sum = 0;for (auto x = ivec.begin(); x != ivec.end() - 1; x++){temp_sum = *x + *(x + 1);cout << temp_sum << " ";}system("pause");return 0;}--------------------------------#include <string>#include <iostream>#include <vector>#include <iterator>using std::string;using std::cin;using std::cout;using std::endl;using std::vector;using std::iterator;int main(){    vector<int> ivec;    int var;    while (cin >> var)        ivec.push_back(var);    int temp_sum = 0;    vector<int>::iterator it, beg, end;    beg = ivec.begin();    end = ivec.end();    int i = 1;  //因为迭代器相减会报错,所以设置一个变量来保证最后一个变量也跟着移动。    for(it = ivec.begin(); it!=ivec.begin()+(ivec.size()+1)/2; (i++,it++)){        temp_sum = *it + *(end - i);  //迭代器相减的后类型是带符号整形。?        cout << temp_sum << " ";    }    system("pause");    return 0;}
3.25

#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){vector<unsigned> ivec(11, 0);//容纳成绩。unsigned grade = 0;auto x = ivec.begin();while (cin >> grade)if (grade <= 100)++(*(x + (grade / 10)));for (auto x : ivec)cout << x << " ";system("pause");return 0;}
3.26

//迭代器没有定义加法吧。。两个迭代器相加如何理解其含义?但是定义了简单,尾首迭代器相减正好是他们直接的元素个数。
3.27

a,c,d .因为数组下标运算符的内必须是常量表达式。
3.28

sa 是10 个空字符串。ia 是10个0sa2 是10个空串ia2 是10个垃圾值。
3.29

1,固定容量;2,使用下标运算符,易越界。
3.30

下标越界,下标不可以取到10
3.31

#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){int array[10];int i = 0;for (auto &x : array){x = i++;}for (auto x : array)cout << x << " ";system("pause");return 0;}
3.32

#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){int array[10];int i = 0;for (auto &x : array){x = i++;}int array2[10];for (int i = 0; i < 10; i++)array2[i] = array[i];system("pause");return 0;}----------------------------------------#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){    vector<int> ivec;    for (int i = 0; i < 10; i++){        ivec.push_back(i);    }    vector<int> ivec_copy = ivec;    for (auto x : ivec_copy)        cout << x << " ";    system("pause");    return 0;}
3.33

视 数组的位置而定,如果数组是全局的,那么无所谓。但若不是全局的,那么数组的初始化可能会是垃圾值。

3.34

因为指针相减的类似是带符号整数。所以可以理解为指针p1的上下移动(p2-p1)个元素。指针相加是非法的。比如(p1+=p2)-p1;默认的+=符号的优先级比-号低。
3.35

#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){int array[10] = { 1, 2, 3,4,5,6,7,8,11,12 };int *p = array;for (auto &x : array)*p++ = 0;for (auto x : array)cout << x << " ";system("pause");return 0;}
3.36

#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){int array1[10] = { 1, 2, 3,4,5,6,7,8,11,12 };int array2[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 11, 12 };int i = 0;for (i = 0; i < 10; i++){if (array1[i] != array2[i]){cout << "Not equal" << endl;break;}}if (i == 10)cout << "Equal" << endl;system("pause");return 0;}----------------------------#include <iostream>#include <vector>#include <iterator>using namespace std;int main(){    vector<int> ivec1 = { 1, 2, 3 };    vector<int> ivec2 = { 1, 2, 3 };    if (ivec2 != ivec1)        cout << "Not Equal" << endl;    else        cout << "Equal" << endl;    system("pause");    return 0;}容器太方便了吧。。
3.37

由于不存在空字符,故会出现奇怪的输出。严重内粗一直找下去,直到找到空字符。
3.38

//两个地址相加需要什么意义?最多得出一个地址,但是那个地址说不定存着别人的东西,想要有意义,除非你给它规定一种意义。

3.39

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){string str1 = "Hello World";string str2 = "Hello Max";if (str1 == str2)cout << "Equal" << endl;elsecout << "Not Equal" << endl;system("pause");return 0;}-----------------------------------#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){    char ca[] = "C++";//如果如此会怎么样? char c[]={'C','+',‘+’};主要一定要给c字符串一个空字符。//不然调用它的相关函数会出现问题。    char cb[] = "Java";    int var=strcmp(ca, cb);    if (var != 0)        cout << "Not equal" << endl;    else        cout << "Equal" << endl;    system("pause");    return 0;}
3.40

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){char ca[10] = "C++";char cb[] = " ,Java";char cc[sizeof(ca)+sizeof(cb)+1];//为什么多1呢?万恶的空字符。strcat(ca, cb);strcpy(cc, ca);system("pause");return 0;}
3.41

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){int array[] = { 1, 2, 3, 5 };vector<int> ivec(begin(array), end(array));for (auto x : ivec)cout << x << endl;system("pause");return 0;}
3.42

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){int array[] = { 1, 2, 3, 5 };vector<int> ivec = { 2, 3, 4,1,5 };auto var = ivec.begin();for (auto &x : array){x = *var;++var;                if (var==ivec.end())                   break;        }for (auto x : array)cout << x << " ";system("pause");return 0;}
3.43

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){int array[3][4];/*for (size_t i = 0; i < 3; i++) *for (size_t j = 0; j < 4; j++)array[i][j] = i * 4 + j;*///第二种初始化方式。int var = 0;for (auto& x:array)for (auto &y : x)y = var++;for (int (&x)[4] : array){//cout << typeid(x).name() << endl;for (int &y : x){cout << y << " ";}cout << endl;}cout << endl;for (size_t i = 0; i <3; i++){for (size_t j = 0; j < 4; j++){cout << array[i][j] << " ";}cout << endl; //内层循环结束后打印换行。}for (int (*p)[4] = array; p != array + 3;p++)  //这个地方P是二级指针。用指针遍历数组的方式可以参考一维数组。for (int *q = *p; q != *p + 4; q++)cout << *q << " ";system("pause");return 0;}
3.44

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){int array[3][4];/*for (size_t i = 0; i < 3; i++) *for (size_t j = 0; j < 4; j++)array[i][j] = i * 4 + j;*///第二种初始化方式。int var = 0;for (auto& x:array)for (auto &y : x)y = var++;typedef int(&Name1)[4];typedef int &Name2;for ( Name1 x : array){//cout << typeid(x).name() << endl;for (Name2 y : x){cout << y << " ";}cout << endl;}cout << endl;using IINT = size_t;for (IINT i = 0; i <3; i++){for (IINT j = 0; j < 4; j++){cout << array[i][j] << " ";}cout << endl; //内层循环结束后打印换行。}using Name3 = int (*)[4];using Name4 = int *;for (Name3 p = array; p != array + 3;p++)  //这个地方P是二级指针。用指针遍历数组的方式可以参考一维数组。for (Name4 q = *p; q != *p + 4; q++)cout << *q << " ";system("pause");return 0;}
重点掌握两种类型别名的使用方法。
3.45

#include <iostream>#include <vector>#include <iterator>#include <string>using namespace std;int main(){int array[3][4];/*for (size_t i = 0; i < 3; i++) *for (size_t j = 0; j < 4; j++)array[i][j] = i * 4 + j;*///第二种初始化方式。int var = 0;for (auto& x:array)for (auto &y : x)y = var++;//typedef int(&Name1)[4];//typedef int &Name2;for ( auto &x : array){//cout << typeid(x).name() << endl;for (auto &y : x){cout << y << " ";}cout << endl;}cout << endl;//using IINT = size_t;for (auto i = 0; i <3; i++){for (auto j = 0; j < 4; j++){cout << array[i][j] << " ";}cout << endl; //内层循环结束后打印换行。}//using Name3 = int (*)[4];//using Name4 = int *;for (auto p = array; p != array + 3;p++)  //这个地方P是二级指针。用指针遍历数组的方式可以参考一维数组。for (auto q = *p; q != *p + 4; q++)cout << *q << " ";system("pause");return 0;}

5.后记:

    写的着实眼花头胀啊,习题写了一下午,笔记部分也是一下午。有时转念一想,很多人已经写过了,写的那么好,自己就开始动摇了,到底要不要写下去。其实坚持做一件事的过程中最可怕的是明明知道已经有人已经做的比你好了,但你还是要咬牙做下去。加油吧骚年,这本书你才看了五分之一。

End












0 0
原创粉丝点击