参数压栈一般是右往左压栈,(实际情况看调用约定)。
==判断一般将常量放在左边,因为如果写成了=号,编译器会识别出来。
指针表示你能访问的地址空间,故根据计算机能访问的地址空间不同(32位 or 64位),指针的大小也不同(4字节,8字节).实际上更准确点来说应该是编译的时候决定的,因为可以交叉编译。
C++语言支持函数重载,c不支持函数重载,这是因为他们编译后的生成的符号不同,C++的符号名里是附带参数信息的,而C是没有的.C++提供C连接交换制定符号extern "C"解决名字匹配问题.
用宏的时候要小心,懂得使用括号。
const修饰指针一般分为4种情况:
1.const int* a;这种情况const在*的左侧,那么指针所指向的为常量.
2.int const *a;跟上面一样
3.int* const a;指针本身是常量,这种情况不能对指针本身进行修改操作.故定义时必须初始化.
4.const int* const a;情况是上面结合.
const默认只在文件内有效,如果想共享,必须声明和定义都加上extern。
使用typedef别名之后的类型套const的理解需要修正,const修饰的是指针本身而不是指针指向的对象。
const成员函数的使用,成员函数一些是不改变类的数据成员,一些是要改变数据成员的值,如果把不改变的都加上const显然可以提高可读性和可靠性.用法如下:
int Gety() const;
如果想在const函数里面修改数据成员,则必须让该数据成员前面加关键字mutable.
如果把const 放在函数前,则说明返回值是常量.
一个const变量是不能随意转换成非const变量.
const和define的区别:
const有数据类型而define没有,前者可以进行类型安全检查而后者没有.
当结构体内的元素的长度都小于处理器的位数时,便以结构体里面最长的数据元素为对齐单位,也就是说,结构体的长度一定是最长的数据元素的整数倍.
反之则用处理机的位数为对齐单位.若要禁止对齐可以用pack指令:#pragma pack().
静态变量是存放在全局数据区的。
sizeof和strlen的区别
sizeof的类型是unsigned int
sizeof是运算符,strlen是函数
sizeof可以用类型做参数,strlen只能用char*做参数而且必须以\0结尾.
sizeof()括号中的内容是不会被编译的,而是被类型代替,如sizeof(a=6),a=6并不会执行
对函数使用sizeof(),在编译阶段会被返回值所代替.
sizeof(string)==4,因为其内部实现是指针动态分配内存,故大小为一个指针大小4.
空类所占的空间为1,单一继承的空类空间也为1,多重继承的空类空间还是1.但是虚继承涉及虚表(虚指针)所以大小为指针大小。
内联函数与宏的区别:
内联函数比普通函数要快,函数调用是有额外开销的比如参数压栈,在编译的时候内联函数直接镶嵌到目标代码当中,而宏只是简单的替换.
内联函数要做参数类型检查,这是内联函数跟宏相比的优势.
inline是镶嵌代码,在调用函数的地方不是跳转,而是把代码直接写到那里去,这样消耗了更多空间换来了效率提高.
inline一般用于:
1.一个函数不断地被重复调用.
2.函数只有几行,不包含for while switch语句.
inline必须与函数定义体放在一起才能成为内联.
若函数的执行的效率太低,其大部分时间都在实现函数代码上,那么这时候就不要用inline了,如果函数的开销大部分在调用上,那么使用inline是个很好的选择.
类的构造和析构函数不一定使用内联比较好,要看是否调用了基类的构造函数.
标记inline不一定起作用,具体还是看编译器怎么处理。
指针和引用的区别:
1.非空区别.指针可以为空,引用不能为空.
2.合法性区别,引用在使用前不需要检测,而指针经常被检测是否为空.
3.可修改区别,指针与引用的另一个重要的区别是指针可以被重复赋值以指向另一个不同的对象.
4.应用区别,如需要指向空对象或者需要在不同时刻指向不同的对象则使用指针,否则应该使用引用.
本质引用是用指针实现的,引用在访问时自动取地址操作。
函数指针:void (*f)()
函数返回指针:void *f()
const指针:const int*
指向const的指针:int* const
指向const的const指针:const int* const
函数指针的用法如下:
int max(int,int);
int (*p)(int,int)=&max;
(*p)(a,b);
指针数组:*p[10]
数组指针:(*p)[10]
迷途指针的产生是指针delete后没有设置为空.
malloc/free和new/delete的区别:
malloc和free是标准库函数,new/delete是c++的运算符.他们都可以用于申请动态内存和释放内存.
对于非内部对象而言,你在创建的时候需要调用构造函数,消亡时需要调用析构函数,故产生了new和delete函数。
shared_ptr:采用引用计数的方法,当引用为0时才释放内存,可以有多个shared_ptr指向一个对象
unique_ptr:同一时间只能有一个unique_ptr指向一个对象
weak_ptr:辅助shared_ptr,不会引起shared_ptr引用计数加1,一般是为了解决shared_ptr的循环引用
关于this指针:
1.this指针本质是一个函数参数,只是编译器隐藏了起来.this只能在成员函数中使用.
2.this在成员函数的开始前构造,结束后删除.
3.this指针并不占用对象空间.
map和set底层实现都是红黑树,因为红黑树插入和删除时旋转最多只需要3次,比起其他的平衡树来说更便于统计.比起hash的优势是有序,复杂度更稳定。
面向对象的三大原则:封装 继承 多态.
多态是一个接口多种方法,c++通过虚函数来实现多态.
对于一个空类,编译器默认生成构造 析构 拷贝 赋值函数
struct和class是一样的,只是struct默认访问是public而class默认是private
静态成员函数可以只能访问静态成员.
const标识的常量必须在构造函数里面初始化.或者设置为static.
析构函数若有派生类的情况必须声明是virtual.构造函数不能为virtual.
构造函数冒泡后面的是成员变量初始化列表.
RAND_MAX是随机数能取的最大值.
dynamic_cast:用于上行类转换到下行类派生类,且只能转换指针和引用。运行时检查,比较耗性能。基类必须要有虚函数。
static_cast:相当于c的强制类型转换,不安全,当你排除了其他三种之后就用这个。
const_cast:改变const和volatile属性,只能用于指针和引用。
reinterpret_cast:用于无关联的转换,一般用于指针和整型的转换,指针和指针间的转换。
union里的所有数据都是同一个地址。
在C语言中,static关键字至少有下列几个作用:
函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分
配一次,因此其值在下次调用时仍维持上次的值。
在模块内的static全局变量可以被模块内所有函数访问,但不能被模块外其他函数访
问。
在模块内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限
制在声明它的模块内。
在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝。
在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问
类的static成员变量。
局部静态变量在第一次使用时初始化,且线程安全。
栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等。
其操作方式类似于数据结构中的栈。
堆区(heap):一般由程序员分配和释放,若程序员不释放,程序节束时可能由操
作系统回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一
块区域。程序节束后由系统释放。
文字常量区:常量字符串就是放在这里的。程序节束后由系统释放。
程序代码区:存放函数体的二进制代码。
进程虚拟内存分布从低到高是这样的: text代码段——data数据段——bss段——heap——memory map——stack
kernel空间在最高的地址。
堆和栈的区别:
从内存分布上讲,堆从低地址向高地址扩展,栈从高地址向低地址扩展。
从分配效率上讲,堆的分配效率较低,但是可控,栈的分配效率较高,但是不可控。
从空间大小上讲,栈的空间比较小,堆的空间比较大。
排序的稳定性指的是排序前的系列存在a[i]==a[j]且i<j,那么如果排序后他们的相对次序不变证明是稳定的。
c的编译过程:
预处理:替换掉带#的东西,如#include,#define
编译:C源码翻译成汇编
汇编:汇编翻译成机器代码
链接:符号解析和重定位,将程序每一个全局变量和全局函数的引用和符号表里的一个符号对应起来,重定位确定每一个模板模块的全局变量和函数在可执行文件内存空间的位置。
重载重写和重定义:
重载是指函数名一样但是参数不一样,发生在同一个作用域。
重写是指派生类覆盖基类的方法,要求返回值参数函数名完全一样,且是虚函数。
重定义是指派生类通过定义一个与父类同名的函数进行对父类函数的隐藏。返回值和参数可以不一样但必须同名。
左值和右值:
左值可以简单理解为有变量名,有地址的值。其他的例如临时变量都是右值。