现代程序设计 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 在常量区,p3在栈上。 static int c =0; // 全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); // 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); // 123456 放在常量区,编译器可能会将它与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]='