现代程序设计 homework-08
1. 理解C++变量的作用域和生命周期
a) 用少于10行代码演示你对局部变量的生命周期的理解
1 /*------局部变量的生命周期的理解------*/ 2 void test1()//在if代码块中中定义的string局部变量str在超出该代码块时已经无法引用,会报错"未声明标识符str",即str已经被销毁 3 { 4 if(true) 5 { 6 string str; 7 str="Hello,World"; 8 } 9 cout<<str<<endl; 10 }
2. 理解堆和栈,两种内存的申请和释放的方式
a) 用少于30行代码演示你对堆和栈两种内存申请方式的理解
1 /*--- 2 栈区:由编译器自动分配和释放,存放函数的参数值,局部变量的值等, 3 甚至函数的调用过程都是用栈来完成 4 堆区:一般由程序猿手动申请以及释放,若程序猿不释放,程序结束时 5 可能由操作系统回收 6 ---*/ 7 void test2() 8 { 9 /*--- 10 new即分配了一块堆内存,指针p分配一块栈内存 11 即在栈内存中存放了一个指向一块堆内存的指针p 12 ---*/ 13 /*--- 14 据说这是VC6的汇编码 15 push 14h 16 17 0040102A call operator new (00401060) 18 19 0040102F add esp,4 20 mov dword ptr [ebp-8],eax 21 mov eax,dword ptr [ebp-8] 22 mov dword ptr [ebp-4],eax 23 ---*/ 24 int *p=new int[10]; 25 delete[] p; 26 }
3. 理解unique_ptr和shared_ptr
a) http://msdn.microsoft.com/en-us/library/vstudio/hh279676.aspx
b) http://msdn.microsoft.com/en-us/library/vstudio/hh279669.aspx
1 /*------关于shared_ptr和unique_ptr------*/ 2 /*--- 3 shared_ptr实现的是引用计数型的智能指针,可以被自由拷贝赋值, 4 在任意的地方共享它,当引用计数为0时它才是年初被包装 5 的动态分配的对象 6 unique_ptr是独享所有权的智能指针,无法进行复制构造,也无法进行 7 复制赋值操作,但可以进行移动构造和移动赋值操作当它本身 8 被删除释放的时候会使用给定的删除器释放它指向的对象 9 ---*/ 10 void test3() 11 { 12 shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr 13 assert(sp.unique()); //现在shared_ptr是指针的唯一持有者 14 shared_ptr<int> sp2 = sp; //第二个shared_ptr,拷贝构造函数 15 assert(sp == sp2 && sp.use_count() == 2); //两个shared_ptr相等,指向同一个对象,引用计数为2 16 *sp2 = 100; //使用解引用操作符修改被指对象 17 assert(*sp == 100); //另一个shared_ptr也同时被修改 18 sp.reset(); //停止shared_ptr的使用 19 assert(!sp); //sp不再持有任何指针(空指针) 20 }
4. 请尝试用“C++0x”,“C++11 & STL”两种不同的代码风格分割一个url,并上传代码到博客上。
For example:
Input: http://msdn.microsoft.com/en-us/library/vstudio/hh279674.aspx
Output: http, msdn, Microsoft, com, en-us, library, vstudio, hh279674, aspx
1 // homework-08.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<string> 9 #include<cstdlib> 10 #include<algorithm> 11 #include<vector> 12 #include<regex> 13 #include<memory> 14 #include<cassert> 15 using namespace std; 16 const int NumDelimiter=3; 17 const string delimiter[NumDelimiter]={"://","/","."}; 18 class MyUrl 19 { 20 public: 21 MyUrl(); 22 ~MyUrl(); 23 bool Getstring();//得到输入 24 void PrintResult();//输出分隔结果 25 void SeperateUrl();//利用STL分隔URL 26 void SeperateUrlWithoutSTL();//不用STL分隔URL 27 bool IsUrl();//判断当前输入是否为URL,利用正则表达式,速度很慢 28 29 private: 30 string url;//输入 31 vector<string> result;//分隔结果 32 }; 33 34 MyUrl::MyUrl() 35 { 36 } 37 38 MyUrl::~MyUrl() 39 { 40 } 41 void MyUrl::PrintResult() 42 { 43 for(vector<string>::size_type i=0;i!=result.size();i++) 44 { 45 cout<<result[i]; 46 if(i==result.size()-1) 47 { 48 cout<<endl; 49 } 50 else 51 { 52 cout<<","; 53 } 54 } 55 } 56 bool MyUrl::IsUrl() 57 { 58 // const regex pattern("^((site)|((ht|f)tp(s?)))\:\/\/[a-zA-Z0-9\u4e00-\u9fa5\-\._]+(\.[a-zA-Z0-9\u4e00-\u9fa5\-\._]+){2,}(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&%\$#_]*)?$");//其中\u4e00-\u9fa5为中文字符unicode编码范围 59 // const regex pattern("^(((ht|f)tp(s?))\://)?(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\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$"); 60 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\-\.\?\,\'\/\\\+&%\$#_]*)?$"); 61 try 62 { 63 if(!regex_match(url,pattern)) 64 { 65 throw("The format of the Url you input is not true"); 66 } 67 } 68 catch(char *ExceptionStr) 69 { 70 cout<<"Exception: "<<ExceptionStr<<endl; 71 return false; 72 } 73 return true; 74 } 75 bool MyUrl::Getstring() 76 { 77 cout<<"Please input the Url you want to seperate: "<<endl; 78 try 79 { 80 if(getline(cin,url)==nullptr) 81 { 82 throw("Input Error"); 83 } 84 } 85 catch(char *ExceptionStr) 86 { 87 cout<<"Exception: "<<ExceptionStr<<endl; 88 return false; 89 } 90 return true; 91 } 92 void MyUrl::SeperateUrl() 93 { 94 size_t lastIndex=0;//截取起始点 95 size_t templastIndex=0; 96 size_t index=url.find_first_of(delimiter[0],lastIndex);//截取终止点 97 size_t tempIndex=string::npos; 98 int tempPos=0;//记录当前截取的是哪个分隔符 99 100 while(index!=string::npos) 101 { 102 result.push_back(url.substr(lastIndex,index-lastIndex)); 103 lastIndex=index+delimiter[tempPos].length(); 104 tempIndex=string::npos; 105 for(int i=0;i<NumDelimiter;i++) 106 { 107 templastIndex=url.find_first_of(delimiter[i],lastIndex); 108 if(templastIndex<=tempIndex) 109 { 110 tempIndex=templastIndex; 111 tempPos=i; 112 } 113 } 114 index=tempIndex; 115 } 116 if(index-lastIndex>0) 117 { 118 result.push_back(url.substr(lastIndex,index-lastIndex)); 119 } 120 } 121 void MyUrl::SeperateUrlWithoutSTL() 122 { 123 int begin=0;//记录跳过://后的开始点 124 int length=url.length(); 125 string tempStr=""; 126 for(int i=0;i<length;i++) 127 { 128 if(url[i]==':'&&url[i+1]=='/'&&url[i+2]=='/') 129 { 130 result.push_back(tempStr); 131 begin=i+3;//跳过:// 132 break; 133 } 134 tempStr+=url[i]; 135 } 136 tempStr=""; 137 for(int i=begin;i<length;i++) 138 { 139 if(i==length-1) 140 { 141 tempStr+=url[i]; 142 result.push_back(tempStr); 143 } 144 else if(url[i]=='.'||url[i]=='/') 145 { 146 result.push_back(tempStr); 147 tempStr=""; 148 } 149 else 150 { 151 tempStr+=url[i]; 152 } 153 } 154 } 155 int _tmain(int argc, _TCHAR* argv[]) 156 { 157 while(true) 158 { 159 MyUrl myUrl=MyUrl::MyUrl(); 160 if(!myUrl.Getstring())//未正确输入 161 { 162 continue; 163 } 164 if(!myUrl.IsUrl())//未输入正确格式的URL 165 { 166 continue; 167 } 168 myUrl.SeperateUrl(); 169 // myUrl.SeperateUrlWithoutSTL(); 170 myUrl.PrintResult(); 171 myUrl.~MyUrl(); 172 173 cout<<"Enter Y to continue Or break"<<endl; 174 char ch=getchar(); 175 if(ch=='Y'||ch=='y') 176 { 177 continue; 178 } 179 else 180 { 181 break; 182 } 183 } 184 return 0; 185 } 186 187 188 // 189 ///*------局部变量的生命周期的理解------*/ 190 //void test1()//在if代码块中中定义的string局部变量str在超出该代码块时已经无法引用,会报错"未声明标识符str",即str已经被销毁 191 //{ 192 // if(true) 193 // { 194 // string str; 195 // str="Hello,World"; 196 // } 197 // cout<<str<<endl; 198 //} 199 ///*------栈和堆两种内存申请方式------*/ 200 ///*--- 201 //栈区:由编译器自动分配和释放,存放函数的参数值,局部变量的值等, 202 // 甚至函数的调用过程都是用栈来完成 203 //堆区:一般由程序猿手动申请以及释放,若程序猿不释放,程序结束时 204 // 可能由操作系统回收 205 //---*/ 206 //void test2() 207 //{ 208 // /*--- 209 // new即分配了一块堆内存,指针p分配一块栈内存 210 // 即在栈内存中存放了一个指向一块堆内存的指针p 211 // ---*/ 212 // /*--- 213 // 据说这是VC6的汇编码 214 // push 14h 215 // 216 // 0040102A call operator new (00401060) 217 // 218 // 0040102F add esp,4 219 // mov dword ptr [ebp-8],eax 220 // mov eax,dword ptr [ebp-8] 221 // mov dword ptr [ebp-4],eax 222 // ---*/ 223 // int *p=new int[10]; 224 // delete[] p; 225 //} 226 ///*------关于shared_ptr和unique_ptr------*/ 227 ///*--- 228 //shared_ptr实现的是引用计数型的智能指针,可以被自由拷贝赋值, 229 // 在任意的地方共享它,当引用计数为0时它才是年初被包装 230 // 的动态分配的对象 231 //unique_ptr是独享所有权的智能指针,无法进行复制构造,也无法进行 232 // 复制赋值操作,但可以进行移动构造和移动赋值操作当它本身 233 // 被删除释放的时候会使用给定的删除器释放它指向的对象 234 //---*/ 235 //void test3() 236 //{ 237 // shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr 238 // assert(sp.unique()); //现在shared_ptr是指针的唯一持有者 239 // shared_ptr<int> sp2 = sp; //第二个shared_ptr,拷贝构造函数 240 // assert(sp == sp2 && sp.use_count() == 2); //两个shared_ptr相等,指向同一个对象,引用计数为2 241 // *sp2 = 100; //使用解引用操作符修改被指对象 242 // assert(*sp == 100); //另一个shared_ptr也同时被修改 243 // sp.reset(); //停止shared_ptr的使用 244 // assert(!sp); //sp不再持有任何指针(空指针) 245 //}
测试用例:
考察重点:
1. 类的定义和使用,基本成员是否完整
定义了一个MyUrl类,成员如下
1 class MyUrl 2 { 3 public: 4 MyUrl(); 5 ~MyUrl(); 6 bool Getstring();//得到输入 7 void PrintResult();//输出分隔结果 8 void SeperateUrl();//利用STL分隔URL 9 void SeperateUrlWithoutSTL();//不用STL分隔URL 10 bool IsUrl();//判断当前输入是否为URL,利用正则表达式,速度很慢 11 12 private: 13 string url;//输入 14 vector<string> result;//分隔结果 15 };
2. 输入参数的检查及其他鲁棒性的考虑
这里对输入是否正确和输入的字符串是否为正确的URL形式进行了检测
对于输入是否为正确的URL形式用了正则表达式来实现,速度有点慢;后来改进了正则表达式的描述,速度很nice
1 bool MyUrl::IsUrl() 2 { 3 // const regex pattern("^((site)|((ht|f)tp(s?)))\:\/\/[a-zA-Z0-9\u4e00-\u9fa5\-\._]+(\.[a-zA-Z0-9\u4e00-\u9fa5\-\._]+){2,}(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&%\$#_]*)?$");//其中\u4e00-\u9fa5为中文字符unicode编码范围 4 // const regex pattern("^(((ht|f)tp(s?))\://)?(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\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$"); 5 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\-\.\?\,\'\/\\\+&%\$#_]*)?$"); 6 try 7 { 8 if(!regex_match(url,pattern)) 9 { 10 throw("The format of the Url you input is not true"); 11 } 12 } 13 catch(char *ExceptionStr) 14 { 15 cout<<"Exception: "<<ExceptionStr<<endl; 16 return false; 17 } 18 return true; 19 } 20 bool MyUrl::Getstring() 21 { 22 cout<<"Please input the Url you want to seperate: "<<endl; 23 try 24 { 25 if(getline(cin,url)==nullptr) 26 { 27 throw("Input Error"); 28 } 29 } 30 catch(char *ExceptionStr) 31 { 32 cout<<"Exception: "<<ExceptionStr<<endl; 33 return false; 34 } 35 return true; 36 }
3. STL和C++11元素的使用
在分隔字符串操作中使用STL中string中的find()和substr()方法,C++11元素主要是使用了正则表达式
1 void MyUrl::SeperateUrl() 2 { 3 size_t lastIndex=0;//截取起始点 4 size_t templastIndex=0; 5 size_t index=url.find_first_of(delimiter[0],lastIndex);//截取终止点 6 size_t tempIndex=string::npos; 7 int tempPos=0;//记录当前截取的是哪个分隔符 8 9 while(index!=string::npos) 10 { 11 result.push_back(url.substr(lastIndex,index-lastIndex)); 12 lastIndex=index+delimiter[tempPos].length(); 13 tempIndex=string::npos; 14 for(int i=0;i<NumDelimiter;i++) 15 { 16 templastIndex=url.find_first_of(delimiter[i],lastIndex); 17 if(templastIndex<=tempIndex) 18 { 19 tempIndex=templastIndex; 20 tempPos=i; 21 } 22 } 23 index=tempIndex; 24 } 25 if(index-lastIndex>0) 26 { 27 result.push_back(url.substr(lastIndex,index-lastIndex)); 28 } 29 }
1 const regex pattern("^((site)|((ht|f)tp(s?)))\:\/\/[a-zA-Z0-9\u4e00-\u9fa5\-\._]+(\.[a-zA-Z0-9\u4e00-\u9fa5\-\._]+){2,}(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&%\$#_]*)?$");//其中\u4e00-\u9fa5为中文字符unicode编码范围
4. 除http://之外, 是否有考虑ftp:// site:// 等情况
考虑了http:// https:// ftp:// site://情况,不过这不是重点,只需要在正则表达式中加需要的前缀即可
1 // const regex pattern("^((site)|((ht|f)tp(s?)))\:\/\/[a-zA-Z0-9\u4e00-\u9fa5\-\._]+(\.[a-zA-Z0-9\u4e00-\u9fa5\-\._]+){2,}(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&%\$#_]*)?$");//其中\u4e00-\u9fa5为中文字符unicode编码范围 2 // const regex pattern("^(((ht|f)tp(s?))\://)?(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\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$"); 3 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\-\.\?\,\'\/\\\+&%\$#_]*)?$"); 4
5. 是否考虑url中的中文
中文这里利用中文字符unicode编码范围为\u4e00-\u9fa5的特点,在正则表达式中相应表示
1 // const regex pattern("^((site)|((ht|f)tp(s?)))\:\/\/[a-zA-Z0-9\u4e00-\u9fa5\-\._]+(\.[a-zA-Z0-9\u4e00-\u9fa5\-\._]+){2,}(\/?)([a-zA-Z0-9\u4e00-\u9fa5\-\.\?\,\'\/\\\+&%\$#_]*)?$");//其中\u4e00-\u9fa5为中文字符unicode编码范围 2 // const regex pattern("^(((ht|f)tp(s?))\://)?(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\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$"); 3 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\-\.\?\,\'\/\\\+&%\$#_]*)?$"); 4
6. 算法是否简洁高效
正则表达式验证是否为URL,非常简洁,但不高效,
分隔字符串算法复杂度为O(n*m),n为URL长度,m为分隔符数量,非常简洁高效
至于其他匹配算法,不会..
7. 代码风格
命名遵循业界规范命名方式,代码缩进风格良好