C++ Prime Plus Part1


  1. C++在C的基础上加入了面向对象编程和泛型编程。C是一种面向过程的编程语言,旨在用一系列函数来实现这一过程;而C++则是面向对象的编程语言,将相关的数据和方法(函数)看作一个整体。泛型编程则是基于C++中所引入的“模板”的概念上的一种编程方法。
  2. main函数定义以int main()开始。一般来说,main函数通常不会被程序中的其他部分所调用,但会被启动代码调用,启动代码是编译器自动添加到程序中,是可执行程序与操作系统之间的桥梁。main函数最后会有隐含的返回语句return 0;。主函数所返回的值并非返回给程序中的其他部分,而是返回给操作系统。
  3. Cpp将C语言中的.h头文件转换为Cpp头文件,去掉其.h扩展名并在文件名前加上c前缀(表示来自于C语言),如C中的math.h就变为cmath
  4. 当两个不同类中有相同的函数时,可以通过类名(命名空间)来辨别。而using namespace std就是使能命名空间std,在后续程序中如果用到std中的内容时就不需要在内容前加std::的前缀。
  5. cincout语句中的<<>>都是运算符重载的例子。cout打印整型变量值时会先数字转换为字符串的形式,且打印带小数时只打印6位。
  6. 规范:
    • 每条语句占一行
    • 两个花括号各占一行,或者或开始花括号与当前代码块开始的代码行在同一行
    • 语句相对于花括号进行缩进
    • 函数名相关圆括号周围没有空白
  7. C++中的变量都是在首次使用前进行声明。
  8. 赋值运算符的顺序是自右而左。
  9. C++程序中应当为程序中使用的每个函数提供原型,而函数原型之于函数就像变量声明之于变量一般。
  10. 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位小数。
  11. 整型限制信息位于头文件climits中(INT_MAX, SHRT_MAX, LONG_MAX, LLONG_MAX, CHAR_BIT)。unsigned本身是unsigned int的缩写。
  12. cout.put()等同于cout<<.
  13. 类型转换
    • 赋值时转换:右值类型转换为接收变量的类型
    • 以花括号进行初始化时,不允许“缩窄”,即不能将大的赋给小的,但可以将小的赋给大的,且浮点数不能赋给整型。
    • 计算时:对于浮点数,会提升到操作数中较大级别;对于整型,如果均为有符号或无符号,则提升至高级别,而一个为有符号另一个为无符号,若无符号级别更高则提升到无符号,否则转换为有符号。
  14. auto关键字:变量类型设置与初始值相同(右值)。
  15. 编译器不会检测数组下标是否有效,即编译器不检查下标是否越界。
  16. 数组只有在定义时允许进行整体初始化,也不允许将一个数组直接赋给另一个数组。
  17. 字符数组和字符串的差别:二者其实说到底都类似于char数组,但是后者的最后一位必须为\0. 用双引号括起的字符串隐式地包含了结尾的空字符。
  18. 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);
  1. strcpy:
char *strcpy(char *strDest, char *strSrc) {
    assert((strDest!=nullptr)&&(strSrc!=nullptr));
    char *strAddr = strDest;
    while((*strAddr++=*strSrc++)!='\0');
    return strAddr;
}
  1. 除了char类型,还有wchar_t, char16_t, char32_t和raw。区别在于字符串前加的前缀,依次为L,u,U,R. raw(原始字符串)将字符串内容解析为其本身,即\n解析为两个字符而非换行符,并以"()"为界。

  2. 共用体(Union)可以存储不同的数据类型,但是只能同时保存其中的一种类型。由于Union只能存储一个值,因而要求Union的长度为其最大成员的长度。与结构体类似,共用体也可可以是匿名的,此时共用体的成员被视为其父结构体的成员。共用体的主要功能是用于节省内存

  3. 枚举(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)$

  1. 指针:实际上是一个变量,存储的是其指向的变量的地址。对于同一台计算机而言,指向不同数值类型的指针大小都是一样大,即sizeof(int *)==sizeof(double *). 对于int *a;这个声明来说,a被声明为一个指针变量,其指向的是一个int类型的数值。

  指针定义后,必须经过初始化方可进行使用,而仅仅进行声明,即没将该指针变量指向某个地址,那么对其进行访问将会报错(野指针)。

  如果要将整数赋给指针,即直接让指针指向某个确定的地址,需要进行类型强制转化,将整数转换为对应的地址类型,如int *ptr = (int *)0xB8000000;

  1. 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实际上的意义是整个数组的地址。

  1. 函数内部定义的常规变量(局部变量)存储在栈中,用完即销毁;静态变量则是位于静态存储区,在整个运行过程中都维持上一次的数值,直至结束程序时才会销毁该变量;动态申请变量(malloc或new)存放于堆中,通过用户手动申请和释放。

  2. 数组、vector、array

  vector的声明:vector<typeName> arr(n_elem);
  array的声明:array<typeName, n_elem> arr;

vector所存储的区域位于堆或自由存储区,而array和数组都是在栈中。
通过下标访问时,当下标越界时编译器不会报错,用at()来访问时则会检测下标的合法性,代价时运行时间更长。


文章作者: Vyron Su
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Vyron Su !