从C到C++的过渡(2)

七、C++的动态内存分配

C语言中对内存的操作:malloc/calloc/realloc/free。
C++语言中则提供了new和delete运算符来进行内存的动态分配。
1、new/delete:对单个变量进行内存分配/释放。
2、new[]/delete[]:对数组进行内存分配/释放。

#include <iostream>
using namespace std;

int main(){
	//int* pi = (int*)malloc(sizeof(int));
	//free(pi);
	int* pi = new int;
	*pi = 8;
	cout << *pi << endl;
	delete pi;
	pi = NULL;

	pi = new int[10];
	for (int i = 0;i < 10;++i)
		pi[i] = i;
	for (int i = 0;i < 10;++i)
		cout << pi[i] << ' ';
	cout << endl;
	delete[] pi;
	pi = NULL;

	pi = new int(1234);
	cout << *pi << endl;
	delete pi;
	pi = NULL;

	char buf[4] = {0x12,0x34,0x56,0x78};
	pi = new(buf) int;//定位new
	cout << hex << *pi << endl;
	cout << (void*)pi << ' ' << (void*)buf << endl;
	//delete pi;//此处不能delete,new的是栈的内存,不能delete

	int (*p)[4] = new int[3][4];
	delete[] p;
	int (*q)[4][5] = new int[3][4][5];
	delete[] q;
	return 0;
}

八、C++的字符串

    C没有字符串专门机制,用char型数组在末尾加’\0’的办法来处理字符串,C++也兼容这种“C字符串”机制。但在C++中则把字符串封装成了一种数据类型string来专门处理字符串,它提供了非常丰富的字符串处理功能。而且,string还提供了与“C字符串”相互转换的方法,使用非常灵活。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int main(){
	string s1 ("hello");
	string s2 = "world";
	(s1 += " ") += s2;
	cout << s1 << endl;
	string s3 = s1;
	cout << s3 << endl;
	cout << (s1 == s3) << endl;
	s3[0] = 'H';
	cout << s3 << endl;
	cout << (s1 > s3) << endl;
	cout << s1.length() << endl;
	cout << (strcasecmp(s1.c_str(),s3.c_str()) == 0) << endl;

	FILE* fp = fopen("string.txt", "w");
	//fwrite(&s3, 1, sizeof(s3), fp);
	fwrite(s3.c_str(), sizeof(char), s3.length(), fp);
	fclose(fp);
	return 0;
}

九、引用

9.1、引用即别名。

int a = 20;
int& b = a;
b = 10;
cout << a << endl;//10

9.2、引用必须初始化。

int a;
int* p;
a = 20;
p = &a;
int& b;//ERROR
int& b = a;//OK

9.3、引用一旦初始化就不能再引用其他变量。

int a = 20, c = 30;
int& b = a;
b = c;//ERROR

9.4、引用的应用场景

(1)引用型参数
a、修改实参
b、避免拷贝,通过加const可以防止在函数中意外的修改实参的值,同时还可以接受拥有常属性的实参。
(2)引用型返回值

int b = 10;
int a = func(b);
func(b) = a;
#include <iostream>
using namespace std;

int g_data = 100;
int& foo(void){
	return g_data;
}

int main(){
	int data = foo();
	cout << data << endl;//100
	foo() = 200;
	cout << g_data << endl;
	foo() += 100;
	++foo();
	cout << g_data << endl;//301
	return 0;
}

    从一个函数中返回引用往往是为了将该函数的返回值作为左值使用。但是,一定要保证函数所返回的引用的目标在该函数返回以后依然有定义,否则将导致不确定的后果。
    不要返回局部变量的引用,可以返回全局、静态、成员变量的引用,也可以返回引用型形参变量本身。

9.5、引用和指针

(1)引用的本质就是指针,很多场合下引用和指针可以互换。
(2)在C++层面上引用和指针存在以下不同:
A、指针是实体变量,但是引用不是实体变量。

int& a = b;
sizeof(a);//4
double& d = f;
sizeof(d);//8

B、指针可以不初始化,但是引用必须初始化。
C、指针的目标可以修改,但是引用的目标不能修改。
D、可以定义指针的指针,但是不能定义引用的指针。

int a;
int*  p = &a;
int** pp = &p;//OK 
int& r = a;
int&* pr = &r;//ERROR

E、可以定义指针的引用,但是不能定义引用的引用。

int a;
int* p = &a;
int*& q = p;//OK 
int& r = a;
int&& s = r;//ERROR

F、可以定义指针的数组,但是不能定义引用的数组。

int a,b,c;
int* parr[] = {&a,&b,&c};//OK 
int& rarr[] = {a,b,c};//ERROR

G、可以定义数组的引用。

int arr[] = {1,2,3};
int (&arr_ref)[3] = arr;//OK 

十、显式类型转换运算符

C:目标类型变量 = (目标类型)源类型变量;

10.1、静态类型转换

    static_cast<目标类型> (源类型变量)
    如果在目标类型和源类型之间某一个方向上可以做隐式类型转换,那么在两个方向上都可以做静态类型转换。反之如果在两个方向上都不能做隐式类型转换,那么在任意一个方向上也不能做静态类型转换。

int* p1 = ...;
void* p2 = p1;
p1 = static_cast<int*> (p2);

    如果存在从源类型到目标类型的自定义转换规则,那么也可以使用静态类型转换。

10.2、动态类型转换

    dynamic_cast<目标类型> (源类型变量)
    用在具有多态性的父子类指针或引用之间。

10.3、常类型转换

    const_cast<目标类型> (源类型变量)
    给一个拥有const属性的指针或引用去常:

const int a = 100;
const int* p1 = &a;
*p1 = 200;//ERROR 
int* p2 = const_cast<int*> (p1);
*p2 = 200;//OK
#include <iostream>
using namespace std;

int main(){
	const volatile int a = 100;
	const volatile int* p1 = &a;
	//*p1 = 200;
	int* p2 = const_cast<int*> (p1);
	*p2 = 200;
	cout << *p2 << endl;//200
	cout << a << endl;//200
	//cout << 100 << endl;
	return 0;
}

10.4、重解释类型转换

    reinterpret_cast<目标类型> (源类型变量);
    在不同类型的指针或引用之间做类型转换,以及在指针和整数之间做类型转换。

#include <iostream>
using namespace std;

int main(){
	int i = 0x12345678;
	char* p = reinterpret_cast<char*> (&i);
	for (size_t i = 0;i < 4;++i)
		cout << hex << (int)p[i] << ' ';
	cout << endl;

	float* q = reinterpret_cast<float*> (&i);
	cout << *q << endl;
	void* v = reinterpret_cast<void*> (i);
	cout << v << endl;
	return 0;
}
/*
运行结果:
78 56 34 12 
5.69046e-28
0x12345678
*/

10.5、目标类型变量 = 目标类型(源类型变量);

    int a = int(3.14);


十一、C++之父的建议

1、尽量少用宏,多用const、enum和inline。

#define PAI 3.14159
const double PAI = 3.14159;

#define ERROR_FILE -1
#define ERROR_MEM  -2
enm{
	ERROR_FILE = -1;
	ERROR_MME = -2;
};

#define max(a,b) ((a) > (b) ? (a) : (b))
inline double max(double a,double b){
	return a > b ? a : b;
}

2、变量随用随声明同时初始化。
3、少用malloc/free,多用new/delete。
4、少用C风格的强制类型转换,多用类型转换运算符。
5、少用C风格的字符串,多用string。
6、尽量多使用引用,少使用指针。
7、树立面向对象的编程思想。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值