现代程序设计 homework-08
现代程序设计 homework-08
第八次作业。
理解C++变量的作用域和生命周期
作用域就是一个变量可以被引用的范围,如:全局作用域、文件作用域、局部作用域;而生命周期就是这个变量可以被引用的时间段。不同生命周期的变量,在程序内存中的分布位置是不一样的。一个程序的内存分为代码区、全局数据区、堆区、栈区,不同的内存区域,对应不同的生命周期。
int* aa(int a) { int b = a; return &b; } int _tmain(int argc, _TCHAR* argv[]) { int i=0; if (i==0){int* p = &i;}//这里的p的作用域在if语句中 int* p = aa(12); //可以再次定义p,因为上面的p的生命周期已完结 cout<<&p<<endl; //不能正确输出,因为指针所指地址生命周期已经完结 return 0; }
理解堆和栈,两种内存的申请和释放的方式
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
简单来说,栈是由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
一下用简单的代码说明C++中堆和栈:
int a = 0; // 全局初始化区 char *p1; // 全局未初始化区 main() { int b; // 栈 char s[] = "abc"; // 栈 char *p2; // 栈 char *p3 = "123456"; // 123456\0在常量区,p3在栈上。 static int c =0; // 全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); // 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); // 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 }
理解unique_ptr和shared_ptr
首先,智能指针都具有普通指针的功能。
unique_ptr是一种不能共享的智能指针,我们不能复制它、在函数中传递它的值或者是在需要使用其副本的STL中使用。总之,unique_ptr所指向的内存只能被它所指,如果其他unique_ptr想要指向同一块内存,需要使用move()语句。
shared_ptr是可以共享地址的指针。其实就是不同于unique_ptr的一种存在。一个shared_ptr可以被复制,给其他shared_ptr赋值,许多shared_ptr指向同一的内存,并都可以修改所指地址中内容。shared_ptr之所以智能,就是当指向一个存储块的shared_ptr数量减至0时(超出生命周期等原因),该存储块会被自动释放。
用“C++0x”,“C++11 & STL”两种不同的代码风格分割一个url,并上传代码到博客上
代码如下:
#include "stdafx.h" #include <stdio.h> #include <regex> #include <string> #include <iostream> using namespace std; class urlDiv { public: urlDiv() { str = ""; isUrl = true; } urlDiv(string s) { str = s + '#'; isUrl = true; } void divStr()//C++0x风格 { resL = 0; string tmp = ""; //暂存字符串 bool hasC = false; //是否出现':' //string tmpDiv = ""; int i=0; while (i < str.length()) { if ((str[i]<='z' && str[i]>='a')||(str[i]<='Z' && str[i]>='A')||(str[i]<='9' && str[i]>='0')||str[i]<0) //数字字母或中文 { tmp+=str[i]; }else { if (str[i]==':') //当前字符为':'判断 { if (i<str.length()-2 && hasC==false) //判断后两位是否为"//" { if (str[i+1]=='/' && str[i+2]=='/') { hasC = true; result[resL++] = tmp; tmp=""; i+=2; }else { isUrl = false; return; } }else { isUrl = false; return; } }else if (str[i] == '-' || str[i] == '_')//-_正常连接 { tmp+=str[i]; }else if (str[i] == '.' || str[i] == '/' || str[i]=='#')//只用'.' '/' '#'分割,其中手动'#'是在字符串末尾加的,便于处理 { if (tmp=="")//如果分隔符前是非法字符,则报错 { isUrl = false; return; } result[resL++] = tmp; //否则加入分隔结果中 tmp = ""; }else { char c=str[i]; isUrl = false; return; } } i++; } } void divStrBySTL()//C++11 & STL风格,用lambda表达式实现 { resL = 0; char s[100]; //与str相等的字符数组 int i; string tmp=""; string tmp2=""; for (i=0;i<str.length();i++) s[i]=str[i]; s[i]='\0'; for_each(s,s+i,[&] (char c){ if ((c<='z' && c>='a')||(c<='Z' && c>='A')||(c<='9' && c>='0')|| c<0 || c=='-' || c=='_') //合法字符加入tmp中 { tmp+=c; if (tmp2=="." || tmp2=="/" || tmp2=="://" || tmp2=="#" || tmp2=="") //如果合法字符前分隔符非法,则报错 tmp2=""; else isUrl = false; }else { tmp2+=c; if (tmp!="") //tmp2为分隔符暂存字符串 { result[resL++] = tmp; tmp=""; } } }); } void outputResult()//输出分隔结果 { if (isUrl) { int i; for (i=0;i<resL-1;i++) cout<<result[i]<<','; cout<<result[i]<<endl; }else cout<<"is not a URL"<<endl; } private: string str; //输入字符 bool isUrl; //是否为合法URL string result[100];//存分隔结果 int resL; //结果数组长度 }; int _tmain(int argc, _TCHAR* argv[]) { string s = "http://msdn.microsoft.com/en-us/library/vstudio/啊哈.aspx"; urlDiv *div = new urlDiv(s); div->divStr(); //使用c++0x风格分隔 div->outputResult(); //使用c++11 & STL风格分隔 div->divStrBySTL(); div->outputResult(); return 0; }
测试输入的URL为:http://msdn.microsoft.com/en-us/library/vstudio/啊哈.aspx
输出结果如下:
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步