C++校招面经【典藏版】——C/C++部分

1.在main函数执行之前和之后执行的代码可能是什么?

main函数执行之前,主要就是初始化系统相关资源:

包括:1.设置栈指针

           2.初始化静态static变量和global全局变量,即.data段的内容

           3.将未初始化部分的全局变量赋初值:数值型short,int,long为0,bool为false,指针为NULL等等,即.bss段的内容。

           4.全局对象初始化,在main之前调用构造函数,这是可能会执行前的一些代码。

           5.将main函数的参数argc,argv等传递给main函数,然后才真正运行main函数。

           6._attribute_((constructor))

main函数执行之后:

        1.全局对象的析构函数会在main函数之后执行;

        2.可以用atexit注册一个函数,他会在main之后执行;

        3._attribute_((destructor))

2.结构体内存对齐问题?

        结构体内成员按照声明顺序存储,第一个成员地址和整个结构体相同。

        未特殊说明时,按结构体中size最大的成员对齐(double成员,按8字节对齐)。

        C++11以后引入两个关键字alignas与alignof,其中alignof可以计算出类型的对齐方式,alignas可以指定结构体的对齐方式。

3.指针和引用的区别

        指针是一个变量,存储的是一个地址,引用跟原来的变量实质上是一个东西,是原变量的别名。

        指针可以有多级,引用只能有一级。
        指针可以为空,引用不能为NULL且在定义时必须初始化。

        指针在初始化后可以改变指向,而引用在初始化之后不可以再改变。

        sizeof指针得到的是本指针的大小,sizeof引用得到的是引用所指变量的大小。

        当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以。

        引用本质是一个指针,同样会占用4字节;指针是具体变量,需要占用存储空间。

        引用在声明时必须初始化为另一变量,一旦出现必须为typename refname &varname形式;指针声明和定义可以分开,可以先只声明指针变量而不初始化,等到用的时候再指向具体变量。

        引用一旦初始化之后就不可以再改变(变量可以被引用多次,但引用只能作为一个变量引用);指针变量可以重新指向别的变量。

        不存在指向空值的引用,必须有具体实体;但是存在指向空值的指针。

4.在传递函数参数时,什么时候该使用指针,什么时候该使用引用呢?

        需要返回函数内局部变量的内存的时候使用指针。使用指针传参需要开辟内存,用完记得释放指针,不然后内存泄漏。而返回局部变量的引用确是没有意义的。

        对栈空间大小比较敏感(比如递归)的时候使用引用。使用引用传递不需要创建临时变量,开销要更小。

        类对象作为参数传递的时候使用引用,这是C++类对象传递的标准方式。

5.堆和栈的区别

        申请方式不同:栈由系统自动分配。堆是自己申请和释放的。

        申请大小限制不同:栈顶和栈底是之前预设好的,栈是向栈底拓展,大小固定,可以通过ulimit -a查看,由ulimit -s修改。堆向高地址拓展,是不连续的内存区域,大小可以灵活调整。

        申请效率不同:栈由系统分配,速度快,不会有碎片。堆由程序员分配,速度慢,且会有碎片。

        栈空间默认是4M,堆区一般是1G~4G。

6.你觉得堆快一点还是栈快一点?

毫无疑问是栈快一点。

        因为操作系统会在底层对栈提供支持,会分配专门的寄存区存放栈的地址,栈的入栈出栈操作也十分简单,并且由专门的指令执行,所有栈的效率比较高也比较快。

        而堆的操作是由C/C++函数库提供的,在分配堆内存的时候需要一定的算法寻找合适大小的内存。并且获取堆的内容需要两次访问,第一次访问指针,第二次根据指针保存的地址访问内存。因此堆比较慢。

7.区别以下指针类型?

int *p[10]
int (*p)[10]
int *p(int)
int (*p)(int)

int *p[10]表示指针数组,强调数组概念,是一个数组变量,数组大小为10,数组内每个元素都是指向int类型的指针变量。

int (*p)[10]表示数组指针,强调是指针,只有一个变量,是指针类型,不过指向的是一个int类型的数组,这个数组的大小是10。

int *p(int)是函数声明,函数名是p,参数是int类型的,返回值是int*类型的。

int (*p)(int)是函数指针,强调是指针,该指针指向的函数句有int类型参数,并且返回值是int类型的。

8、new/delete与malloc/free的异同

相同点:

        都可以用于内存的动态申请和释放

不同点:

        前者是C++运算符,后者是C/C++语言标准库函数

        new自动计算要分配的空间大小,malloc需要手动计算

        new是类型安全的,malloc不是,比如:

int *p = new float[2]; //编译错误
int *p = (int*)malloc(2 * sizeof(double));//编译无错误

        new调用名为operator new 的标准库函数分配足够的空间并调用相关对象的构造函数,delete对指针所指对象运行适当的析构函数;然后通过调用名为operator delete的标准库函数释放该对象所用内存。后者均没有相关调用。

        后者需要库文件支持,前者不需要。

        new是封装了malloc,直接free不会报错,但是这只是释放内存,而不会析构对象。

9.new和delete是如何实现的?

new的实现过程:

        首先调用名为operator new的标准库函数,分配足够大的原始为类型化的内存,以确保指定类型的一个对象;接下来运行该类型的一个构造函数,用指定初始化构造对象;最后返回指向新分配并构造后的对象的指针。

delete的实现过程:

        对指针指向的对象运行适当的析构函数;然后通过调用名为operator delete的标准库函数释放该对象所用内存。

10.malloc和new的区别?

        malloc和free是标准库函数,支持覆盖;new和delete是运算符,支持重载。

        malloc仅仅分配内存空间,free仅仅回收空间,不具备调用构造函数和析构函数功能,用malloc分配空间存储类的对象存在风险;new和delete除了分配回收功能外,还会调用析构函数和构造函数。        

        malloc和free返回的事void类型指针(必须进行类型转换),new和delete返回的事具体的类型指针。

11.既然有了malloc/free,C++中为什么还需要new/delete呢?直接用malloc/free不好吗?

        malloc/free和new/delete都是用来申请内存和回收内存的。

        在对非基本数据类型的对象使用的时候,对象创建的时候还需要执行构造函数,是已经编译的代码,所以不能把构造函数和析构函数的功能强加给malloc/free,所以new/delete是必不可少的。

12.被free回收的内存是立即返还给操作系统吗?

        不是的。被free回收的内存首先会被ptmalloc使用双链表保存起来,当用户下一次申请内存的时候,会尝试从这些内存中寻找合适的返回。这样就避免了频繁的系统调用,占用过多的系统资源。同时ptmalloc也会尝试对小块内存进行合并,避免过多的内存碎片。

13.宏定义和函数有何区别?

        宏在预处理阶段完成替换,之后被替换的文本参与编译,相当于直接插入了代码,运行时不存在函数调用,执行起来更快;函数调用在运行时需要跳转到具体调用函数。

        宏定义属于在结构中插入代码,没有返回值;函数调用具有返回值。

        宏定义参数没有类型,不进行类型检查;函数参数具有类型,需要检查类型。

        宏定义不要再最后加分号。

14.宏定义和typedef区别?

        宏主要用于定义常量及书写复杂的内容;typedef主要用于定义类型别名。

        宏替换发生在编译阶段之前,属于文本插入替换;typedef是编译的一部分。

        宏不检查类型;typedef会检查数据类型。

        宏不是语句,不在最后加分号;typedef是语句,要加分号表示结束。

        注意对指针的操作。typedef char * p_char 和#define p_char char *区别巨大。

15.变量声明和定义区别?

        声明仅仅是把变量的声明位置及类型提供给编译器,并不分配内存空间;定义要在定义的地方为其分配存储空间。

        相同变量可以在多出声明(外部变量extern),但只能在一处定义。

16.strlen和sizeof区别?

        sizeof是运算符,并不是函数,结果在编译时得到而非运行中获得;strlen是字符处理的库函数。

        sizeof参数可以是任何数据的类型或者数据(sizeof参数不退化);strlen的参数只能是字符指针且结尾是‘\0’的字符串。

        因为sizeof值在编译时确定,所以不能用来得到动态分配(运行时分配)存储空间的大小。

  int main(int argc, char const *argv[]){
      
      const char* str = "name";

      sizeof(str); // 取的是指针str的长度,是8
      strlen(str); // 取的是这个字符串的长度,不包含结尾的 \0。大小是4
      return 0;
  }

        在64位的编译环境下,指针的占用大小为8字节;32位环境下,指针大小为4字节。一个指针占用内存的大小和编译器环境有关,而与机器的位数无关。

17.常量指针和指针常量区别?

        指针常量是一个指针,读成常量的指针,指向一个只读变量,也就是后面所指明的int const和const int,都是一个常量,也可以写作int const *p或 const  int *p。

        常量指针是一个不能给改变指向的指针。指针是个常量,必须初始化,一旦完成初始化,它的值(也就是存放在指针中的地址)就不能改变了,即不能中途改变指向,如int *const p.

18.a和&a有什么区别?

假设数组int a[10];int (*p)[10]=&a;其中:

        a是数组名,是数组首元素地址,+1表示地址值加上一个int类型的大小,如果a的值是0x00000001,加1操作后变为0x00000005. *(a+1)=a[1].

        &a是数组的指针,其类型为 int (*)[10](就是前面提到的数组指针),其加1时,系统会认为是数组首地址加上整个数组的偏移(10个int型变量),值为数组a尾元素后一个元素的地址。

        若(int *)p ,此时输出*p时,其值为a[0]的值,因为被转为int*类型,解引用时按照int类型大小来读取。

19.C++和Python的区别?        

包括但不限于:

        Python是一种脚本语言,是解释执行的,而C++是编译语言,是需要编译后再特定平台运行的。pyhton可以很方便的跨平台,但是效率没有C++高。

        Python使用缩进来区分不同的代码块,C++使用花括号来区分。

        C++中需要事先定义变量的类型,而Python不需要,Python的基本数据类型只有数字,布尔值,字符串,列表,元组等等。

        Python的库函数比C++的多,调用起来很方便。

20.C++和C语言的区别

        C++中new和delete是对内存分配的运算符,取代了C中的malloc和free。

        标准C++中的字符串取代了标准C函数库头文件中的字符数组处理函数(C中没有字符串类型)

        C++中用来控制态输入输出的iostream类替换了标准C中的stdio函数库。

        C++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和longjmp()函数。

        在C++中,允许有相同的函数名,不过他们的参数类型不能完全相同,这样这些函数就可以相互区别开来。而这在C语言中是不允许的。(也就是C++的重载功能)

        在C++中允许变量自定义语句在程序中的任何地方,只要是在使用它之前就可以;而在C语言中,必须要在函数开头部分。而且C++不允许重复定义变量,C语言也是做不到这一点的。

        在C++中,除了值和指针外,新增了引用。引用型变量是其他变量的一个别名,我们可以认为他们只是名字不同,其他都是相同的。

C++相对C增加了一些关键字,如:bool,using,dynamic_cast,namespace等。

后续正在更新......

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值