C++学习笔记(二)C++primer 部分习题和知识点

命名规范

想吧这个命名命名规范写到最前面,匈牙利命名法: 名字=属性+类型+对象描述
http://www.cnblogs.com/ggjucheng/archive/2011/12/15/2289291.html

第三章习题


2016.10.09
在一个函数中再次调用该函数的行为叫做递归,这样的函数被称作递归函数。
1、求5的阶乘。
demo.cpp

#include "GameFactorial.h"
using namespace std; 

int main()
{
    Game g1;
    int a;
    cout << "请输入想要的阶乘:" << endl;
    cin >> a;
    cout<<"该数的阶乘是:"<"pause");
}

GameFactorial.h

#include 
#include 
class Game
{
  public:
     int  factorial(int a);

};
int Game::factorial(int a)
{
    int Num;
    Num = a;
    if (Num==0 || Num==1)
    {
        return 1;
    } 
    else
    {
        return Num*factorial(a - 1);
    }

}

这里写图片描述


2016.10.10
栈(stack)是支持push和pop两种操作的数据结构,Push是在栈的顶端放入一组数据,pop是从其顶端取出一组数据的操作,栈叫做LIFO,Last In First Out 后进先出。
这里写图片描述
今天在南阳理工大学的ACM的OJ 平台上名注册了一个账号,还是很开心的,据说可以根据你的水平智能生成相应的算法,(@ο@) 哇~
附上链接:
http://acm.nyist.net/JudgeOnline/reg.php
这里写图片描述

#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
int main()
{
    char a, b, c,Max,Min,Mediate;
    cin >> a >> b >> c;
    if (a>=b)
    { 

        if (b>=c)
        {
            Min = c;
            Max = a;
            Mediate = b;

        } 
        else//C>B and A>B
        {
            if (a >= c)
            {
                Max = a;
                Mediate = c;
                Min = b;


            }
            else//a
            {
                Max = c;
                Mediate = a;
                Min = b;
            }

        }

    } 
    else//b>a
    {
        if (a>=c)
        {
            Max = b;
            Mediate = a;
            Min = c;
        } 
        else//C>a
        {
            if (b>=c)
            {
                Max = b;
                Mediate = c;
                Min = a;

            } 
            else//C>b
            {
                Max = c;
                Mediate = b;
                Min = a;
            }

        }
    }

    cout << Min << " " << Mediate << " " << Max << " " << endl;
}

我在编译器里面是运行出来额,但是在OJ平台运行出错了

2016.10.14

引用

在输出的时候,&符号叫做取地址

    int Src_nNum = 1;
    int &Src_nRNum = Src_nNum;//这个可以看做是一个简单的赋值操作
    cout << Src_nRNum <<"\n"<< &Src_nRNum << "";//不加&的就是一个单纯的,加&输出的就是地址

这里写图片描述

X  int &SrcNUm=1;//这是错误的,因为引用类型初始值必须是一个对象

习题:2.17

    int i, &ri = i;
    i = 5;
    ri = 10;
    cout << i << " " << ri << endl;
    system("pause");

这里写图片描述
从这个地方可以看出赋值语句和引用语句的不同,引用的话,使得ri和I一直相互关联,其中任何一个值改变,另一个值也跟着改变。

    int Src_nVal = 42;
    cout << &Src_nVal << endl;

这里写图片描述
如果这样去做的就会报错。

//必须这样写
int *p=&a;

这里写图片描述

* 和&* 的比较

int &r=a;//这是声明的部分,表示的是r是一个引用
int *p;//这是声明部分,表示的p是一个指针
p=&a//&出现在表达式中,是一个取地址符号
*p*i//出现在表达式中,是一个解引用符号
int &r2=*p//&是声明的部分,表示r是一个引用,*是解引用符号

*相当于往上走 &相当于往下翻

int Src_nVal = 42;//这个地方42就叫做字面值
cout << &Src_nVal << " "<

这里写图片描述

如何用一个指针来指向另一个指针

int *p_Valp2 = p_Valp;

这里写图片描述

含有多重*和&的问题

int *&r=p;//要理解r的类型,最简单的方法是:1、从右往左阅读;2、离变量名最近的符号(在此例中是&)对变量有最直接的影响,因此r是一个引用,声明符号的其他部分(此例中是*)表示r引用的类型,因此*符号说明,r引用的是一个指针。综上:r引用的是一个int类型的指针
const int &r=i;//将r2绑定对象i

指向常量的指针不能用于改变其所指对象的值,指针只是一个指向的关系。但是引用可以改变引用对象的值。
顶层const表示指针本身是一个常量;底层const表示指针所指的对象是一个常量

对象:是内存的一块区域
变量:就是命名后的对象或者引用
引用:某个对象的别名
指针:就是一个对象,存放着某个对象的地址
字面值:就是一个不能改变的值,例如:数字,字符等。其中单引号是字符字面值,多引号是字符串字面值

利用getline()来输读取一整好行

    string line;
    while (getline(cin,line))//getline的参数一个输入流一个是string对象,把输入流给了line
    {
        cout << line << endl;
    }
    system("pause");

这里写图片描述

初始化string对象的方法

string s1//初始化一个空字符串
string s2(s1)//s2是s1的副本
string s1=s2//s1是s2的副本
string s3(“value”)//s3的字面值是value 等价于string s3="value"
string s4(n,"c")//输出的n个c

凡是string的对象都能够进行的操作

string s
s.empty()//s为空的时候返回true,否则返回false
s.size()//返回s字符的个数
s[n]//返回s中的第N字符
s1+s2//将s1和s2两个字符连接在一起

对string中每个字符都做操作

使用范围for语句

for(declaration:expression)
statement  //expression 表示的对象(一个序列)declaration 声明一个访问string的每个字符的变量

举例说明:

    string Src_sStr("hello world!");
    for (auto Srd_sBL : Src_sStr)
    {
        cout << Srd_sBL << "";
    }
    system("pause");

这里写图片描述
如果在这个例子中想要改变的是Src_sStr的值,就需要把Srd_sStr改成引用类型(加&)

    string Src_sStr("hello world!");
    for (auto &Srd_sBL : Src_sStr)
    {
        Srd_sBL = toupper(Srd_sBL);
    }
    cout << "Src_sStr:" << Src_sStr << "";

这里写图片描述


2016.10.13
C++primer
P90.3.3.1

    vector<vector<int>>ivec;//定义了一个ivec的vector对象,其中每个ivec的每个元素都是vector类型
    vector<string>{10,"hi"};//初始化10个hi,string只能用{}不能用()

解答:

#include 
#include;
using namespace std;
int main()
{
        vector<int> Ivec;
        int i;
        char cont = 'y';
        cout << "Please Input The Num:" << endl;
        while (cin >> i)//从这条语句中看出.pushback只能在最后面走
        {
            Ivec.push_back(i);
            cout << "if you want to continue stop ,please input:n" << endl;
            cin >> cont;
            if (cont=='n'&&cont=='N')
            {
                break;//突然意识到break语句真伟大
            }
        }
    for (auto nOutput:Ivec)//这里是一个冒号
    {
        cout << "The output is:" << nOutput <<" "<< endl;
    }
    system("pause");
}

这里写图片描述
这个程序有个小bug,但是这是我按照思路写的第一个小程序。
3.15跟这道题目类似。
3.16是在3.13的基础上

    int VNum;
    VNum = Ivec.size();//注意这个地方要写括号
    cout << "The Num is:" << VNum << endl;

3.17

//答案里面有一个for语句来遍历每个字符串,然后toupper这个函数改为大写字母。
#include 
#include 
#include;
using namespace std;
int main()
{
    vector<string>ISVec;
    char ProEnd = 'n';
    string SRecWord;
    cout << "Please input a set of word:" << "";
    while (cin>>SRecWord)
    {
        ISVec.push_back(SRecWord);
        //定义中方法,先把输入的字符串都改成大写以后再输入到里面
        //第二种方法,在输入之后想办法再改


        cout << "If you want to stop Please input :N" << "";
        cin >> ProEnd;
        if (ProEnd =='n')
        {
            break;
        }
        for ( auto men:ISVec )
        {
            for (auto c:men)
            {
                c=toupper(c);
                cout << "The Output is:" << c << endl;
            }

        }
    }
    system("pause");
}

这里写图片描述
程序依然是有BUG的
3.21使用迭代器在做一遍

        for (auto it = ISVec.cbegin(); it != ISVec.cend() && !it->empty();++it)
        {
            cout << *it << endl;

        }

将原来的额题目循环输出打印的地方换成这个就可以了

(*it).empty()等价于it->empty();

3.4-3.23
编写一个程序,创建一个含有10个整数的 vector对象,然后用迭代器吧所有的值都变为原来的两倍,并且输出vector对象的内容

vector<int> Src_iVec(10, 1);
    for (auto _IOutPut : Src_iVec)
    {
        cout << _IOutPut * 2 << "";

    }

这里写图片描述

vector和string迭代器支持的运算

容器:vectorstring 就是容器
迭代器:用于访问容器中元素 举个例子,就是上面这个_IOutPut就是迭代器
iter+n//迭代器指示的新位置比原来位置向前移动了n个元素
iter-n//向后移动N个元素
iter+=n//将iter+n的结果赋值给了iter
iter1-iter2就是iter1和iter2之间的距离

举例说明

    vector<int>Src_nDouble{ 1, 2, 3, 4, 6, 7, 8, 9 };
    for (auto Src_nDSing:Src_nDouble)
    {
        cout << Src_nDSing + 1 <<"";
    }

这里写图片描述

3.4.2-3.24
读入一组整数,并把他们存入一个vector的对象中,
1、将每对相邻的整数的和输出。
2、改写程序,将第一个和最后一个元素的和输出,然后是输出第2和和倒数第2个数的和
3、输出一个容器偶数位

    vector<int>Src_nDouble{ 1, 2, 3, 4, 6, 7, 8, 9 };
    for (auto Src_nDSing:Src_nDouble)
    {
        for (int i = 0;i<2;i+=2)
        {
            cout << Src_nDSing + i + Src_nDSing + i+1<< endl;
        }

    }

这个程序数字不对,
这里写图片描述

在这里记录一个问题:begin和Cbegin有什么区别


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

    int a[] = { 1, 2, 3, 4, 5, 6 };
    vector <int> Src_nCSH(begin(a), end(a));//(a,b)a表示起始位置,b表示终止位置
    for (auto Src_nXS:Src_nCSH)
    {
        cout << Src_nXS << "" ;
    }

这里写图片描述
如果我想输出3,4,5

    vector <int> Src_nCSH(a+2, a+5);
    //需要注意的一点是:a+5在数组中指的是6,遍历的时候到6停止,6不输出

这里写图片描述

定义以及初始化二维数组

//定义一个3行4列,也就是3*4的二维数组
int a[3][4]={
    {1,2,3,4},//第一行初始值
    {1,2,3,4},//第二行初始值
    {1,2,3,4}//第三行初始值

};
等价于
int a[3][4]={1,2,3,4,1,2,3,4,1,2,3,4};

++i于i++的区别

int j,i=0;
j=i++;//输出结果是j=0,i=1;//用后自加1
int j,i=0;
j=++i;//输出结果是j=1,i=1;//用前自加1 这种方式尽量多使用

while循环语句

WhileA)
{
        B
}
如果满足A就进入循环体B

用While语句遍历vector中的元素

    vector<int> Src_nUNZero{ 1, 2, 3, 4 };
    auto Src_nUm = Src_nUNZero.begin();
    while (Src_nUm!=Src_nUNZero.end())
    {
        cout << *Src_nUm++ << "";

    }

这里写图片描述

条件表达式

条件运算符(?:)
cond?expr1:expr2;//
如果cond为真,就执行expr1;否则就执行expr2;

》》扩展:嵌套条件表达式
举例

string finalgrade=(grade>90)?"high pass"
                             :(grad<60)?"fail":"pass";

4.7-4.21
编写一段程序,使用条件运算符从vector中找出那些元素是奇数,并把这些奇数翻倍

vector<int> Src_nUNZero{ 1, 2, 3, 4 };
    int vvale;
    for (auto &men:Src_nUNZero)
    {
        vvale=(men % 2 == 0) ? men*2:men*9;
        cout << vvale << endl;
        ++men;
    }

这里写图片描述
看来这个程序通了,只是有点小bug
修改了一下,更加符合题意

    vector<int> Src_nUNZero{ 1, 2, 3, 4 };
    int vvale;

    for (auto men:Src_nUNZero)
    {
        vvale=(men % 2 == 0) ? 0:men*2;//从这个程序中可以看出,表达式必须要翻倍
        cout << vvale << "--";
        ++men;
    }

这里写图片描述

    cout <<((men % 2 == 0) ? 0 : men * 2) << "--";//终于知道原因了,因为这个地方如果我吧他们都括了括号,那么编译就可以通过了

输出的结果一样
这里写图片描述

位运算符

 1. ~,位求反,~a
 2. <<,左移,a<;
 3. >>,右移,a>>b
 4. &,位与,a&b
 5. ^,位异或,a^b
 6. |, 位或,a|b

sizeof运算符

sizeof运算符返回是一个表达式,或者一个类型名字所占有的字节数

sizeof有两种表达形式
sizeof(类型)
sizeof 表达式

以上个题目为例

        vector<int> Src_nUNZero{ 1, 2, 3, 4 };

    for (auto men:Src_nUNZero)
    {
        cout <<((men % 2 == 0) ? 0 : men * 2) << "--";
        ++men;
        cout << (sizeof(men)) << endl;
    }

这里写图片描述那么可以知道每个men占4个字节

逗号运算符

逗号运算符含有两个运算对象,按照从左往右的顺序依次求值;逗号表达式通常被用在for循环语句中

fora;b;C++,d--)

复合语句(块)

复合语句也叫做块,就是{ }里面东西就叫做块


5.3.2-5.9
编写一段程序,统计出cin读入的文本中有多少个元音字母。

char Srv_chName;
    int a = 0;
    while (cin >> Srv_chName)
    {
        if (Srv_chName == 'a' || Srv_chName == 'e' || Srv_chName == 'i' || Srv_chName == 'o' || Srv_chName == 'u' )
        {
            ++a;
        } 
        else
        {
            break;
        }
    }
    cout << a << "";

依然这段程序有个小bug
这里写图片描述
按理说,应该是是5个,

switch语句

    int a = 0;
    char Srv_chName1;
    while (cin>>Srv_chName1)
    {
        switch (Srv_chName1)
        {
        case 'a':case 'e':case 'o':case 'i':case 'u'://
            ++a;
        default:
            break;
        }
        cout << a << endl;
    }

程序仍然有个小BUG
这里写图片描述

迭代语句

迭代语句通常称为循环

  • for
  • While
  • do while

跳转语句

  • break
    负责终止离他最近的While、do While、for、switch
  • continue
    终止最近的循环并且立即进入下一次循环
  • goto
  • return

异常

异常是指存在于运行时的反常行为
异常处理机制主要包括:程序中异常检测和异常处理

  • throw表达式
throw SamNUm("输入的数字不是相同的");
  • try语句块
try{
////请正确输入}
catch(runtime_error)
{///请用户重新检查输入后重新输入
char c;
cin>>c;
}

函数

函数的三要素:返回类型,函数名,形参类型

形参与实参

形参出现在函数定义的地方,实参出现在函数调用的地方;实参是形参的初始化

尾置返回类型

auto func(int i )->int (*)[10];//func接受了一个int类型的实参,返回一直指针,这个指针有10个整数的数组//说心里话,我也不明白这说的是什么话

函数重载

定义:同一作用域内的名字相同,但是形参列表不同的函数

#include 
#include 
#include
#include 
using namespace std;
void Function1(int a,int b);//函数1的声明
void Function1(char a, char b);//函数2的声明
int main()
{

Function1(1, 2);
Function1('a', 'b');
system("pause");
}
void Function1(int a, int b)//函数1的定义
{
    cout << "这是调用的第一个函数" << endl;
}
void Function1(char a, char b)//函数2的定义
{

    cout << "这是调用的第二个函数" << endl;

}

这里写图片描述
这个小程序还是比较满意的

用C++计算整个程序所用的时间

//目前暂定是这方法
#include
#include
using namespace std;

int main()
{
    clock_t start, finish;
    start = clock();
    cout << "HW .... " << endl;
    finish = clock();
    cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;
    system("pause");
}

内联函数

内联函数就是函数部分放到main函数内部去执行
内联函数适合那种函数规模比较小的函数。

函数指针

函数指针指向的是函数(而不是对象),函数的类型是由它的返回类型和形参共同决定的,与函数名无关。

构造函数

构造函数作用就是初始化类的对象的数据成员

友元

友元的关键字是friend

cerr

通常用于输出程序的错误消息,写入到标准错误

继承

继承可以让我们声明一个特定的类继承自另一个类

管理输出缓冲

    cout << "hi" << flush;//输出hi然后刷新缓冲区,不附加任何额外的字符
    cout << "hi" << endl;//输出一个hI和一个换行,然后刷新缓冲区
    cout << "hi" << ends;//输出一个hi和一个空额,然后刷新缓冲区
    cout << unitbuf;//所有输出操作后都会立即刷新缓冲区
    cout<//回到正常的缓冲方式

容器的capacity和size的区别

容器的size是指,容器已经保存的元素的数目
容器的capacity是指,在不分配新的内存空间的前提下,它最多可以保存的元素数目

顺序容器

vector//可变数组大小,支持快速随机访问,在尾部以外的地方插入比较缓慢
deque//双端队列,支持快速随机访问,在头部和尾部插入数据比较快
list//双向链表,支持双向顺序访问,在任何位置进行插入和删除都比较快,不支持元素的随机访问
forward_List//单向链表,支持单向顺序访问,在链表任何位置都比较块,不支持元素的随机访问
array//固定大小数组。支持快速随机访问,不能添加和删除元素
string//与vector相似的容器,专门用于保存字符

begin和cbegin的区别

c.begin(),c.end()//返回指向C的首个元素和末尾元素位置之后的迭代器
c.cbegin(),c.cend()//访问的const_interator

swap

swap用来交换两个类型相同的容器的内容

Vector <string> svec1(10);
vector <string> svec2(21);
swap(svec1,svec2);

向顺序容器中添加元素

.push_back(t)//在容器的尾部添加元素t
.push_front(t)//在容器的顶部部添加元素t
.insert(p,t)//具体怎么用,我也不知道

向顺序容器中访问元素

.back()
.front()
[n]//对下标为n的元素进行引用

向顺序容器中删除元素

.pop_back()//删除容器的最后一个元素
.pop_front()//删除容器第一个元素
.erase(p)//删除迭代器P所指定的元素
.clear()//清除容器中所有元素

改变容器的大小

//array不支持resize
.resize(n)//如果当前值大于n,就会把末尾的值删掉,如果小于n,就会在末尾增加元素
.resize(n,p)//增加的元素是P

capacity和size的区别

容器的size是指的它已经保存了元素数目,而capacity则实在不分配新的内存空间的前提下,它最多可以保存的元素

构造string的方法

string s(cp,n)//cp是数组名,n是数组中前n个元素,s相当于一个实例化的对象

substr

substr把原始string的一部分进行拷贝

s.substr(pos,n)//返回值是s中从pos开始的n个字符的拷贝,pos默认值为0;

改变string值的方法

.insert()
.erase()
.assign()
.replace()

string搜索操作

s.find(a)查找s中a第一次出现的位置,也就是说是返回值是一个数字
s.rfind(a)查找s中a最后一次出现的位置
s.find_first_of()
s.find_last_of()
s.find_first_not_of()
s.find_first_not_of()

数值转换

    int i = 42;
    string s = to_string(i);//将整型数i转化成string类型
    double d = stod(s);//将字符串s转换成浮点类型

顺序容器适配器

  • stack
  • queue
  • priority_queue

求和算法

#include
#include 
#include 
using namespace std;

int main()
{
    vector<int> Src_nVector{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int sum = accumulate(Src_nVector.cbegin(), Src_nVector.cend(), 0);//accumulate函数定义在头文件numeric中,第一参数是容器的起始位置,第二个参数是容器的末尾,最后一个sum的初始值
    cout << sum << endl;
    system("pause");
}

运行的结果图:
这里写图片描述

back_inserter

back_inserter是一种插入迭代器(也叫做迭代器适配器),向容器中添加元素,它定义在iterator的头文件中

迭代器的类别

  • 输入迭代器
  • 输出迭代器
  • 双向迭代器
  • 前向迭代器
  • 随机访问迭代器

关联容器

关联容器支持高效关键字查找和访问,两个主要的关键容器类型map和set
标准库提供了8种关联容器

map//关键字和值之间要一一对应的集合,也叫做关联数组,关联数组与正常数组之间的差别在于,关联数组下标可以不是整数
set//只含有关键字
multimap//关键字可以重复出现额map
multiset//关键字可以重复出现的set
unordered_map//用哈希组织的map
unordered_set//用哈希组织的set
unordered_multimap//用哈希组织的map,关键字可以重复出现
unordered_multiset//用哈希组织的set,关键字可以重复出现

我梳理了一下我知识结构:
这里写图片描述

pair类型

pair的标准库类型定义在头文件utility中

hash

hash是一种特殊额标准库模板,无序容器用他来管理元素的位置

哈希函数

将给定类型的数值映射到整型值的函数,相同的值必须映射到相等的整数,不相等的值映射到不相等的整数

weak_ptr

Weak_ptr是一种不控制所指向对象生存期的智能指针

利用new关键字来实例化一个对象数组

int *p= new int[get_size()]//【】中的数大小必须是常量,但是不必是常量

注意:不能对动态数组调用begin或者end

释放动态数组

你可能感兴趣的:(【C++编程】)