第二章 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. 引用型参数
- 通过引用型参数可以在函数中对实参变量进行修改。
- 通过引用型参数可以避免参数传递过程中数据拷贝。
- 通过将参数定义为常引用防止在函数对实参的意外修改,同时还可以接受常量型实参。
- 传递引用型参数实际上就是传递地址,引用的本质还是指针。
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程序员的建议
- 尽量少用宏,而代之以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
-
变量随用随声明
-
不用malloc而用new
-
避免使用void*、指针算数、联合和强制类型转换
-
尽量少用C风格的字符串(char*和char数组),代之以string对象
-
建立起面向对象的思想
#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++有趣!