c++高级进阶,文件流,异常,模板,命名空间,信号处理,多线程等

1.c++文件流

到目前为止,我们已经使用了 iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。本教程介绍如何从文件读取流和向文件写入流。这就需要用到 C++ 中另一个标准库 fstream,它定义了三个新的数据类型:

数据类型

描述

ofstream

该数据类型表示输出文件流,用于创建文件并向文件写入信息。

ifstream

该数据类型表示输入文件流,用于从文件读取信息。

fstream

该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

void open(const char *filename, ios::openmode mode);

下面是c++打开文件的模式

模式标志

描述

ios::app

追加模式。所有写入都追加到文件末尾。

ios::ate

文件打开后定位到文件末尾。

ios::in

打开文件用于读取。

ios::out

打开文件用于写入。

ios::trunc

如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。

上面的模式可以混用

#include <iostream>
using namespace std;
#define endline "\n"
#include <fstream>
#include <string>

int write_file()
    // 写文件
{
        ofstream wfile;
        wfile.open("test.txt");
        wfile << "hello world!" << endline;
        wfile << "xiaoli!" << endline;
        wfile.close();
}

int read_file()
    // 读文件
{
        ifstream rfile;
        rfile.open("test.txt");
        string line;
        while(getline(rfile, line))
        {
                cout << line << endline;
        }
        rfile.close();

}
int file()
    // 以fstream方式读文件
{
        fstream file;
        file.open("test.txt", ios::out|ios::in);
        string line;
        while(getline(file, line))
        {
                cout << line << endline;
        }
        file.close();
}

int main()
{
        write_file();
        read_file();
        file();
}

· getline()的原型是istream& getline ( istream &is , string &str , char delim );

其中 istream &is 表示一个输入流,譬如cin;

string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);

char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为'\n',也就是回车换行符(遇到回车停止读入)。

cin用法

#include <iostream>
using namespace std;
#define endline "\n"
#include <string>

int main()
{
        string name;
        string age;
        cout << "please input your name:" << endline;
        cin >> name;
        cin.ignore();
        cout << "palease input your age:" << endline;
        cin >> age;
        cout << "your name is " << name << " and your age is " << age << endline;

}

ignore() 函数会忽略掉之前读语句留下的多余字符。

2.文件流指针定位

seep()和seekg()函数功能

seekp:设置输出文件流的文件流指针位置

seekg:设置输入文件流的文件流指针位置

函数原型:

ostream& seekp( streampos pos );

ostream& seekp( streamoff off, ios::seek_dir dir );

istream& seekg( streampos pos );

istream& seekg( streamoff off, ios::seek_dir dir );

#include <iostream>
using namespace std;
#define endline "\n"
#include <fstream>
#include <string>

int main()
{
        ifstream file;
        file.open("test.txt");
        file.seekg(2, ios::cur);
        string line;
        getline(file, line);
        cout << line << endline;
        file.close();
}

ios::beg:文件流的起始位置

ios::cur:文件流的当前位置

ios::end:文件流的结束位置

// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg( n );
 
// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg( n, ios::cur );
 
// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg( n, ios::end );
 
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );

3.异常捕获

throw:抛出异常

try:捕获异常

catch:处理异常

以下是标准库异常

异常

描述

std::exception

该异常是所有标准 C++ 异常的父类。

std::bad_alloc

该异常可以通过 new 抛出。

std::bad_cast

该异常可以通过 dynamic_cast 抛出。

std::bad_exception

这在处理 C++ 程序中无法预期的异常时非常有用。

std::bad_typeid

该异常可以通过 typeid 抛出。

std::logic_error

理论上可以通过读取代码来检测到的异常。

std::domain_error

当使用了一个无效的数学域时,会抛出该异常。

std::invalid_argument

当使用了无效的参数时,会抛出该异常。

std::length_error

当创建了太长的 std::string 时,会抛出该异常。

std::out_of_range

该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator[]()。

std::runtime_error

理论上不可以通过读取代码来检测到的异常。

std::overflow_error

当发生数学上溢时,会抛出该异常。

std::range_error

当尝试存储超出范围的值时,会抛出该异常。

std::underflow_error

当发生数学下溢时,会抛出该异常。

 

#include <iostream>
using namespace std;
#define endline "\n"
#include <string>
#include <exception>

class Myexception: public exception
{
        public:
        const char* what() const throw()
        {
                return "my exception";
        }
};
int main()
{
        try
        {
                //int a = 0/0; 
                // 这里的异常没有办法捕获,所以这里会抛出异常并退出程序
                throw exception();
        }catch(exception& e)
        {
                cout << e.what() << endline;
        }
        try
        {
                throw Myexception();
        }catch(Myexception& e)
        {
                cout << "catch a exception:" << endline;
                cout << e.what() << endline;
        }
        try
        {
                throw "throw a exception";
        }catch(const char* e)
        {
                cout << e << endline;
        }
}

注意,异常的捕获是通过throw抛出来的

4.动态内存

栈:在函数内部声明的所有变量都将占用栈内存

堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存

在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。

int* a = new int[2]; // 创建数组对象a,并为其分其内存

如果您不再需要动态分配的内存空间,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。

#include <iostream>
using namespace std;
#define endline "\n";
#include <string>

int main()
{
        double* d = NULL;
        d = new double;
        *d = 2000.1;
        cout << *d << endline;
        delete d;

        int **arr;
        arr = new int *[2];
        for(int i = 0; i < 2; i++)
        {
                arr[i] = new int[2];
        }
        for(int i=0; i < 2; i++)
        {
                delete [] arr[i];
        }
        delete [] arr;
}

5.命名空间

用来区分不同库中相同名称的函数,类,变量,使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。

#include <iostream>
using namespace std;
#define endline "\n"

namespace space1
{
        void func()
        {
                cout << "space1" << endline;
        }
}
namespace space2
{
        void func()
        {
                cout << "space2" << endline;
        }
}

int main()
{
        space1::func();
        space2::func();
}

6.模板

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

函数模板和类模板;

template <class type> ret-type func-name(parameter list)
{
   // 函数的主体
}

 

#include <iostream>
using namespace std;
#define endline "\n"
#include <string>

template <typename T>
void max(T& a,T& b)
{
        if(a > b)
        {
                cout << a << endline;
        }else
        {
                cout << b << endline;
        }
}

int main()
{
        int a = 10;
        int b = 20;
        string c = "asdas";
        string d = "bsafsd";
        max(a,b);
        max(c,d);
}

理解:

这里的T代表了通用类型,既可以表示int,float也能表示其他类型数据

7.信号处理

两个库:<csignal> <cstdlib>

void (*signal (int sig, void (*func)(int)))(int); 第一个参数为信号参数,第二个参数为对应的处理函数

exit(signum) 根据信号退出程序

sleep(); 休眠时间

#include <iostream>
using namespace std;
#define endline "\n"
#include <string>
#include <csignal>
#include <cstdlib>

void func(int signum)
{
        cout << "interrupt signal " << signum << " received " << endline;
        exit(signum);
}

int main()
{
        signal(SIGINT, func);
        while(1)
        {
                cout << "sleep..." << endline;
                sleep(2);
        }
}

raise()函数,生成信号

int raise (signal sig); 参数类型:SIGINT、SIGABRT、SIGFPE、SIGILL、SIGSEGV、SIGTERM、SIGHUP

raise(SIGINT); 就会发出终止信号

8.线程

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

pthread_create 创建一个新的线程,并让它可执行,创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败

参数

描述

thread

指向线程标识符指针。

attr

一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。

start_routine

线程运行函数起始地址,一旦线程被创建就会执行。

arg

运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

#include <pthread.h> 
pthread_exit (status) // 终止线程

 

#include <iostream>
using namespace std;
#define endline "\n"
#include <pthread.h>
#include <stdio.h>
#define thread_num 5

void *func(void* arg)
{
        sleep(3);
        cout << arg << " process is completed" << endline;
}
int main()
{
        pthread_t tids[thread_num];
        for(int i = 0; i < thread_num; i++)
        {
                int ret = pthread_create(&tids[i], NULL, func, &i);
                if (ret != 0)
                {
                        cout << "pthread error...." << ret << endline;
                }
        }
        cout << "wait..." << endline;
        pthread_exit(NULL);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章