homework-08

(1) 理解C++变量的作用域和生命周期

作用域是空间上的概念,包含全局作用域、文件作用域和局部作用域。生命周期是时间上的概念,其内存分配位置不同,可被引用的时间段也不同。static关键字和{}等标识符可以用来指定变量的作用域和生命周期。

局部变量,分配内存是分配在栈存储区上的,其作用域也只是在局部函数内,在定义该变量的函数内,只要出了该函数,该局部变量就不再起作用,该变量的生命周期也只是和该函数同在。

局部静态变量,分配的内存也是在静态存储内存上的,其第一次初始化后就一直存在直到程序结束,该变量的特点是其作用域只在定义它的函数内可见,出了该函数就不可见了。

1 int function1(int n){
2     static int i = 0; //静态局部变量生命周期为程序运行期
3     return i++; // i只初始化一次,每次返回值递增
4 }
5 int function2(){
6     int i = 0; //OK, 上述i作用域之外
7     return i++; //每次返回值相同,因为生命周期外被销毁,每次重新初始化。
8 }

(2) 理解堆和栈,两种内存的申请和释放的方式

 堆和栈是内存分配方式之二,除此之外还有全局变量与静态变量区、代码区等等。

 栈,由编译器自动分配和释放,主要是函数体的地址,参数和局部变量,静态变量不包含其中,操作方式类似于数据结构中的栈。

 堆,由程序员手动完成申请和释放的,需要通过malloc和new手动申请,使用后使用delete手动释放。程序员没有手动释放的话,当程序结束时由系统释放没有释放的空间,其实现方式与数据结构中的堆完全不同,此时的堆的实现方式有些类似于数据结构中的链表。

 1 main(){
 2     int b; //
 3     char s[] = "abc"; //
 4     char *p2; //
 5     char *p3 = "123456"; // 123456\0在常量区,p3在栈上。
 6     static int c =0//全局(静态)初始化区
 7     dog Wangwang = new dog("Wangwang"); // Wangwang狗人工申请,在堆上
 8     p1 = (char *)malloc(10); //堆,手动申请手动释放
 9     p2 = (char *)malloc(20); //自主确定大小
10     strcpy(p1, "123456"); 
11    // 123456\0放在常量区,编译器可能会将它与p3所指的"123456"优化成一个地方。
12 }

补充:

 

栈,只要栈剩余的空间大小比申请的空间小,系统就自动为其分配空间,否则就会报错说明栈空间溢出。

堆,首先要知道操作系统中有一个存放空闲存储块的链表,当程序员申请空间的时候,系统就会遍历整个链表,找到第一个比申请空间大的空闲块节点,系统会将该空闲块从空闲链表中删除,分配给程序,同时系统会记录这个空闲块的首地址和申请的大小,当程序员使用delete释放该空间的时候能够找到该存储区。另外,申请的空间不一定与找到的空闲块大小相同,多出来剩余的空闲区会被系统重新添加到空闲链表中。

栈,是一种向低地址扩展的数据结构,并且是连续的存储空间,所以栈顶和栈的最大容量是固定的,在windows下,栈的最大容量是2m或者是1m,是在编译的时候就已经确定的,当申请空间大于栈的剩余空间的时候,就会报错说明overflow,所以栈能够申请的空间是比较有限的。

堆,是一种向高地址扩展的数据结构,并且是不连续的,因为系统采用的是链表的方式存放空闲存储块,当然是不连续的,链表的遍历方向是由低向高的,所以堆能够申请的空间的大小其实等同于整个系统的虚拟内存,只要还有内存空间,那么堆就能够不受限制的申请空间,这种方式比较灵活,申请空间也较大。

 

(3) 理解unique_ptr和shared_ptr

 两者均是C++11的智能指针。unique_ptr只可以被move,并且原unique_ptr失效,不可被传值、取值等任何或进行任何需要复制的算法和操作。这个限制防止了很多冲突。

shared_ptr可以被复制给其他shared_ptr, 可以在函数调用中作为参数进行传递,其根本是允许了多个指针指向同一个目标,同一个目标可以被多个指针操作。当指向该目标的有效指针减为0,则目标被自动释放。

个人的理解是,unique_ptr防止了指针操作的冲突,而shared_ptr防止了 memory leak, 程序员不必纠结于内存释放。但是shared+ptr也有低效率的劣势,并存在互环问题。

(4) 尝试用“C++0x”,“C++11 & STL”两种不同的代码风格分割一个url

c++0x风格,使用strtok()分割。

 1 #include <stdio>
 2 #include <string>
 3 int main(){
 4         char s[50];
 5         const char *div = "/.:";
 6         gets(s);
 7         char *tokenPtr;
 8         tokenPtr = strtok(s,div);
 9         while(tokenPtr != NULL){
10                 printf("%s,",tokenPtr);
11                 tokenPtr=strtok(NULL,div);
12         }
13         return 0;
14 }

C++和STL,我使用STL的容器来处理。

 1 #include<vector>
 2 using namespace std;
 3 
 4 vector<string> split(string s, string div){ //输入串和分割字符串
 5     string::size_type idx;
 6     vector<string> out;
 7     for(int i=0; i < s.size(); i++){
 8         idx = s.find(div, i); //查找分割位置
 9         if(idx < size){
10             string str=s.substr(i, idx - i);//切割出子串
11             out.push_back(str + ","); //拼到输出串
12             i = idx + div.size()-1;
13         }
14     }
15     return out;
16 }

不过,这个用C#的Split()函数更方便。鲁棒性可以通过将split放到try{}catch{}中保证。

1. 这里面能够处理site:// http:// https://等开头,也可以处理中文(必要时可改变字符串编码)。

2. 还需要的就是鲁棒性不够,因为目前还没对输入进行检查。两种风格的代码,都可以预先用下面的正则表达式匹配检查是不是url:

const regex pattern("^((http|https|site|ftp|ftps)\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$");

 

 

posted @ 2013-11-18 10:54  Shone JIN  阅读(212)  评论(0编辑  收藏  举报