基于C语言的C++学习(三)

基于C语言的C++学习(三)

这是作者的学习经历和学习笔记,如有错误,欢迎指正。
学习网址是黑马程序员的C++

文件操作

C++中对文件操作需要包含头文件

文件类型分为两种:

  1. 文本文件
  2. 二进制文件

操作文件的三大类:

  1. ofstream:写操作
  2. ifstream:读操作
  3. fstream:读写操作

文本文件

写文件
  1. 包含头文件:#include<fstream
  2. 创建流对象:ofstream ofs;
  3. 打开文件:ofs.open("文件路径", 打开方式);
  4. 写数据:ofs << "写入的数据"
  5. 关闭文件:ofs.close();
打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件尾
ios::app追加方式写文件
ios::trunc如果文件存在,先删除,再创建
ios::binary二进制方式

**注意:**文件打开方式可以配合使用,用|操作符

#include<iostream>
#include<string>
#include<fstream>
using namespace std;

void test01()
{
    ofstream ofs;
    ofs.open("test.txt", ios::out);
    ofs << "姓名:张三" << endl;
    ofs << "性别:男" << endl;
    ofs.close();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
读文件
  1. 包含头文件:#include<fstream
  2. 创建流对象:ifstream ifs;
  3. 打开文件:ifs.open("文件路径", 打开方式);
  4. 读数据:四种方式读取,见代码
  5. 关闭文件:ifs.close();
#include<iostream>
#include<string>
#include<fstream>
using namespace std;

void read_mode_1(ifstream& ifs)
{
	char buf[1024] = { 0 };
	cout << "第一种读取方式" << endl;
	while (ifs >> buf)
	{
	cout << buf << endl;
	}
}

void read_mode_2(ifstream& ifs)
{
	char buf[1024] = { 0 };
	cout << "第二种读取方式" << endl;
	while (ifs.getline(buf, sizeof(buf)))
	{
		cout << buf << endl;
	}
}

void read_mode_3(ifstream& ifs)
{
	string buf;
	cout << "第三种读取方式" << endl;
	while (getline(ifs, buf))
	{
		cout << buf << endl;
	}
}

void read_mode_4(ifstream& ifs)
{
	char c;
	cout << "第四种读取方式" << endl;
	while ((c = ifs.get()) != EOF)
	{
		cout << c;
	}
}

void test01()
{
	ifstream ifs;
	ifs.open("test.txt", ios::in);

	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}

	//read_mode_1(ifs);
	//read_mode_2(ifs);
	//read_mode_3(ifs);
	read_mode_4(ifs);

	ifs.close();
}

int main()
{
	test01();
	system("pause");
	return 0;
}

二进制文件

写文件

二进制方式写文件主要利用流对象调用成员函数write

函数原型:ostream& write(char * buffer, int len);

参数解释:字符指针buffer指向内存中一段存储空间,len是读写的字节数

#include<iostream>
#include<string>
#include<fstream>
using namespace std;

class Person
{
public:
    char m_Name[64];
    int m_Age;
};

void test01()
{
    ofstream ofs;
    ofs.open("Person.txt", ios::out | ios::binary);
    
    Person p = { "张三", 18 };
    ofs.write((const char*)&p, sizeof(Person));

    ofs.close();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
读文件

二进制方式写文件主要利用流对象调用成员函数read

函数原型:ostream& read(const char * buffer, int len);

参数解释:字符指针buffer指向内存中一段存储空间,len是读写的字节数



#include<iostream>
#include<string>
#include<fstream>
using namespace std;

class Person
{
public:
    char m_Name[64];
    int m_Age;
};

void test01()
{
    ifstream ifs;
    ifs.open("Person.txt", ios::in | ios::binary);
    
    if (!ifs.is_open())
    {
        cout << "文件打开失败" << endl;
        return;
    }

    Person p;
    ifs.read((char*)&p, sizeof(Person));

    cout << "姓名:" << p.m_Name << "年龄:" << endl;

    ifs.close();
}

int main()
{
    test01();
    system("pause");
    return 0;
}

模板

C++另一种编程思想称为泛型编程,主要利用的技术就是模板

C++提供两种模板机制:函数模板类模板

模板的特点:

  • 模板不可以直接使用
  • 模板不是通用的

函数模板

函数模板的基本用法

**函数模板作用:**建立一个通用函数,其返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。

语法:

template<typename T>
函数定义或声明
  • template:声明创建模板
  • typename:表明其后面的符号是一种数据类型,可以用class代替
  • T:通用的数据类型,名称可以替换,通常为大写字母
#include<iostream>
using namespace std;

template<typename T>
void Swap(T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}

void test01()
{
    int a = 10;
    int b = 20;
    //1.自动类型推导
    Swap(a, b);
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    double c = 0.1;
    double d = 0.2;
    //显示指定类型
    Swap<double>(c, d);
    cout << "c = " << c << endl;
    cout << "d = " << d << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
函数模板注意事项
  • 自动类型推导,必须推导出一致的数据类型T才可以使用
  • 模板必须要确定出T的数据类型,才可以使用
#include<iostream>
using namespace std;

template<typename T>
void Swap(T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}
//自动类型推导,必须推导出一致的数据类型T才可以使用
void test01()
{
    int a = 10;
    int b = 20;

    Swap(a, b);			//错误,a和b应该要统一数据类型
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
}

template<typename T>
void func()
{
    cout << "func的调用" << endl;
}

void test02()
{
    func();	//错误,编译器无法推导出T的类型
    func<int>();	//正确
}

int main()
{
    test01();
    test02();
    system("pause");
    return 0;
}
函数模板案例
  • 利用函数模板封装一个排序函数,可以对不同类型的数据数组进行排序
  • 排序从小到大,选择排序
#include<iostream>
using namespace std;


template<typename T>
void Swap(T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}

template<typename T>
void Sort(T arr[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        int min = i;
        for (int j = i + 1; j < n; j++)
        {
            if (arr[min] > arr[j])
            {
                min = j;
            }
        }
        if (min != i)
        {
            Swap(arr[min], arr[i]);
        }
    }
}

template<typename T>
void Printf(T arr[], int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
}

void test01()
{
    int intArray[5] = { 2, 5, 4, 3, 1 };
    char charArray[] = "icnwljf";
    int num1 = sizeof(intArray) / sizeof(int);
    int num2 = sizeof(charArray) / sizeof(char) - 1;

    Sort(intArray, num1);
    Sort(charArray, num2);
    Printf(intArray, num1);
    Printf(charArray, num2);
}

int main()
{
    test01();
    system("pause");
    return 0;
}
普通函数和函数模板的区别
  • 普通函数在调用时可以发生隐式类型转换
  • 函数模板用自动类型推导,不可以发生隐式类型转换
  • 函数模板用显示指定类型,可以发生隐式类型转换
普通函数与函数模板的调用规则
  • 如果函数模板和普通函数都可以调用,优先调用普通函数
  • 可以通过空模板的参数列表,强制调用函数模板
  • 函数模板可以发生重载
  • 如果函数模板可以产生更好的匹配,优先调用函数模板
模板的具体化

模板不是万能的,有时候模板无法对自定义数据类型进行操作,可以通过运算符重载或模板具体化

语法:

// 1. 先声明通用函数模板
template<typename T>
返回值类型 函数名(参数列表) {
    // 通用实现
}

// 2. 再声明针对特定类型的具体化版本
template<>  // 必须添加 template<> 关键字
返回值类型 函数名<具体类型>(参数列表) {  // 显式指定具体类型
    // 针对该类型的定制实现
}
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person(int age, string name)
	{
		this->age = age;
		this->name = name;
	}

	int age;
	string name;
};

//比较相同函数
template<typename T>
bool compare(const T& a, const T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}

template<> 
bool compare(const Person& a, const Person& b)	//具体化
{
	if (a.age == b.age && a.name == b.name)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test01()
{
	Person p1(18, "Ton");
	Person p2(18, "Ton");

	if (compare(p1, p2))
	{
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;
	}
}

int main()
{
	test01();
	system("pause");
	return 0;
}

类模板

**作用:**建立一个通用类,类中的成员数据类型可以不具体定制,用一个虚拟的类型来代表

语法:

template<class T>
#include<iostream>
#include<string>
using namespace std;

template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson()
    {
        cout << "name:" << this->m_Name << "\tage:" << this->m_Age << endl;
    }

private:
    NameType m_Name;
    AgeType m_Age;
};

void test01()
{
    Person<string, int>p1("张三", 19);
    p1.showPerson();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
类模板和函数模板的区别
  • 类模板没有自动类型推导的使用方式
  • 类模板在模板参数列表中可以有默认参数
#include<iostream>
#include<string>
using namespace std;

template<class NameType, class AgeType = int>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson()
    {
        cout << "name:" << this->m_Name << "\tage:" << this->m_Age << endl;
    }

private:
    NameType m_Name;
    AgeType m_Age;
};

void test01()
{
    //Person p1("张三", 19);    //错误
    Person<string, int>p1("张三", 19);
    p1.showPerson();
}

void test02()
{
    Person<string>p2("李四", 18);
    p2.showPerson();
}

int main()
{
    test01();
    test02();
    system("pause");
    return 0;
}
类模板中成员函数创建时机
  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在带哦应时才创建
#include<iostream>
#include<string>
using namespace std;

class Person1
{
public:
    void showPerson1()
    {
        cout << "Person1的调用" << endl;
    }
};

class Person2
{
public:
    void showPerson2()
    {
        cout << "Person2的调用" << endl;
    }
};

template<class T>
class MyClass
{
public:

    T obj;

    void func1()
    {
        obj.showPerson1();  //因为没有确定obj的类型,所以不会报错
    }

    void func2()
    {
        obj.showPerson2();
    }
};

void test01()
{
    MyClass<Person1>m1; //指定m1为Person1类型
    m1.func1();
    MyClass<Person2>m2; //指定m2为Person2类型
    m2.func2();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
类模板对象做函数参数

一共有三种传入方式:

  1. 指定传入的类型——直接显示对象的数据类型
  2. 参数模板化——将对象中的参数变为模板进行传递
  3. 整个类模板化——将这个对象类型模板化进行传递
#include<iostream>
#include<string>
using namespace std;

template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << "name:" << m_Name << "\tage:" << m_Age << endl;
    }

private:
    T1 m_Name;
    T2 m_Age;
};

//1.指定传入类型
void printPerson1(Person<string, int>& p)
{
    p.showPerson();
}

void test01()
{
    Person<string, int>p("孙悟空", 100);
    printPerson1(p);
}

//2.参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
    p.showPerson();
    cout << "T1的类型为:" << typeid(T1).name() << endl;
    cout << "T2的类型为:" << typeid(T2).name() << endl;
}

void test02()
{
    Person<string, int>p("猪八戒", 99);
    printPerson2(p);
}

//3.整个类模板化
template<class T>
void printPerson3(T & p)
{
    p.showPerson();
    cout << "T的类型为:" << typeid(T).name() << endl;
}

void test03()
{
    Person<string, int>p("唐僧", 1000);
    printPerson3(p);
}

int main()
{
    test01();
    test02();
    test03();
    system("pause");
    return 0;
}
类模板与继承
  • 当子类继承父类是一共类模板时,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也要变为类模板
#include<iostream>
#include<string>
using namespace std;

template<class T>
class Base
{
    T m;
};

//class Son : public Base   //错误,必须要知道父类中的T类型,才能继承给子类
class Son1 : public Base<int>
{

};

void test01()
{
    Son1 S1;
}

template<class T1, class T2>
class Son2 : public Base<T2>
{
public:

    Son2()
    {
        cout << "T1的数据类型为:" << typeid(T1).name() << endl;
        cout << "T2的数据类型为:" << typeid(T2).name() << endl;
    }
    T1 obj;
};

void test02()
{
    Son2<int, char> S2;
}

int main()
{
    test01();
    test02();
    system("pause");
    return 0;
}
类模板成员函数类外实现
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age);

    void showPerson();
 
    T1 m_Name;
    T2 m_Age;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "name:" << this->m_Name << "\tage:" << this->m_Age << endl;
}

void test01()
{
    Person<string, int>P("Tom", 20);
    P.showPerson();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
类模板分文件编写

**问题:**类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

  1. 直接包含.cpp源文件
  2. 将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称

方法一:

Person.cpp

#include"Person.h"

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "name:" << m_Name << "\tage:" << m_Age << endl;
}

Person.h

#pragma once
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age);

    void showPerson();

private:
    T1 m_Name;
    T2 m_Age;
};

main.cpp

#include<iostream>
using namespace std;
#include<string>
#include"Person.cpp"

void test01()
{
    Person<string, int>P("Tom", 18);
    P.showPerson();
}

int main()
{
    test01();
    system("pause");
    return 0;
}

方法二:

Person.hpp

#pragma once
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age);

    void showPerson();

private:
    T1 m_Name;
    T2 m_Age;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "name:" << m_Name << "\tage:" << m_Age << endl;
}

main.cpp

#include<iostream>
using namespace std;
#include<string>
#include"Person.hpp"

void test01()
{
    Person<string, int>P("Tom", 18);
    P.showPerson();
}

int main()
{
    test01();
    system("pause");
    return 0;
}
类模板与友元
  • 全局函数类内实现:直接在类内声明友元即可
  • 全局函数类外实现:需要提前让编译器知道全局函数的存在

类内实现:

#include<iostream>
#include<string>
using namespace std;

template<class T1, class T2>
class Person
{

    friend void printPerson(Person<T1, T2>& p)
    {
        cout << "name:" << p.m_Name << "\tage:" << p.m_Age << endl;
    }


public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

private:
    T1 m_Name;
    T2 m_Age;
};

void test01()
{
    Person<string, int> p("Tom", 18);
    printPerson(p); // 调用友元函数
}

int main()
{
    test01();
    system("pause");
    return 0;
}

类外实现:

#include<iostream>
#include<string>
using namespace std;

// 提前声明模板类(供友元函数声明使用)
template<class T1, class T2>
class Person;

// 提前声明友元函数(模板函数)
template<class T1, class T2>
void printPerson(Person<T1, T2>& p);

template<class T1, class T2>
class Person
{
    // 声明友元函数,并指定其模板参数
    friend void printPerson<>(Person<T1, T2>& p);
    // 注意:<> 表示使用与类相同的模板参数

public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

private:
    T1 m_Name;
    T2 m_Age;
};

// 定义友元函数(全局模板函数)
template<class T1, class T2>
void printPerson(Person<T1, T2>& p)
{
    cout << "name:" << p.m_Name << "\tage:" << p.m_Age << endl;
}

void test01()
{
    Person<string, int> p("Tom", 18);
    printPerson(p); // 调用友元函数
}

int main()
{
    test01();
    system("pause");
    return 0;
}

STL初识

STL基本概念

  • STL(Standard Template Library,标准模板库)
  • STL广义上分为:容器(container)算法(algorithm)迭代器(iterator)
  • 容器和算法之间通过迭代器进行无缝链接
  • STL几乎所有的代码都采用了类模板或者函数模板

STL六大组件:

  1. 容器:各种数据结构,如vector、list、deque、set、map等
  2. 算法:各种常用的算法,如sort、find、copy、for_each等
  3. 迭代器:扮演了容器与算法之间的胶合剂
  4. 仿函数:行为类似函数,可以作为算法的某种策略
  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
  6. 空间配置器:负责空间的配置与管理

vector容器

功能:

  • vector数据结构和数组非常相似,也称为单端数组

vector与普通数组的区别:

  • 不同之处在于数组是静态空间,而vector可以动态扩展

动态扩展:

  • 并不是在原有空间之后继续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间
vector构造函数
  • vector<T> v;——采用模板实现类实现,默认构造函数
  • vector(v.begin(), v.end());——将v[begin(), end()]区间中的元素拷贝给本身
  • vector(n, elem);——构造函数将n个elem拷贝
  • vector(const vector &vec);
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;  //默认构造,无参构造
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);

    vector<int>v2(v1.begin(), v1.end());
    printVector(v2);

    vector<int>v3(10, 100);
    printVector(v3);

    vector<int>v4(v3);
    printVector(v4);
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector赋值操作
  • vector& operator=(const vector &vec);——重载等号操作符
  • assign(beg, end);——将[beg, end]区间中的数据拷贝赋值给本身
  • assign(n, elem);——将n个elem拷贝赋值给本身
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);

    vector<int>v2;
    v2 = v1;
    printVector(v2);

    vector<int>v3;
    v3.assign(v1.begin(), v1.end());
    printVector(v3);

    vector<int>v4;
    v4.assign(10, 100);
    printVector(v4);
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector容量和大小
  • empty();——判断容器是否为空
  • capacity();——容器的容量
  • size();——返回容器中元素的个数
  • resize(int num);——重新指定容器的长度num,若容器变长, 则以默认值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
  • resize(int num, elem);——重新指定容器的长度num,若容器变长, 则以elem填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);

    if (v1.empty())
    {
        cout << "v1为空" << endl;
    }
    else
    {
        cout << "v1不为空" << endl;
        cout << "v1容量为:" << v1.capacity() << endl;
        cout << "v1大小为:" << v1.size() << endl;
    }

    v1.resize(15);
    printVector(v1);    //默认用0填充

    v1.resize(20, 99);
    printVector(v1);

    v1.resize(5);
    printVector(v1);
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector插入和删除
  • push_back(ele);——尾部插入元素ele
  • pop_back();——删除最后一个元素
  • insert(const_iterator pos, ele);——迭代器指向位置pos插入元素ele
  • insert(const_iterator pos, int count, ele)——迭代器指向位置pos插入count个元素ele
  • erase(const_iterator pos);——删除迭代器指向位置的元素
  • erase(const_iterator start, const_iterator end);——删除迭代器从start到end之间的元素
  • clear();——删除容器中所有的元素
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);

    printVector(v1);

    //尾删
    v1.pop_back();
    printVector(v1);

    //插入
    v1.insert(v1.begin(), 100);
    printVector(v1);

    v1.insert(v1.begin(), 2, 200);
    printVector(v1);

    //删除
    v1.erase(v1.begin());
    printVector(v1);

    v1.clear();
    printVector(v1);
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector存放数据
  • at(int idx);——返回索引idx所指的数据
  • operator[];——返回索引idx所指的数据
  • front();——返回容器第一个数据元素
  • back();——返回容器最后一个数据元素
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }

    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;

    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1.at(i) << " ";
    }
    cout << endl;

    cout << "第一个元素为:" << v1.front() << endl;
    cout << "最后一个元素为:" << v1.back() << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector互换容器
  • swap(vec);——将vec与本身的元素互换
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);

    vector<int>v2;
    for (int i = 10; i > 0; i--)
    {
        v2.push_back(i);
    }
    printVector(v2);

    cout << "交换后:" << endl;
    v1.swap(v2);
    printVector(v1);
    printVector(v2);
}

//实际用途
//巧用swap可以收缩内存空间
void test02()
{
    vector<int>v;
    for (int i = 0; i < 10000; i++)
    {
        v.push_back(i);
    }
    cout << "v的容量为:" << v.capacity()<< endl;
    cout << "v的大小为:" << v.size() << endl;

    v.resize(3);
    cout << "v的容量为:" << v.capacity() << endl;
    cout << "v的大小为:" << v.size() << endl;

    vector<int>(v).swap(v);
    cout << "v的容量为:" << v.capacity() << endl;
    cout << "v的大小为:" << v.size() << endl;
}

int main()
{
    test02();
    system("pause");
    return 0;
}
vector预留空间
  • reverse(int len);——容器预留len个元素长度,预留位置不初始化,元素不可访问
#include<iostream>
#include<vector>
#include<string>
using namespace std;

void printVector(vector<int>& v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

void test01()
{
    vector<int>v1;

    v1.reserve(10000);

    int num = 0;
    int* p = NULL;
    for (int i = 0; i < 10000; i++)
    {
        v1.push_back(i);
        if (p != &v1[0])
        {
            p = &v1[0];
            num++;
        }
    }

    cout << "num = " << num << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector存放内置数据
  • 容器:vector

  • 算法:for_each

  • 迭代器:vector<int> iterator

    #include<iostream>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    void myPrint(int val)
    {
        cout << val << endl;
    }
    
    void test01()
    {
        //创建一个vector容器,数组
        vector<int> v;
        //向容器中插入数据
        v.push_back(10);
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        vector<int>::iterator itBegin = v.begin();  //起始迭代器,指向容器中第一个元素
        vector<int>::iterator itEnd = v.end();      //结束迭代器,指向容器中最后一个元素的下一个位置
    
        while (itBegin != itEnd)
        {
            cout << *itBegin << endl;
            itBegin++;
        }
    
        for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
        {
            cout << *it << endl;
        }
    
        for_each(v.begin(), v.end(), myPrint);
    }
    
    int main()
    {
        test01();
        system("pause");
        return 0;
    }
    
vector存放自定义数据
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};

void test01()
{
    vector<Person> v;
    Person p1("aaa", 10);
    Person p2("bbb", 20);
    Person p3("ccc", 30);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);

    vector<Person*> v1;
    Person p4("ddd", 40);
    Person p5("eee", 50);
    Person p6("fff", 60);
    v1.push_back(&p4);
    v1.push_back(&p5);
    v1.push_back(&p6);

    for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << (*it).m_Name << (*it).m_Age << endl;
    }
    for (vector<Person*>::iterator it = v1.begin(); it != v1.end(); it++)
    {
        cout << (*it)->m_Name << (*it)->m_Age << endl;
    }
}

int main()
{
    test01();
    system("pause");
    return 0;
}
vector容器嵌套容器
#include<iostream>
#include<vector>
#include<string>
using namespace std;



void test01()
{
    vector< vector<int> >v;

    vector<int>v1;
    vector<int>v2;
    vector<int>v3;
    vector<int>v4;

    for (int i = 0; i < 4; i++)
    {
        v1.push_back(i + 1);
        v2.push_back(i + 2);
        v3.push_back(i + 3);
        v4.push_back(i + 4);
    }

    v.push_back(v1);
    v.push_back(v2);
    v.push_back(v3);
    v.push_back(v4);

    for (vector< vector<int>>::iterator it = v.begin(); it != v.end(); it++)
    {
        for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
        {
            cout << *vit << " ";
        }
        cout << endl;
    }
}

int main()
{
    test01();
    system("pause");
    return 0;
}

string容器

string构造函数
  • 本质:string本质上是一个类
  • 特点:
    • string类内部封装了很多成员方法
    • string管理char*所分配的内存,不用担心复制越界和取值越界,由类内部进行负责
#include<iostream>
#include<string>
using namespace std;



void test01()
{
    string s1;//默认构造

    const char* str = "hello world";
    string s2(str);

    cout << "s2 = " << s2 << endl;

    string s3(s2);
    cout << "s3 = " << s3 << endl;

    string s4(10, 'a');
    cout << "s4 = " << s4 << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
string赋值操作
  • string& operator=(const char* s);——char*类型字符串赋值给当前字符串
  • string& operator(const string &s);——把字符串s赋值给当前的字符串
  • string& operator=(char C);——字符赋值给当前的字符串
  • string& assign(const char *s);——把字符串s赋值给当前的字符串
  • string& assign(const char *s, int n);——把字符串s的前n个字赋值给当前的字符串
  • string& assign(const string &s);——把字符串s赋给当前字符串
  • string& assign(int n, char C);——用n个字符c赋值给当前字符串
#include<iostream>
#include<string>
using namespace std;



void test01()
{
    string str1;
    str1 = "hello world";
    cout << "str1 = " << str1 << endl;

    string str2;
    str2 = str1;
    cout << "str2 = " << str2 << endl;

    string str3;
    str3 = 'a';
    cout << "str3 = " << str3 << endl;

    string str4;
    str4.assign("hello C++");
    cout << "str4 = " << str4 << endl;

    string str5;
    str5.assign("hello C++", 5);
    cout << "str5 = " << str5 << endl;

    string str6;
    str6.assign(str5);
    cout << "str6 = " << str6 << endl;

    string str7;
    str7.assign(10, 'w');
    cout << "str7 = " << str7 << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
string拼接
  • string& operator+=(const char* str);——重载+=操作符
  • string& operator+=(const char c);——重载+=操作符
  • string& operator=+(const string& str);——重载+=操作符
  • string& append(const char *s);——把字符串s连接到当前字符串结尾
  • string& append(const char *s, int n);——把字符串s的前n个字符连接到当前字符串的结尾
  • string& append(const string &s);——同operator+=(const string& str)
  • string& append(const string &s, int pos, int n);——字符串s中从pos开始的n个字符串连接到字符串结尾
#include<iostream>
#include<string>
using namespace std;



void test01()
{
    string str1 = "wo";

    str1 += "爱玩游戏";
    cout << "str1 = " << str1 << endl;

    str1 += ':';
    cout << "str1 = " << str1 << endl;

    string str2 = "LOL DNF";
    str1 += str2;
    cout << "str1 = " << str1 << endl;

    string str3 = "I";
    str3.append(" love");
    cout << "str3 = " << str3 << endl;

    str3.append(" game abcde", 6);
    cout << "str3 = " << str3 << endl;

    str3.append(str2);
    cout << "str3 = " << str3 << endl;

    str3.append(str2, 4, 6);
    cout << "str3 = " << str3 << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
string查找和替换
  • int find(const string& str, int pos = 0) const;——查找str带一次出现位置,从pos开始查找
  • int find(const char* s, int pos = 0) const;——查找s第一次出现位置,从pos开始查找
  • int find(const cahr* s, int pos, int n) const;——从pos位置查找s的前n个字符
  • int find(const char c, int pos = 0) const;——查找字符c第一次出现位置
  • int rfind(const string& str, int pos = npos) const;——查找
  • int rfind(const char* s, int pos = npos) const;
  • int rfind(const char* s, int pos, int n) const;
  • int rfind(const char* c, int pos = 0) const;
  • string& replace(int pos, int n, const string& str);
  • string& replace(int pos, int n, const char* s);
#include<iostream>
#include<string>
using namespace std;

//查找
void test01()
{
    string str1 = "abcdefg abcdefg";

    int pos = str1.find("bc");  //从0开始索引
    if (pos == -1)
    {
        cout << "未找到字符串" << endl;
    }
    else
    {
        cout << "找到字符串,pos = " << pos << endl;

    }

    pos = str1.rfind("ab"); //从后面开始查找,返回第一次遇到的索引
    cout << "pos = " << pos << endl;
}

//替换
void test02()
{
    string str2 = "abcdefgh";
    str2.replace(1, 3, "1111");     //从一号位置到三号位置,替换为四个1
    cout << "str2 = " << str2 << endl;
}


int main()
{
    test01();
    system("pause");
    return 0;
}
string字符串比较

比较方式:

字符串比较是按字符的ASCLL码进行对比

  • = 返回 0
  • >返回1
  • <返回-1
  • int comapre(const string &s) const;——与字符串s比较
  • int compare(const char *s) const;——与字符串s比较
#include<iostream>
#include<string>
using namespace std;

void test01()
{
    string str1 = "hello";
    string str2 = "hello";
    string str3 = "sello";
    string str4 = "aello";

    if (str1.compare(str2) == 0)
    {
        cout << "str1 == str2" << endl;
    }
    if (str1.compare(str3) < 0)
    {
        cout << "str1 < str3" << endl;
    }
    if (str1.compare(str4) > 0)
    {
        cout << "str1 > str4" << endl;
    }
}


int main()
{
    test01();
    system("pause");
    return 0;
}
string字符存取
  • char& operator[](int n);
  • char& at(int n);
#include<iostream>
#include<string>
using namespace std;

void test01()
{
    string str1 = "hello";
    cout << "str1 = " << str1 << endl;

    //读取
    for (int i = 0; i < str1.size(); i++)
    {
        cout << str1[i] << " ";
    }
    cout << endl;

    for (int i = 0; i < str1.size(); i++)
    {
        cout << str1.at(i) << " ";
    }
    cout << endl;

    //修改
    str1[0] = 'x';
    cout << "str1 = " << str1 << endl;
    str1.at(1) = 'x';
    cout << "str1 = " << str1 << endl;
}


int main()
{
    test01();
    system("pause");
    return 0;
}
string插入和删除
  • string& insert(int pos, const char* s);——在pos位置插入字符串s
  • string& insert(int pos, const string& str);——在pos位置插入字符串
  • string& insert(int pos, int n, char C);——在指定位置插入n个字符C
  • string& erase(int pos, int n = npos);——删除从pos开始的n个字符
#include<iostream>
#include<string>
using namespace std;

void test01()
{
    string str = "hello";

    //插入
    str.insert(1, "111");
    cout << "str = " << str << endl;

    //删除
    str.erase(1, 3);
    cout << "str = " << str << endl;
}


int main()
{
    test01();
    system("pause");
    return 0;
}
string子串
  • string substr(int pos = 0, int n = npos) const;——返回从pos开始的n个字符组成的字符串
#include<iostream>
#include<string>
using namespace std;

void test01()
{
    string str = "hello";

    string subStr = str.substr(1, 3);

    cout << "subStr = " << subStr << endl;
}

//实用操作
void test02()
{
    string email = "zhangsan@sina.ocm";

    int pos = email.find('@');

    string usename = email.substr(0, pos);

    cout << "usename = " << usename << endl;
}

int main()
{
    test02();
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值