[toc]

内存布局

零散知识点 - 图1


const

  1. 用于变量
  2. 用于指针:分两种情况

    1. int a;
    2. const int* p = &a; // 指向常量的指针 (*前)
    3. int* const p = &a; // 指向变量的常指针 (*后)
  3. 用于形参

  4. 修饰成员函数:成员函数无法修改成员变量

全局变量和static

全局变量
在其他文件中也可以用。
静态局部变量

  • 变量存放在全局数据段,生命期和程序相同。

    1. int func() {
    2. static int a = 0;
    3. return ++a;
    4. }
    5. int main() {
    6. printf("%d\n", func());
    7. printf("%d\n", func());
    8. }
    9. // 1
    10. // 2

    静态函数

  • 其他文件不可见

静态全局变量

  • 变量位于全局数据段;其他文件不可见

类的静态成员

  • 类的静态字段:位于全局数据段;所有对象共享这个数据;在没有对象存在时就可以使用。
  • 类的静态方法:同理;只能访问类的static字段。

extern

作用1:引用在其他模块中定义的全局变量或函数,否则会发生重定义。
作用2:extern "C",修饰变量或函数按照C语言的方式编译和链接。


sizeof

  1. 用于数组:得到整个数组占用的空间
  2. 用于指针:得到指针占用的空间(~4字节)。

new和malloc

malloc是函数,分配堆内存。
new是运算符,首先调用构造函数,然后使用malloc分配内存。


delete this

是合法的,在这之后,这个对象就没法再用了。


堆中类和栈中类

仅能在堆中使用的类:将析构函数私有化.因为栈中对象的生命期是编译器控制的,析构无法访问,则不能在堆上创建。
仅能在栈中使用的类:将new运算符和delete运算符私有化。


内存对齐

内存对齐是结构体需要考虑的,四字节对齐。
注:单个union占用的空间,等于size最大的成员的size。


浅拷贝和深拷贝

浅拷贝和深拷贝的区别是:类里面的指针。


?运行时类型信息?

  • typeid运算发允许运行时确定对象的类型
  • type_info类描述类型信息。

使用memcmp比较结构体

  1. struct Acc {
  2. int a;
  3. short b;
  4. };
  5. Acc a, b;
  6. memcmp(&a, &b, sizeof(Acc));

不能,因为存在内存对齐,对齐的内存是随机的。

浮点数作比较

不能使用==,应该判断差值是否在误差范围内。

可变参数的实现

依赖于这几个宏:

  1. typedef char * va_list;
  2. #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1)&~(sizeof(int) - 1))
  3. #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
  4. #define va_arg(ap,t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
  5. #define va_end(ap) ( ap = (va_list)0 )

参数列表在栈中的内存布局:
零散知识点 - 图2

  • _INTSIZEOF(n):计算类型内存对齐后占用的空间。比如struct{int a; short b};就占用8B
  • va_start(ap, v):使用ap来记录可变参数的首地址。其中v是最后一个非可变参数。
  • va_arg(ap, t):从地址ap中取出类型为t的值,并且使ap指向下一个可变参数。
  • va_end(ap):结束。

下面是自己实现的一个可变参数函数:

  1. // 打印count个int
  2. void PrintInt(int count, ...) {
  3. va_list ap;
  4. __crt_va_start(ap, count);
  5. for (int i = 0; i < count; ++i) {
  6. cout << __crt_va_arg(ap, int) << endl;
  7. }
  8. __crt_va_end(ap);
  9. }

判断单链表是否有环

由于环存在的位置不可知,所以可以使用两个指针:fastPtr, slowPtr,如果有环,那么两个指针就可能在环中相遇。
注:指针的快慢有要求,并不是每一种指针设置都可以达到要求。最好使用的是:fastPtr一次走两格,slowPtr一次走一格。
衍生1:求环长:首先要进入环。然后固定fastPtr,让slowPtr走即可。
衍生2:判断环的入口:TODO

判断单链表是否相交

首先,相交只有两种情况:要么都是无环链表,有么都是有环链表。因为相交之后,后续链表就相同了。
先判断有环情况:打破第一个环,如果第二个环也破了,那么说明相交。
无环情况:判断最后一个结点是否相同即可。

strcpymemcpy的区别是什么

  • strcpy无需指定长度,memcpy需要。