现代程序设计 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

输出结果如下:

posted @ 2013-11-17 23:07  Z-MaC  阅读(157)  评论(0编辑  收藏  举报