- C++在C的基础上加入了面向对象编程和泛型编程。C是一种面向过程的编程语言,旨在用一系列函数来实现这一过程;而C++则是面向对象的编程语言,将相关的数据和方法(函数)看作一个整体。泛型编程则是基于C++中所引入的“模板”的概念上的一种编程方法。
- main函数定义以
int main()
开始。一般来说,main函数通常不会被程序中的其他部分所调用,但会被启动代码调用,启动代码是编译器自动添加到程序中,是可执行程序与操作系统之间的桥梁。main函数最后会有隐含的返回语句return 0;
。主函数所返回的值并非返回给程序中的其他部分,而是返回给操作系统。 - Cpp将C语言中的
.h
头文件转换为Cpp头文件,去掉其.h
扩展名并在文件名前加上c
前缀(表示来自于C语言),如C中的math.h
就变为cmath
。 - 当两个不同类中有相同的函数时,可以通过类名(命名空间)来辨别。而
using namespace std
就是使能命名空间std
,在后续程序中如果用到std
中的内容时就不需要在内容前加std::
的前缀。 cin
和cout
语句中的<<
和>>
都是运算符重载的例子。cout
打印整型变量值时会先数字转换为字符串的形式,且打印带小数时只打印6位。- 规范:
- 每条语句占一行
- 两个花括号各占一行,或者或开始花括号与当前代码块开始的代码行在同一行
- 语句相对于花括号进行缩进
- 函数名相关圆括号周围没有空白
- C++中的变量都是在首次使用前进行声明。
- 赋值运算符的顺序是自右而左。
- C++程序中应当为程序中使用的每个函数提供原型,而函数原型之于函数就像变量声明之于变量一般。
- short至少为16位,int至少和short一样长,long至少32位且至少与int等长,long long至少64位且至少与long等长。float至少为32位,double至少为48位且不少于float,long double至少和double等长,而通常情况下float为32、double为64、long double为80/96/128,这三种类型的指数范围至少为-37到37. float只保留6位小数。
- 整型限制信息位于头文件
climits
中(INT_MAX, SHRT_MAX, LONG_MAX, LLONG_MAX, CHAR_BIT)。unsigned
本身是unsigned int
的缩写。 cout.put()
等同于cout<<
.- 类型转换
- 赋值时转换:右值类型转换为接收变量的类型
- 以花括号进行初始化时,不允许“缩窄”,即不能将大的赋给小的,但可以将小的赋给大的,且浮点数不能赋给整型。
- 计算时:对于浮点数,会提升到操作数中较大级别;对于整型,如果均为有符号或无符号,则提升至高级别,而一个为有符号另一个为无符号,若无符号级别更高则提升到无符号,否则转换为有符号。
- auto关键字:变量类型设置与初始值相同(右值)。
- 编译器不会检测数组下标是否有效,即编译器不检查下标是否越界。
- 数组只有在定义时允许进行整体初始化,也不允许将一个数组直接赋给另一个数组。
- 字符数组和字符串的差别:二者其实说到底都类似于char数组,但是后者的最后一位必须为
\0
. 用双引号括起的字符串隐式地包含了结尾的空字符。 - cin遇到空格就停下,想要记下空格需要用getline()或get(),前者会读取并丢弃换行符,而后者则将换行符保留在输入流中,因而用连续用get()时,第二次get()遇到换行符认为已经读取完成,实际上读取为空,即get()无法跳过换行符,可以采用
cin.get(str, arSize).get()
.
const int arSize=20;
char name1[arSize];
char name2[arSize];
cin.getline(name1, arSize);
getline(cin, name2);
- strcpy:
char *strcpy(char *strDest, char *strSrc) {
assert((strDest!=nullptr)&&(strSrc!=nullptr));
char *strAddr = strDest;
while((*strAddr++=*strSrc++)!='\0');
return strAddr;
}
除了char类型,还有wchar_t, char16_t, char32_t和raw。区别在于字符串前加的前缀,依次为L,u,U,R. raw(原始字符串)将字符串内容解析为其本身,即
\n
解析为两个字符而非换行符,并以"(
和)"
为界。共用体(Union)可以存储不同的数据类型,但是只能同时保存其中的一种类型。由于Union只能存储一个值,因而要求Union的长度为其最大成员的长度。与结构体类似,共用体也可可以是匿名的,此时共用体的成员被视为其父结构体的成员。共用体的主要功能是用于节省内存。
枚举(enum)默认第一个枚举值为0,而后的枚举值在前一位枚举值的基础上逐位加
1
.枚举只有赋值运算而没有算术运算。将非enum值赋给enum变量将会报错,enum量为整型,可提升为int类型,但int不能自动转为enum类型。
enum bigstep{
zero, // 默认为0
first=0, // 0
second=100, // 100
third // 101
}; // 范围为0~127
将int类型赋给enum,如果int类型值在enum的取值范围内,即使不是枚举值也可可以成功赋值。上限:找到最小x使得$2^x$大于enum的最大值,则上限为$2^x-1$;下限:enum值得最小值不小于0则下限为0,小于0则找到最小得x使得$-2^x$小于最小值,则下限为$-(2^x-1)$
- 指针:实际上是一个变量,存储的是其指向的变量的地址。对于同一台计算机而言,指向不同数值类型的指针大小都是一样大,即
sizeof(int *)==sizeof(double *)
. 对于int *a;
这个声明来说,a
被声明为一个指针变量,其指向的是一个int
类型的数值。
指针定义后,必须经过初始化方可进行使用,而仅仅进行声明,即没将该指针变量指向某个地址,那么对其进行访问将会报错(野指针)。
如果要将整数赋给指针,即直接让指针指向某个确定的地址,需要进行类型强制转化,将整数转换为对应的地址类型,如int *ptr = (int *)0xB8000000;
。
- new是在堆或自由存储区中为对象分配一个空闲的、足够大的内存,而delete则释放通过new申请的内存块,但不会删除指针本身,因而在释放内存后不应该直接继续访问该指针指向的内存,而是应该修改其指向(野指针),应该注意delete只能释放用通过new申请的内存。
通过new来创建动态数组:int *ptr=new int[10];
,而释放时需要通过另一种格式的delete来释放:delete [] ptr;
.
指针和数组具有以下区别:通过下标进行访问时是一样的,其中指针和数组名都是指向数组的首元素地址;而当通过地址进行访问时,可以通过地址的偏移;而指针可以修改其指向,即修改指针的值,但数组名是常量,不允许修改。
int arr[10]={1,2,3,4,5};
int *ptr=arr;
cout << arr[2] << endl; // valid
cout << ptr[2] << endl; // valid
cout << *(ptr+2) << endl; // valid
cout << *(arr+2) << endl; // valid
ptr = ptr+1; // valid
arr = arr+1; // invalid
数组名实际上不是数组的地址,而仅仅是首元素的地址,对于数组进行取址操作得到的地址虽然和前边的地址一样,但
&arr
实际上的意义是整个数组的地址。
函数内部定义的常规变量(局部变量)存储在栈中,用完即销毁;静态变量则是位于静态存储区,在整个运行过程中都维持上一次的数值,直至结束程序时才会销毁该变量;动态申请变量(malloc或new)存放于堆中,通过用户手动申请和释放。
数组、vector、array
vector的声明:vector<typeName> arr(n_elem);
array的声明:array<typeName, n_elem> arr;
vector所存储的区域位于堆或自由存储区,而array和数组都是在栈中。
通过下标访问时,当下标越界时编译器不会报错,用at()
来访问时则会检测下标的合法性,代价时运行时间更长。