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);
}

 

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