C/C++(C++内存管理,内联函数,类型转换,命名空间,string类)

---恢复内容开始---

## 内存管理 ### new/delete C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请和释放。而 c++则提供了两关键字 new 和 delete ,new delete关键字。 **生成单变量空间和数组空间**
int *p = (int *)malloc(sizeof(int));//c

int *p = static_cast<int*>(malloc(sizeof(int)));//c过渡到c++
int *p = new int(200);//C++单变量初始化
cout<< *p<<endl;
string *ps = new string("assassin");
cout<< *ps<<endl;

struct Stu
{
   int age;
   string name;
};
Stu* pStu = new Stu{23,"assassin"};
cout<< pStu->age<<endl;
cout<< pStu->name<<endl;
//23
//assassin

生成数组

char *p = new int[4];
strcpy(p,"china");
cout<<p<<endl;

int *pi = new int[5];
//int *pi = new int[5]{0};//初始化0,一般不这样
memset(pi,0,sizeof(int[5]));//初始化
for(int i = 0;i < 5;i++)
{
    cout<<pi[i]<<endl;
}

生成指针数组:

char **p = new char*[5]{NULL};
p[0] = "assassin";
p[1] = "automan";
p[2] = "wunworld";
while(*p)
{
    cout<<*p++<<endl;
}
/*
assassin
automan
wunworld
*/

生成二维数组;

int (*pa)[4] = new int[3][4]{{0}};//初始化
for(int i = 0;i < sizeof(int[3][4])/sizeof(int[4]);i++)
{
    for(int j = 0;j < 4;j++)
    {
        cout<<pa[i][j]<<" ";
    }
    cout<<endl;
}
/*
0 0 0 0
0 0 0 0
0 0 0 0
*/
//多维
int (*ppp) [3][4][5] = new int[2][3][4];

释放delete:

int *p = new int;
delete p;
int *a = new int[100];
delete []a;//正确的释放
delete a;//只把第一个释放了

int (*aa)[4] = new int[3][4];
delete []aa;//多位的数组也是一个方括号,底层用递归

注意事项

1,new/delete 是关键字,效率高于 malloc 和 free.
2,配对使用,避免内存泄漏和多重释放。
3,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free;

//c
int *p = (int *)malloc(100);
if(NULL == p)
    return -1;
//c++
int *pi = new (std::nothrow) int[100];
if(pi == NULL)
    return -1;

内联函数(inline function)

c语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错,容易使得内存text段体积变大,不会类型检查。

#define SQR(i) ((i)*(i))
int main()
{
    int i=0;
    while(i<5)
    {
        // printf("%d
",SQR(i++));
        printf("%d
",sqr(i++));
    }
    return 0;
}

int sqr(int i)
{
    return i*i;
}
/*
优点:一段高度抽象的逻辑,不易产生歧义,是的text段体积变小,会类型检查。
缺点:函数调用的压栈与出栈的开销
*/

内联函数兼有宏和函数的优点。系统自己有一套优化方案,inline变成了给编译器的一种建议。

inline int sqr(int i)
{
    return i*i;
}

评价
优点:避免调用时的额外开销(入栈与出栈操作)
代价:由于内联函数的函数体在代码段中会出现多个“副本”,因此会增加代码段的空间。
本质:以牺牲代码段空间为代价,提高程序的运行时间的效率。
适用场景:函数体很“小”,且被“频繁”调用。

强制类型转化

static_cast 
//对于隐时类型可以转化的
reinterpret_cast
//对于无隐式的类型转化,static_cast不可用
const_cast
//
dynamic_cast
//

static_cast

float a = 5.6;
int b = 5;

b = static_cast<int>(a);//把a转成int赋值给b

void *p,int *q;
p = q;//可以
q = p;//不可以,任何指针都可以赋值给void *类型,但是void *类型不可以赋值给指针类型。
q = static_cast<int*>(p);

reinterpret_cast

int a[5] = {1,2,3,4,5};
int *p = reinterpret_cast<int*>((reinterpret_cast<int>(a)+1));

const_cast
( 脱) 常类型转换,只能引用与指针与引用
const 一定不可以修改

void func(const int &r)
{

}
void func2(int & v)
{
    cout<<v<<endl;
}

int main()
{
    const int a = 19;
    func(10);//可以
    func(a+10);//可以,应为参数中有const修饰。
    func2(const_cast<int&>(a));//因为a是const int类型
    int & ra = const_cast<int&>(a);
    ra = 200;
    cout<<"a = "<<a<<" ra= "<<ra<<endl;
    cout<<"&a = "<<&a<<" ra = "<<&ra<<endl;
    /*
    a = 19 ra = 200
    &a = 0x... 不一样
    */
}

用来移除对象的常量性(cast away the constness)使用 const_cast 去除 const 限定的目的不是为了修改它的内容,使用 const_cast 去除 const 限定,通常是为了函数能够接受这个实际参数。
可以改变 const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为 .

const 常变量

#defined N 200 //宏,在预处理的阶段发生了替换
const int a = 100;//编译阶段发生了替换
//const 永远不会发生改变

命名空间(namespace scope)

//全局就是无名空间
int v = 55;
int main()
{
    int *p = &v;//访问全局的
    int v =5;
    cout<<v<<endl;//5
    cout<<*p<<endl;//55

    cout<<::v<<endl;//::作用域运算符,前面要命名空间,平常调配用的函数之前省略::
    
    return 0;
}

namespace 是对全局命名空间的再次划分

#include<iostream>
using namespace std;
namespace Spac{
    int a;//全局变量 
    struct Stu{};//数据类型 
    void func();//函数 
    namespace//其它命名空间 
}

使用:

#include<iostream>
using namespace std;
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    Space::x = 200;//这种与本地的不会冲突
    cout<<Space::x<<endl;//200

    using Space::x;//在这作用域内的x都是Space命名空间中的x
    x = 20;
    cout<<x<<endl;

    using Space Space;//直接把Space这个命名空间打开
    x = 20;
    y = 30;


    return 0;
}

各种之间冲突解决

利用最小单位的作用域块

#include<iostream>
using namespace std;//标中库空间命名
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    {
        using Space Space;
        x = 20;
        y = 30;
    }
    {
        using Space Other;
        x = 50;
        y = 70;
    }
    int x,y;

    return 0;
}

支持嵌套

namespace Space {
    int x;
    int y;
    namespace Other {
        int m;
        int n;
    }
}
int main()
{
    using namespace Space::Other;//使用Other命名空间中的变量,不建议嵌套
    m = 30;
    return 0;
}

协同开发中的使用

namespace Space {
    int x;
}
namespace Space {
    int y;
}//命名空间相同会自动合并
int main()
{
    using namespace Space;
    x = 10;
    y = 20;
    return 0;
}

系统string类

string是一个类而非关键字,初始化比较灵活(类似js中var)

string s = "assassin";//赋值
string s2 = "assassin1";
cout<<s2.size()<<endl;//大小
string s3 = "wunworld";
s3 += s2;//拼接
if(s == s2)//比较 
    cout<<"s = s2"<<endl;
else if(s > s2)
    cout<<"s > s2"<<endl;
else
    cout<<"s < s2"<<endl;

char buf[1024];
strcpy(buf,s.c_str());
//如果和字符连用时,一定用c_str(),返回的是char *类型
//交换swap(string &s2)成员函数
s.swap(s2);

查找:

int find(char c, int pos = 0);
int find(char * s, int pos = 0);
//返回下标值,没有找到返回-1,默认从 0 下标开找

eg:

string s = "assassin";
int n = s.find("i",0);
cout<<n<<endl;//6

string 类型数组

string sArray[10] = {
                        "0",
                        "1",
                        "22",
                        "333",
                        "4444",
                        "55555",
                        "666666",
                        "7777777",
                        "88888888",
                        "999999999",
};
for(int i=0; i<10; i++)
{
    cout<<sArray[i]<<endl;
}

string 数组是高效的,如果用二维数组来存入字符串数组的话,则容易浪费空间,此时列数是由最长的字符串决定。如果用二级指针申请堆空间,依据大小申请相应的空间,虽然解决了内存浪费的问题,但是操作麻烦。用 string 数组存储,字符串数组的话,效率即高又灵活。

学习C++的建议:
1、在 C++中几乎不需要用宏,用 const 或 enum 定义显式的常量,用 inline 避免函数 调用的额外开销,用模板去刻画一族函数或类型,用 namespace 去避免命名冲突。
2、不要在你需要变量之前去声明,以保证你能立即对它进行初始化。
3、不要用 malloc,new 运算会做的更好。
4、避免使用 void*、指针算术、联合和强制,大多数情况下,强制都是设计错误的指示器。
5、尽量少用数组和 C 风格的字符串,标准库中的 string 和 vector 可以简化程序。
6、更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制

---恢复内容结束---

## 内存管理

new/delete

C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请和释放。而 c++则提供了两关键字 new 和 delete ,new delete关键字。
生成单变量空间和数组空间

int *p = (int *)malloc(sizeof(int));//c

int *p = static_cast<int*>(malloc(sizeof(int)));//c过渡到c++
int *p = new int(200);//C++单变量初始化
cout<< *p<<endl;
string *ps = new string("assassin");
cout<< *ps<<endl;

struct Stu
{
   int age;
   string name;
};
Stu* pStu = new Stu{23,"assassin"};
cout<<pStu->age<<endl;
cout<<pStu->name<<endl;
//23
//assassin

生成数组

char *p = new int[4];
strcpy(p,"china");
cout<<p<<endl;

int *pi = new int[5];
//int *pi = new int[5]{0};//初始化0,一般不这样
memset(pi,0,sizeof(int[5]));//初始化
for(int i = 0;i < 5;i++)
{
    cout<<pi[i]<<endl;
}

生成指针数组:

char **p = new char*[5]{NULL};
p[0] = "assassin";
p[1] = "automan";
p[2] = "wunworld";
while(*p)
{
    cout<<*p++<<endl;
}
/*
assassin
automan
wunworld
*/

生成二维数组;

int (*pa)[4] = new int[3][4]{{0}};//初始化
for(int i = 0;i < sizeof(int[3][4])/sizeof(int[4]);i++)
{
    for(int j = 0;j < 4;j++)
    {
        cout<<pa[i][j]<<" ";
    }
    cout<<endl;
}
/*
0 0 0 0
0 0 0 0
0 0 0 0
*/
//多维
int (*ppp) [3][4][5] = new int[2][3][4];

释放delete:

int *p = new int;
delete p;
int *a = new int[100];
delete []a;//正确的释放
delete a;//只把第一个释放了

int (*aa)[4] = new int[3][4];
delete []aa;//多位的数组也是一个方括号,底层用递归

注意事项

1,new/delete 是关键字,效率高于 malloc 和 free.
2,配对使用,避免内存泄漏和多重释放。
3,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free;

//c
int *p = (int *)malloc(100);
if(NULL == p)
    return -1;
//c++
int *pi = new (std::nothrow) int[100];
if(pi == NULL)
    return -1;

内联函数(inline function)

c语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错,容易使得内存text段体积变大,不会类型检查。

#define SQR(i) ((i)*(i))
int main()
{
    int i=0;
    while(i<5)
    {
        // printf("%d
",SQR(i++));
        printf("%d
",sqr(i++));
    }
    return 0;
}

int sqr(int i)
{
    return i*i;
}
/*
优点:一段高度抽象的逻辑,不易产生歧义,是的text段体积变小,会类型检查。
缺点:函数调用的压栈与出栈的开销
*/

内联函数兼有宏和函数的优点。系统自己有一套优化方案,inline变成了给编译器的一种建议。

inline int sqr(int i)
{
    return i*i;
}

评价
优点:避免调用时的额外开销(入栈与出栈操作)
代价:由于内联函数的函数体在代码段中会出现多个“副本”,因此会增加代码段的空间。
本质:以牺牲代码段空间为代价,提高程序的运行时间的效率。
适用场景:函数体很“小”,且被“频繁”调用。

强制类型转化

static_cast 
//对于隐时类型可以转化的
reinterpret_cast
//对于无隐式的类型转化,static_cast不可用
const_cast
//
dynamic_cast
//

static_cast

float a = 5.6;
int b = 5;

b = static_cast<int>(a);//把a转成int赋值给b

void *p,int *q;
p = q;//可以
q = p;//不可以,任何指针都可以赋值给void *类型,但是void *类型不可以赋值给指针类型。
q = static_cast<int*>(p);

reinterpret_cast

int a[5] = {1,2,3,4,5};
int *p = reinterpret_cast<int*>((reinterpret_cast<int>(a)+1));

const_cast
( 脱) 常类型转换,只能引用与指针与引用
const 一定不可以修改

void func(const int &r)
{

}
void func2(int & v)
{
    cout<<v<<endl;
}

int main()
{
    const int a = 19;
    func(10);//可以
    func(a+10);//可以,应为参数中有const修饰。
    func2(const_cast<int&>(a));//因为a是const int类型
    int & ra = const_cast<int&>(a);
    ra = 200;
    cout<<"a = "<<a<<" ra= "<<ra<<endl;
    cout<<"&a = "<<&a<<" ra = "<<&ra<<endl;
    /*
    a = 19 ra = 200
    &a = 0x... 不一样
    */
}

用来移除对象的常量性(cast away the constness)使用 const_cast 去除 const 限定的目的不是为了修改它的内容,使用 const_cast 去除 const 限定,通常是为了函数能够接受这个实际参数。
可以改变 const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为 .

const 常变量

#defined N 200 //宏,在预处理的阶段发生了替换
const int a = 100;//编译阶段发生了替换
//const 永远不会发生改变

命名空间(namespace scope)

//全局就是无名空间
int v = 55;
int main()
{
    int *p = &v;//访问全局的
    int v =5;
    cout<<v<<endl;//5
    cout<<*p<<endl;//55

    cout<<::v<<endl;//::作用域运算符,前面要命名空间,平常调配用的函数之前省略::
    
    return 0;
}

namespace 是对全局命名空间的再次划分

#include<iostream>
using namespace std;
namespace Spac{
    int a;//全局变量 
    struct Stu{};//数据类型 
    void func();//函数 
    namespace//其它命名空间 
}

使用:

#include<iostream>
using namespace std;
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    Space::x = 200;//这种与本地的不会冲突
    cout<<Space::x<<endl;//200

    using Space::x;//在这作用域内的x都是Space命名空间中的x
    x = 20;
    cout<<x<<endl;

    using Space Space;//直接把Space这个命名空间打开
    x = 20;
    y = 30;


    return 0;
}

各种之间冲突解决

利用最小单位的作用域块

#include<iostream>
using namespace std;//标中库空间命名
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    {
        using Space Space;
        x = 20;
        y = 30;
    }
    {
        using Space Other;
        x = 50;
        y = 70;
    }
    int x,y;

    return 0;
}

支持嵌套

namespace Space {
    int x;
    int y;
    namespace Other {
        int m;
        int n;
    }
}
int main()
{
    using namespace Space::Other;//使用Other命名空间中的变量,不建议嵌套
    m = 30;
    return 0;
}

协同开发中的使用

namespace Space {
    int x;
}
namespace Space {
    int y;
}//命名空间相同会自动合并
int main()
{
    using namespace Space;
    x = 10;
    y = 20;
    return 0;
}

系统string类

string是一个类而非关键字,初始化比较灵活(类似js中var)

string s = "assassin";//赋值
string s2 = "assassin1";
cout<<s2.size()<<endl;//大小
string s3 = "wunworld";
s3 += s2;//拼接
if(s == s2)//比较 
    cout<<"s = s2"<<endl;
else if(s > s2)
    cout<<"s > s2"<<endl;
else
    cout<<"s < s2"<<endl;

char buf[1024];
strcpy(buf,s.c_str());
//如果和字符连用时,一定用c_str(),返回的是char *类型
//交换swap(string &s2)成员函数
s.swap(s2);

查找:

int find(char c, int pos = 0);
int find(char * s, int pos = 0);
//返回下标值,没有找到返回-1,默认从 0 下标开找

eg:

string s = "assassin";
int n = s.find("i",0);
cout<<n<<endl;//6

string 类型数组

string sArray[10] = {
                        "0",
                        "1",
                        "22",
                        "333",
                        "4444",
                        "55555",
                        "666666",
                        "7777777",
                        "88888888",
                        "999999999",
};
for(int i=0; i<10; i++)
{
    cout<<sArray[i]<<endl;
}

string 数组是高效的,如果用二维数组来存入字符串数组的话,则容易浪费空间,此时列数是由最长的字符串决定。如果用二级指针申请堆空间,依据大小申请相应的空间,虽然解决了内存浪费的问题,但是操作麻烦。用 string 数组存储,字符串数组的话,效率即高又灵活。

学习C++的建议:
1、在 C++中几乎不需要用宏,用 const 或 enum 定义显式的常量,用 inline 避免函数 调用的额外开销,用模板去刻画一族函数或类型,用 namespace 去避免命名冲突。
2、不要在你需要变量之前去声明,以保证你能立即对它进行初始化。
3、不要用 malloc,new 运算会做的更好。
4、避免使用 void*、指针算术、联合和强制,大多数情况下,强制都是设计错误的指示器。
5、尽量少用数组和 C 风格的字符串,标准库中的 string 和 vector 可以简化程序。
6、更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制

原文地址:https://www.cnblogs.com/intelwisd/p/8506922.html