【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 |
| ...... |
|_________________|

class Dictionary
{
public:
//......
void read(const std::string & filename);
void store(const std::string & filename);
private:
//......
};

 

转载于:https://www.cnblogs.com/zhangwanying/p/10138282.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值