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

时间:2024-01-14 10:55:38

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

## 内存管理
### 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\n",SQR(i++));
printf("%d\n",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\n",SQR(i++));
printf("%d\n",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、更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制