【C++学习笔记】2 第二章 C++ 程序基础

第二章 C++ 程序基础

一、C++的内存分配

C语言中通过malloc/calloc/realloc/free函数实现内存的分配与释放。C++除了提供对C的兼容之外还提供了new/delete运算符来实现内存的分配与释放。

int* p = (int*)malloc (sizeof (int));
*p = 100;
free (p);
p = (int*)malloc (10 * sizeof (int));
for (int i = 0; i < 10; i++)
    p[i] = i;
free (p);
------------------------------------
int* p = new int;
*p = 100;
delete p;
p = new int[10];
for (int i = 0; i < 10; i++)
    p[i] = i;
delete[] p;
p = new int(100);
cout << *p << endl; // 100
delete p;
#include <iostream>
#include <cstring>
using namespace std;
int main (void) 
{
	int* pn = new int;
	cout << *pn << endl;
	*pn = 100;
	cout << *pn << endl;
	delete pn;
    
	double* pd = new double (3.14);
	cout << *pd << endl;
	delete pd;
    
	char* pc = new char[10];
	for (int i = 0; i < 10; i++)
		pc[i] = 'A' + i;
	for (int i = 0; i < 10; i++)
		cout << pc[i] << endl;
	delete[] pc;
    
	struct Student 
    {
		char name[256];
		int age;
		void print (void) 
        {
			cout << name << ", " << age << endl;
		}
	};
	Student* ps = new Student;
	strcpy (ps -> name, "张飞");
	ps -> age = 25;
	ps -> print ();
	delete ps;
    
	pc = new char[6] {'h', 'e', 'l', 'l', 'o', 0};//Windows系统下g++编译报错
	cout << pc << endl;
	delete[] pc;
    
	char mem[1024];
	pn = new (mem) int[256];
	cout << (void*)pn << ", " << (void*)mem << endl;
	return 0;
}

结果:
7214720
100
3.14
A
B
C
D
E
F
G
H
I
J
张飞, 25
`n
0x64fb10, 0x64fb10

二、引用

1. 引用即别名

int a = 10;
int& b = a;
cout << b << endl; // 10
b++;
cout << a << endl; // 11
int& b; // error !
int& c = b; // int& c = a;
int* p;
int * p;
int *p;
int* p, *q;
int& r = a;
int & r = a;
int &r = a;
int& r = a, &s = b;
typedef int* PINT;
PINT p, q;
typedef int& RINT;
RINT r = a , s = b;

2. 引用必须被初始化为与有效内存相关联。

int& r = *new int;
delete &r;

3. 引用型参数

  1. 通过引用型参数可以在函数中对实参变量进行修改。
  2. 通过引用型参数可以避免参数传递过程中数据拷贝。
  3. 通过将参数定义为常引用防止在函数对实参的意外修改,同时还可以接受常量型实参。
  4. 传递引用型参数实际上就是传递地址,引用的本质还是指针。

4. 引用型返回值

永远不要返回对局部变量的引用,返回对全局/静态/成员变量的引用是安全的。

5. 引用和指针

    1) 指针可以不初始化,其目标可在指针被初始化后随意改变,而引用必须初始化,而且一旦被初始化就不能再引用其它目标。
    int a, b;
    int* p = &a;
    p = &b;
    int& r = a;
    r = b; // b值赋给a而非令r引用b
   2) 可以定义指向指针的指针,但是不能定义指向引用的指针。
    int a;
    int* p = &a;
    int** pp = &p; // ok
    int& r = a;
    int&* pr = &r; // error !
   3) 可以定义引用指针的引用,但是不能定义引用引用的引用。 
    int a;
    int* p = &a;
    int*& rp = p; // ok
    int& r = a;
    int&& rr = r; // error !
4) 可以定义指针数组,但是不能定义引用数组,可以定义数组引用。
   int a, b, c;
   int* parr[] = {&a, &b, &c}; // ok
   int& rarr[] = {a, b, c}; // error !
   int arr[] = {1, 2, 3};
   int (&rarr)[3] = arr; // ok,数组引用
   int (*parr)[3] = &arr; // ok,数组指针
// 引用型参数
#include <iostream>
using namespace std;
/* 不正确的交换函数
void swap (int a, int b) {
	int c = a;
	a = b;
	b = c;
}
*/
void swap (int* a, int* b) {
	int c = *a;
	*a = *b;
	*b = c;
}
void swap (int& a, int& b) {
	int c = a;
	a = b;
	b = c;
}
struct Student {
	char name[256];
	int age;
};
void print (const Student& s) {
	cout << s.name << ", " << s.age << endl;
//	s.age++; // 编译错误
}
void foo (const int& r) {
	cout << r << endl;
}
int main (void) {
	int a = 100, b = 200;
	cout << a << ", " << b << endl;
//	swap (&a, &b);
	swap (a, b);
	cout << a << ", " << b << endl;
	Student s = {"张飞", 25};
	print (s);
	foo (a);
	foo (1000);
	return 0;
}

结果:
100, 200
200, 100
张飞, 25
200
1000
// 引用型返回值
#include <iostream>
using namespace std;
int g_data = 0;
int& foo (void) {
	return g_data; // 返回全局变量的引用,安全
}
int& bar (void) {
	static int s_data = 0;
	return s_data; // 返回静态变量的引用,安全
}
int& hum (void) {
	int data = 100;
	return data; // 返回局部变量的引用,危险
}
void fun (void) {
	int data = 200;
}
struct A {
	int data;
	int& dum (void) {
		return data; // 返回成员变量的引用,安全
	}
};
int& addadd (int& data) {
	data++;
	return data; // 返回参数引用,安全
}
int main (void) {
	foo ()++;
	cout << foo () << endl; // 1
	foo () = 100;
	cout << g_data << endl; // 100
	bar ()++;
	cout << bar () << endl; // 1
	bar () = 100;
	cout << bar () << endl; // 100
	int& data = hum ();
	cout << data << endl; // 100
	fun ();
	cout << data << endl; // 200
	A a = {1000};
	cout << a.dum () << endl; // 1000
	a.dum ()++;
	cout << a.dum () << endl; // 1001
	a.dum () = 2000;
	cout << a.dum () << endl; // 2000
	int d = 0;
	addadd (addadd (addadd (d)));
	cout << d << endl; // 3
	return 0;
}

编译警告:
.\retref.cpp:13: warning: reference to local variable `data' returned

结果:
1
100
1
100
100
200
1000
1001
2000
3

三、类型转换运算符

char c = ‘a’;
int n = (int)c;

1. 静态类型转换:

目标类型 变量名 = static_cast<目标类型> (源类型变量名);
int n = static_cast<int> (c);

编译器做静态类型检查:在源类型和目标类型之间只要有一个方向可以做隐式类型转换,那么在两个方向上都可以做静态类型转换。反之如果在两个方向上都不能做隐式类型转换,那么在两个方向上也都不能做静态类型转换。

// 静态类型转换
#include <iostream>
using namespace std;
int main (void) {
	int n;
	char c;
	n = c;
	n = static_cast<int> (c);
	c = static_cast<char> (n);
	double f;
	int* p;
//	p = f;
//	f = p;
//	p = static_cast<int*> (f);
//	f = static_cast<double> (p);
	void* v = p;
	int* q = static_cast<int*> (v);
	return 0;
}

2. 动态类型转换:

目标类型 变量名 = dynamic_cast<目标类型> (源类型变量名);
主要用于具有多态特性的父子类指针/引用之间的转换。

3. 常量类型转换:

目标类型 变量名 = const_cast<目标类型> (源类型变量名);
用于去除指针/引用上面的常属性。
const int* p1;
int* p2 = const_cast<int*> (p1);
double* p3 = const_cast<double*> (p1); // error !
注意:试图通过const_cast修改一个常量的值,其后果将是不确定的。

#include <iostream>
using namespace std;
void foo (const int& data) {
	int& rdata = const_cast<int&> (data);
//	char& rc = const_cast<char&> (data);
	rdata++;
	cout << data << endl;
}
int main (void) {
	int data = 100;
	foo (data);
	cout << data << endl;
	const volatile int cn = 1000;
	int* pn = const_cast<int*> (&cn);
	*pn = 2000;
	cout << *pn << ", " << cn << endl;
	return 0;
}


结果:
101
101
2000, 2000

4. 重解释类型转换:

目标类型 变量名 = reinterpret_cast<目标类型> (源类型变量名);

在任意类型的指针或引用之间进行转换。甚至可以在指针和整数之间做转换。

#include <iostream>
#include <cstdio>
using namespace std;
int main (void) {
	int n = 0x12345678;
	char* p = reinterpret_cast<char*> (&n);
	for (size_t i = 0; i < sizeof (n); i++)
		printf ("%X ", p[i]);
	printf ("\n");
	int i = reinterpret_cast<int> (&n);
	printf ("%p\n", &n);
	printf ("%#x\n", i);
	return 0;
}

结果:
78 56 34 12
0064FF24
0x64ff24

四、C++之父给C程序员的建议

  1. 尽量少用宏,而代之以const和enum以及inline
      #define PAI 3.14
      const double PAI = 3.14;
      #define square(x) ((x)*(x))
      inline double square (int x) {...}
      #define int double
  1. 变量随用随声明

  2. 不用malloc而用new

  3. 避免使用void*、指针算数、联合和强制类型转换

  4. 尽量少用C风格的字符串(char*和char数组),代之以string对象

  5. 建立起面向对象的思想

#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
int main (void) {
	string s1 ("hello, ");
	string s2 = "world !";
	cout << s1 << endl;
	cout << s2 << endl;
	s1 += s2;
	cout << s1 << endl;
	if (s1 < s2)
		cout << s1 << " < " << s2 << endl;
	else
	if (s1 > s2)
		cout << s1 << " > " << s2 << endl;
	else
	if (s1 == s2)
		cout << s1 << " == " << s2 << endl;
	string s3 = s1;
	cout << s3 << endl;
	string s4 (s3);
	cout << s4 << endl;
	printf ("%s\n", s4.c_str ());
	const char* ps = "学习";
	string s5 (ps);
	cout << s5 << endl;
	char str[] = "C++有趣!";
	string s6 = str;
	cout << s6 << endl;
	return 0;
}

结果:
hello,
world !
hello, world !
hello, world ! < world !
hello, world !
hello, world !
hello, world !
学习
C++有趣!
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值