【C/C++】知识点系统复习 (第一周)
2018/12/18 周二
1. C++內存布局分為幾個區域,每個區域有什么特點?
主要可以分為 5 個區域,
(1) 棧區:由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧。
(2) 堆區:由程序員分配釋放。
(3) 全局/靜態區:全局變量和靜態變量的存儲是放在一塊的,在程序編譯時分配。
(4) 文字常量區:存放常量字符串
(5) 程序代碼區:存放函數體(類的成員函數,全局函數)的二進制代碼
內存布局見CSAPP第七章的圖7-13,Linux運行時存儲器映像
衍生問題:
1.1 棧和堆的區別
(1) 管理方式不同;(棧是系統自動分配, 堆是需要程序員申請,程序員釋放,使用不好可能 memory leak)
(2) 空間大小不同;
棧是向低地址擴展的數據結構,它的容量是系統預先設定好的,一般是1M或者2M?申請的時候不要超過棧的剩余空間。
堆是向高地址擴展的數據結構,鏈表的方式來存儲空閑內存地址的,不連續,鏈表遍歷方向是從低地址向高地址。堆可以獲得的空間受限于計算機系統中有效的虛擬內存的大小。(一般來說可以到達 4GB?)
(3) 能否產生碎片不同;(堆是鏈表分配內存,容易產生碎片,棧不會產生碎片)
對于堆來說,頻繁的 new/delete操作勢必會造成內存空間的不連續,從而造成大量的碎片,使得程序效率降低。對于棧來說,不會出現這個問題,因為棧是先進先出的。在棧頂彈出之前,永遠不可能有一個內存塊從棧中間彈出。
(4) 生長方向不同;(棧:高地址->低地址(生長方向向下), 堆: 低地址->高地址(生長方向向上))
(5) 分配方式不同;
內存有兩種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配是用 malloc, calloc 函數進行分配,但是棧的動態分配和堆的動態分配是不同的,棧的動態分配由編譯器進行釋放,不需要手動。
(6) 分配效率不同;(棧:系統分配,速度快,堆:new出來的內存,速度慢)
?
2.當定義類的時候,編譯器會自動為類自動生成那些函數?這些函數各自有什么特點?
構造函數,析構函數?
3.什么是淺拷貝,什么是深拷貝?
淺拷貝是說拷貝指向空間的指針,拷貝出來的目標對象的指針和原對象的指針指向內存的同一塊空間。(幾個對象共用一塊內存空間)
深拷貝是說拷貝對象的具體內容,其內容的地址是程序員向系統申請分配的,拷貝結束后拷貝的內容完全一樣,但是使用的內存空間地址不同。
?
4.實現一個自定義的string類,保證main函數的正確執行。(main函數已經給出)
題解:主要是實現深拷貝情況下的構造函數和析構函數。構造函數包含無參構造函數,有參構造函數,拷貝構造函數,和賦值構造函數。析構函數可以delete開辟的堆空間。
1 /* 2 * File: string.cc 3 * Time: 2018-12-18 19:36:01 4 * Author: wyzhang 5 */ 6 7 #include <cstdio> 8 #include <cstring> 9 #include <iostream> 10 11 using std::cout; 12 using std::endl; 13 14 class String { 15 public: 16 String() 17 : _ptr(nullptr) { 18 _ptr = nullptr; 19 cout << __FUNCTION__ << endl; 20 } 21 String(const char * s) 22 : _ptr(new char[strlen(s) + 1]()) { 23 cout << "String(const char * s)" << endl; 24 strcpy(_ptr, s); 25 } 26 27 String & operator = (const char * s) { 28 cout << "String & operator = (const char * s)" << endl; 29 _ptr = new char[strlen(s) + 1](); 30 strcpy(_ptr, s); 31 } 32 33 String & operator = (const String & rhs) { 34 cout << "String & operator = (const String & rhs)" << endl; 35 if (&rhs == this) { 36 return *this; 37 } 38 _ptr = new char[strlen(rhs._ptr)+1](); 39 strcpy(_ptr, rhs._ptr); 40 } 41 String(const String & rhs) 42 : _ptr(new char[strlen(rhs._ptr) + 1]()) { 43 cout << "String(const String & rhs)" << endl; 44 strcpy(_ptr, rhs._ptr); 45 } 46 ~String() { 47 cout << "~String()" << endl; 48 if (_ptr) { 49 delete[] _ptr; 50 } 51 } 52 void print() { 53 if (!_ptr) { 54 cout << "_ptr is nullptr. " << endl; 55 return; 56 } 57 cout << "string = " << _ptr << endl; 58 } 59 private: 60 char * _ptr; 61 }; 62 int main () { 63 String str1; 64 str1.print(); 65 66 String str2 = "hello world"; 67 String str3("test"); 68 69 cout << __LINE__ << ": " ; str2.print(); 70 cout << __LINE__ << ": " ; str3.print(); 71 72 String str4 = str3; 73 cout << __LINE__ << ": " ; str4.print(); 74 75 str4 = str2; 76 cout << __LINE__ << ": " ; str4.print(); 77 78 return 0; 79 } string.cc?
5.單例模式復習
題解:感覺 singleton 還是寫的有點點問題。先放著吧。這個務必學會手寫。orz。
1 /* 2 * File: singleton.cc 3 * Time: 2018-12-19 10:22:18 4 * Author: wyzhang 5 */ 6 7 //要求: 在內存中只能創建一個對象 8 //1. 該對象不能是棧(全局)對象 9 //2. 該對象只能放在堆中 10 11 //應用場景: 12 //1. 直接替換任意的全局對象(變量)//因為全局對象越少越好 13 //2. 配置文件 14 //3. 詞典類 15 16 //實現步驟: 17 //1. 將構造函數私有化 18 //2. 在類中定一個靜態的指針對象(一般設置為私有),并且在類外初始化為空 19 //3. 定義一個返回值為類指針的靜態成員函數, 20 // 如果2中的指針對象為空,則初始化對象,以后在有對象調用該靜態成員函數的時候,不再初始化對象, 21 // 而是直接返回對象,保證類在內存中只有一個對象 22 23 24 #include <cstdio> 25 #include <iostream> 26 27 using std::cout; 28 using std::endl; 29 30 class Singleton { 31 public: 32 static Singleton * getInstance() { //不是靜態的成員函數就沒法調用,因為沒有對象,需要類名調用 33 if (!_pInstance) { 34 _pInstance = new Singleton(); 35 } 36 return _pInstance; 37 } 38 static void destory() { 39 if (_pInstance) { 40 delete _pInstance; 41 } 42 } 43 void print() { 44 cout << "Singleton::print() " ; 45 if (_pInstance) { 46 printf("_pInstance = %p \n", _pInstance); 47 } 48 } 49 private: 50 Singleton() { 51 cout << "Singleton()" << endl; 52 } 53 ~Singleton() { 54 cout << "~Singleton(): " ; 55 printf("_pInstance = %p \n", _pInstance); 56 } 57 static Singleton * _pInstance; 58 }; 59 60 Singleton * Singleton::_pInstance = 0; 61 62 /* 63 wyzhang@IdeaPad:~/code/c++/20181214/homework$ ./singleton 64 Singleton() 65 p1 = 0x555eef444e70 66 p2 = 0x555eef444e70 67 Singleton::print() _pInstance = 0x555eef444e70 68 ~Singleton(): _pInstance = 0x555eef444e70 69 Singleton::print() _pInstance = 0x555eef444e70 70 ~Singleton(): _pInstance = 0x555eef444e70 71 */ 72 73 int main () { 74 Singleton * p1 = Singleton::getInstance(); 75 Singleton * p2 = Singleton::getInstance(); 76 printf("p1 = %p\n", p1); 77 printf("p2 = %p\n", p2); 78 79 p1->print(); 80 p1->destory(); 81 82 //可能寫的有bug?能調用析構函數兩次? 83 p2->print(); 84 p2->destory(); 85 86 return 0; 87 } singleton.cc?
6.編寫一個類,實現棧操作。
編寫一個類,實現簡單的棧。棧中有以下操作:
> 元素入棧 void push(int);
> 元素出棧 void pop();
> 讀出棧頂元素 int top();
> 判斷棧空 bool emty();
> 判斷棧滿 bool full();
如果棧溢出,程序終止。棧的數據成員由存放10個整型數據的數組構成。先后做如下操作:
> 創建棧
> 將10入棧
> 將12入棧
> 將14入棧
> 讀出并輸出棧頂元素
> 出棧
> 讀出并輸出棧頂元素
1 /* 2 * File: stack.cc 3 * Time: 2018-12-19 11:14:15 4 * Author: wyzhang 5 */ 6 7 #include <cstdio> 8 #include <iostream> 9 #include <vector> 10 11 using std::cout; 12 using std::endl; 13 using std::vector; 14 15 class Stack { 16 public: 17 Stack() { 18 19 } 20 Stack(int n) { 21 nums.reserve(n); //capacity 22 } 23 ~Stack() { 24 nums.clear(); 25 } 26 void push(int num) { 27 if (full()) { 28 cout << "can not push, stk is full. input is " << num << endl; 29 return; 30 } 31 nums.push_back(num); 32 } 33 void pop() { 34 if (empty()) { 35 cout << "can not pop, stk is empty." << endl; 36 return; 37 } 38 nums.pop_back(); 39 } 40 int top() { 41 if (empty()) { 42 cout << "can not get top, stk is empty." << endl; 43 return -1; 44 } 45 return nums.back(); 46 } 47 bool empty() { 48 return nums.size() == 0; 49 } 50 bool full() { 51 return nums.size() == nums.capacity(); 52 } 53 private: 54 vector<int> nums; 55 }; 56 57 int main () { 58 Stack stk = Stack(2); 59 stk.push(10); 60 stk.push(12); 61 stk.push(14); 62 63 cout << "top of stk is " << stk.top() << endl; 64 stk.pop(); 65 cout << "top of stk is " << stk.top() << endl; 66 67 cout << "stk is emtpy : " << stk.empty() << endl; 68 cout << "stk is full : " << stk.full() << endl; 69 return 0; 70 } stack.cc?
7.編寫一個類,實現簡單隊列操作?
編寫一個類,實現簡單的隊列。隊列中有以下操作:
> 元素入隊 void push(int);
> 元素出隊 void pop();
> 讀取隊頭元素 int front();
> 讀取隊尾元素 int back();
> 判斷隊列是否為空 bool emty();
> 判斷隊列是否已滿 bool full();
1 /* 2 * File: queue.cc 3 * Time: 2018-12-19 11:45:10 4 * Author: wyzhang 5 */ 6 7 #include <cstdio> 8 #include <iostream> 9 #include <vector> 10 11 using std::cout; 12 using std::endl; 13 using std::vector; 14 15 class Queue { 16 public: 17 Queue() 18 : first(0) 19 , rear(0) 20 , size(0) 21 , capacity(0) { 22 } 23 Queue(int num) 24 : first(0) 25 , rear(0) 26 , size(0) 27 , capacity(num) { 28 nums.reserve(num); 29 } 30 ~Queue() { 31 nums.clear(); 32 first = rear = -1; 33 size = capacity = 0; 34 } 35 void push(int num) { 36 if (full()) { 37 cout << "can not push element, queue is full. input is " << num << endl; 38 return; 39 } 40 ++size; 41 nums[rear] = num; 42 rear = (rear + 1) % capacity; 43 } 44 void pop() { 45 if (empty()) { 46 cout << "can not pop, queue is empty." << endl; 47 return; 48 } 49 --size; 50 first = (first + 1) % capacity; 51 } 52 int front() { 53 if (empty()) { 54 cout << "can not get front, queue is empty." << endl; 55 return -1; 56 } 57 return nums[first]; 58 } 59 int back() { 60 if (empty()) { 61 cout << "can not get back, queue is empty." << endl; 62 return -1; 63 } 64 int tmp_rear = ((rear + capacity) - 1) % capacity; 65 return nums[tmp_rear]; 66 } 67 bool empty() { 68 return size == 0; 69 } 70 bool full() { 71 return size == capacity; 72 } 73 74 private: 75 vector<int> nums; 76 int first, rear, size, capacity; 77 78 void print() { 79 printf("capacity = %d, size = %d, first = %d, rear = %d, [", capacity, size, first, rear); 80 for (int i = 0; i < capacity; ++i) { 81 printf(" %d", nums[i]); 82 } 83 printf("]\n"); 84 } 85 }; 86 87 int main () { 88 Queue que = Queue(3); 89 que.push(1); 90 printf("%d: que.front = %d, que.back = %d\n", __LINE__, que.front(), que.back()); 91 que.push(2); 92 que.push(3); 93 que.push(4); 94 printf("%d: que.front = %d, que.back = %d\n", __LINE__, que.front(), que.back()); 95 que.pop(); 96 printf("%d: que.front = %d, que.back = %d\n", __LINE__, que.front(), que.back()); 97 98 printf("begin while loop\n"); 99 while (!que.empty()) { 100 printf("%d: que.front = %d, que.back = %d\n", __LINE__, que.front(), que.back()); 101 que.pop(); 102 } 103 return 0; 104 } queue.cc?
8.封裝Linux下互斥鎖和條件變量
?
9. 實現只能生成棧對象的代碼
?
10. 實現只能生成堆對象的代碼
?
11. 統計一篇英文(The_Holy_Bible.txt)文章中出現的單詞和詞頻
輸入:某篇文章的絕對路徑
輸出:詞典(詞典中的內容為每一行都是一個“單詞 詞頻”)
詞典的存儲格式如下
-----------------
| a 66 |
| abandon 77 |
| public 88 |
| ...... |
|_________________|
?
轉載于:https://www.cnblogs.com/zhangwanying/p/10138282.html
總結
以上是生活随笔為你收集整理的【C/C++】知识点系统复习 (第一周)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数论基础 练习
- 下一篇: s3c2440移植MQTT