目录
本文是复习C++的读书笔记之一,参考C++ Primer 前四章
头文件与命称空间
头文件:有些文件由“#include ”包含进其他文件,写在其他文件的头部,也叫头文件。
例如使用#include编译指令,#include <iostream> 该编译指令导致预处理器将iostream的文件内容添加到程序中。在源代码编译之前替换或者添加文本。
头文件类型 | 约定 | 范例 | 说明 |
---|---|---|---|
C++旧式风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
C旧式风格 | 以.h结尾 | math.h | C和C++程序都可以使用 |
C++新式风格 | 没有扩展名 | iostream | C++可以使用,使用namespace std |
转换后的C | 加上前缀c,没有扩展名 | cmath | C++可以使用,可以使用不是c的特性,如namespace std |
命称空间:如上表使用iostream时需要使用名称空间编译指令 “using namespace std;”,叫做using 编译指令。省略using时,使用下面这种方式
std::cout<<”hello”<< endl;
变量与数据类型
变量命名规则
- 名称中只能使用字母字符、数字和下划线
- 名称的第一个字符不能是数字
- 不能将C++关键字用作变量名称
- 区分大小写字母
- 长度没有限制,都有意义
- 以两个下划线或者大写字母打头的名称被保留给实现(编译器及其使用的资源)使用
以一个下划线打头的名称被保留给实现,用作全局标示符
int Poodle; // valid but distinct from poodle
int _Mytime; // valid but reserved –starts with underscore
int __fools; // valid but reserved,starts with two underscore
数据类型
C++内置整型:unsigned int、int、unsigned short、short、unsigned long、long、unsigned char、char、bool;
C++内置浮点类型:float、double、long double
C++的基本整型有 char、short、int、long,每种类型有有符号和无符号两种,总共8种供选择。
char 一个字节8位
short 至少16位
int 至少与short相同
long 至少32位,且至少与int一样长
当前很多系统使用最小长度 short 16位 long32位 int 16、24或者32
C标准中并没有具体给出规定那个基本类型应该是多少字节数,而且这个也与机器、OS、编译器有关,比如同样是在32bits的操作系统系,VC++的编译器下int类型为占4个字节;而tuborC下则是2个字节。
使用sizeof()查看占用的字节数 通常short 2个字节 int 4个字节 long 4个字节 char 一个字节,有变化的一般是int和long,16位编译器int是2个字节,64位编译器long是8个字节,unsigned long: 8个字节
下面给出不同位数编译器下的基本数据类型所占的字节数:
32位编译器
short: 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
bool类型是ANSI/IOS C++标准添加的新类型
注意
cout<< hex不会显示任何内容,只是更改整型数值以16进制显示;由于hex位于命名空间std中,而程序使用了该命名空间,因此不能将它作为变量名,但是如果省略编译指令using,而使用std::cout, std::endl, std::hex, std::oct等等,则可以将它用作变量名。
#include<iostream>
using namespace std;
int main(){
int num = 42;
cout<< num<<endl;
cout<<hex;
cout<<num<<endl;
cout<< oct;
cout<<num<<endl;
}
浮点数的优缺点
优点:
- 可以表示整数之间的数值
- 表示的范围较大
缺点:
- 表示的精度降低
- 运算速度比整数慢
#include <iostream>
int main(){
using namespace std;
float a = 2.34E+22f;
float b = a + 1.0f;
cout<< "a = " << a << endl;
cout<< "b - a = " << b - a << endl;
return 0;
}
程序输出:
a = 2.34E+022
b - a = 0
输出 b - a = 0,因为float类型只能表示数值的前六位或者前七位,在23位加1,不会对表示的值的大小产生影响.
总结:
C++ 中 signed char、short、int、long统称为符号整型,他们的无符号类型称为无符号整型;bool、char、wchar_t、无符号整型和符号整型统称为整型;float、double和long double统称为浮点型;整型和浮点型统称为算数类型。 |
const 限定符
最好用const限定符定义符号常量,定义后不能修改,而不是使用C 中#define来定义
const int MONTHS = 12;
注意:
const int toes;//value of toes undefined
toes = 12; // too late
如果在声明常量时没有提供值,那么它的值将是不确定的,并且无法赋值改变。
复合类型
数组
有效下标的重要:
编译器不会检查使用的数组下标是否有效,如果将一个值赋值给一个不存在的下标的数组元素,编译器并不会指出错误,但是程序运行后可能会出现异常终止,也可能会破坏数据或代码
数组的初始化规则:
只有在定义数组的时候才能初始化数组,此后就不能使用了,也不能将一个数组赋值给另外一个数组。
int card[4] = {2, 3, 4, 5}; //正确
int hand[4]; //正确
hand[4] = {3,5,6,7}; //错
hand = card; //错
不过可以使用下标分别给数组元素赋值。
字符串
C 风格的字符串以空字符结尾(null),字符数组中写作“\0”
char dog[5] ={‘b’,’e’,’a’,’t’,’y’} not a string
char cat[5] ={‘c’,’e’,’a’,’t’,’y’,’\0’} a string
两个字符数组都是char数组,但只有第二个是字符串
C++很多处理字符串的函数,包括cout 都是逐个处理字符数组中的字符,知道遇到空字符后停止,如果cout显示的是上面的dog数组,cout打印5个字母,并接着将内存中随后的各个字节解释为要打印的字符,直到遇到空字符为止由于空字符在内存中很常见,因此会很快停止。但是,还是不应该将不是字符串的数组当字符串处理。
例如:
char fish[] = “sadhasa” 用引号括起来的字符串隐式的包括结尾的空字符,字符数组的长度要注意包括空字符。
“S”包含两个字符‘S’和‘\0’
‘S’;是83的一种写法
char aa = "S" //不合法,“S”实际上表示的是字符串所在的内存地址,内存地址是一种独立的类型,不允许这样赋值
char bb = 'S' //合法
char boss[8] = “boss”;
b | o | s | s | \0 | \0 | \0 | \0 |
---|
strlen()函数返回的是存储在数组中的字符串的长度,而不是数组本身的长度。上面的数组长度是8,但是用strlen()函数返回的是字符串长度5
string类
std::string name = "Lijing";
std::string name2 = name;
不能将一个数组赋给另一个数组,但是可以将一个string 赋给另一个string 对象
将一行输入读取到string str 对象:getline(cin, str);
将一行输入读取到数组char charr[20] 对象:cin.getline(charr , 20);
结构体
创建结构包括两步:定义结构描述、创建结构变量
struct inflatable
{
char name[20];
float volume;
double price;
};
inflatable hat; //C++ 允许省略struct关键字,但是C在此不能省略struct
使用成员操作符(.) 访问成员,如hat.volume
C++ 允许在声明结构变量时省略struct 关键字
C++的一些老版本不能对函数中定义的常规数组初始化,也不能对函数中定义的常规结构初始化,解决方式是加上static
某些编译器如7.0版本之前的Visual C++不支持String类对象作为成员的结构进行初始化
共用体
一种数据格式,能够存储不同的数据类型,但是只能同时存储其中的一种类型,也就是说结构可以同时存储int 、long 和double,但是共用体只能存储int、long或者double,也就是说共用体每次只能存储一个值
union one4all
{
int int_val;
long long_val;
double double_val;
};
可以使用one4all变量存储int、long或者double,但是条件是在不同的时间进行:
one4all pail;
pail.int_val = 13; //store int value
cout<<pail.int_val ;
pail.double_val= 16.35; //store double value, lost int value;
cout<<pail.double_val;
用途:当数据项使用两种或更多种格式,但是不会同时使用的时候,可以节省空间。
struct widget
{
char band[20];
int type;
union id
{
long id_num; //一些商品的id为long
char id_char[20]; //一些商品的id为char
}id_val;
};
....
widget price;
...
if(price.type = 1){
cin>> price.id_val.id_num;
}else{
cin>>price.id_val.id_char;
}
枚举
C++的enum提供了另外一种创建符号常量的方式:
enum epecturm = {red,orange,yellow,green,blue,violet};
可以用枚举名声明这种类型的变量;
epecturm band;
在不进行强制类型转换的情况下,只能将定义枚举时使用的枚举量赋值给这种枚举的变量,如下:
band = red; //right
band = 233; //wrong 233 is not a emuerator , 非enum值赋给enum 错误
枚举量是整型,可以被提升为int类型,但是int类型不能自动转换成枚举类型;
color = 3 + red; //right
对于枚举只定义了赋值运算,并没有为枚举定义算术运算
int color = blue; //right
++band; //wrong
band = red+orange;// wrong red + orange 将被转换为0+1,但是结果是一个int值不能赋值给band
枚举变量的取值与取值范围:
取值必须是整数
enum bitstep{first, second = 100, third};
first默认为0,third为101;
取值范围是0—127,因为最大值101,在2的幂中比这个大的最小值是128.
enum bit{one = -6, second = 9, third};
取值范围是-7—15,因为最小值101,在2的幂中比这个大的最小值是8. 8-1=7,加上负号-7
enum {zero, null= 0, one, number_tr = 1};
zero为默认值0,one和number_tr都是1
选择多少空间存储enum由编译器决定,对于取值范围较小的枚举,使用一个字节或者更小的空间;对于包含long类型的枚举,使用4个字节
指针和自由存储空间
指针的危险:
long *fellow;
*fellow = 12993;
上述代码没有赋给fellow一个地址,由于fellow没有被初始化,他可能是任何值,fellow指向的地方可能并不是要存储12993的地方,可能导致一些最隐匿、最难以跟踪的bug
一定要在指针应用*之前,将指针初始化一个确定的、适当的地址。这是关于使用只指针的金科玉律。
使用new 来分配内存,有可能因为内存不足分配失败,返回空指针
配对使用new 和delete,否则将发生内存泄漏
- 只能用delete释放有new分配的内存,不过对空指针使用delete是安全的,不能使用delete释放声明变量所获得的内存。
int *ps = new int; //allocate memory with new
*ps = 198;
...
delete ps; //free memory with delete
不要尝试释放已经释放过的内存块,否则可能发生预想不到的情况
不要创建两个指向同一个内存块的地址,因为这样将会增加删除同一个内存块两次的机会,出现意想不到的情况
如果使用new []创建数组,那么对应的使用delete []来释放
int *thirst = new int [10];
...
delete [] thirst; //free a dynamic array
使用动态数组
#include<iostream>
using namespace std;
int main(){
double *member = new double[3];
member[0] = 19;
member[1] = 22;
member[2] = 33;
cout<<"*member is "<< *member<<endl;
cout<<"member[1] is"<<member[1]<<endl;
member = member + 1;
cout<<"Now member[0] is"<<member[0]<<endl;
cout<<"and member[1] is "<<member[1]<<endl;"
member = member - 1; // point back to begining
delete [] member; // free memory
return 0;
}
将member减去1,才能让它指向最开始的位置,这样delete删除时才正确
将指针变量加1后,其增加的值等于指向的类型占用的字节数
一般来说C++中数组名被视为数组中的第一个元素的地址
可以修改指针的值,但是数组名是常量,不能修改数组名的值
pointername = pointername + 1; //allowed
arrayname = arrayname +1; //not allowed
数组的动态联编:使用new关键字创建的数组,在运行时为数组分配空间,长度也将在运行时设置,使用完用delete释放
数组的静态联编:使用数组声明来创建数组时,数组的长度在编译时设置。
自由存储空间:
c++有三种管理数据存储的方式,自动存储、静态存储和动态存储(有时也叫自由存储空间或者堆);
自动存储:
局部变量的存储位置
静态存储:
静态存储是在整个程序执行期间都存在的存储方式,有两种:函数外定义和声明时使用static
动态存储:
new 创建的变量,允许在一个函数中创建分配内存,在另外一个函数中释放;数据的生命周期就不完全受到程序或函数的生存时间控制。