京东C++开发工程师 2020校招卷总结

1.静态函数

在函数的返回类型前加上static关键字,函数即被定义为静态函数。以下关于静态函数的描述正确的是:
在这里插入图片描述
B\C明显错误,因为static修饰全局变量或者函数时,主要是为了限制该全局变量或者函数的作用域仅限于本文件,所以又称为内部函数。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

选项A我认为是正确的,静态成员函数无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数;而静态函数也无法访问属于类对象的非静态数据成员、非静态成员函数,可以通过成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数。

对于选项D是正解答案存疑

什么是static?

static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。

在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题。

static可以做到让函数中变量的值保存至下一次调用,同时不破坏此变量的访问范围,即在此函数中定义的变量,仅仅只受此函数控制。且静态函数会被自动分配在一个一直使用的存储区,直到程序结束才从内存消失,避免调用函数时压栈出栈,速度快很多

static的作用

总的来说
(1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
(2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
(3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
(4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
(5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。

总结一下:
static的作用主要有2个:
  一是隐藏功能,对于static修饰的函数和全局变量而言,其作用于局限于所在的文本,不能被其他文本内的函数使用
  二是保持持久性功能,对于static修饰的局部变量而言,其存储区变更到静态存储区,程序结束不销毁并且,因为存放在静态区,全局和局部的static修饰的变量,都默认初始化为0。

静态成员函数

静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。

编译器在编译一个普通成员函数时,会隐式地增加一个形参 this,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象后通过对象来调用,因为它需要当前对象的地址。而静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,所以不能访问普通成员变量,只能访问静态成员变量。静态成员函数可以通过类来直接调用。

加入有一个student类,里面声明了一个static int getTotal(); 静态成员函数,那么它的调用可以是:

Student::getTotal();

静态函数中声明的变量是静态变量 ?

总结而言,static函数的用途主要有两个:

  1. static函数修饰限制函数的使用地点的作用域仅限于本文件
  2. 被static修饰的类成员函数是类的函数也是全局函数,而不是类对象的成员函数

一个静态变量只初始化一次,但是静态函数中声明的变量是否只初始化一次呢?尝试一下:
在这里插入图片描述在这里插入图片描述

第一张图的意思代表定义了一个static函数func,如果符合说法静态函数中声明的变量是静态变量,它里面的变量a就是静态变量,只初始化一次,那么第二次调用func输出就应该是2,而不是再调用了一次int a=1;第二张图用来对比,给出变量a就是静态变量时应该出现的结果。

所以判断D选项错误,有异见的朋友欢迎评论区留言呀~

2. 宏常量和const

在c语言中,#define定义了宏常量,它与const定义的常量有很大的区别,以下描述两者区别中正确的是:

  1. const常量有数据类型,而宏常量没有数据类型,但编译器可以对两者都进行类型安全检查
  2. 编译器可以对两者进行类型安全检查。并可以对宏常量进行字符替换
  3. 集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试
  4. 在C++程序中使用const常量和宏常量,但const常量可取代宏常量

在这里插入图片描述

宏常量和const的实现机制

宏是预处理命令,即在预编译阶段进行字节替换。const常量是变量,在执行时const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态存储区的只读数据区。根据c/c++语法,当你声明该量为常量,即告诉程序和编译器,你不希望此量被修改。 程序的实现,为了保护常量,特将常量都放在受保护的静态存储区内。凡是试图修改这个区域内的值,都将被视为非法,并报错。 )

宏常量和const的区别

  1. 类型和安全检查不同
    #define 宏没有类型,不做任何类型检查,仅仅是展开。
    const 常量有具体的类型,在编译阶段会执行类型检查。
  2. 编译器处理方式不同
    #define 宏是在预处理阶段展开。
    const 常量是编译运行阶段使用。
  3. 存储方式不同
    #define 宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。)
    const定义常量会分配内存。

在C++ 程序中只使用const 常量而不使用宏常量,即const 常量完全取代宏常量

扩展:C与C++语言中const 常量的区别

  1. 可修改性:C++ 中的const 可以理解为在编译阶段的值替换过程,比如对于 const int n = 10;可以直接理解为n是10的别名。但要注意C++中的常量还是会占内存; C语言中不一样,它是一个占用内存的变量,只不过这个变量被const修饰。C语言的const 变量是可以通过指针修改的,比如经过如下代码时,C++ 中n的值仍然为10,但是C语言中n的值变为99:
    const int n = 10;
    int *p = (int*)&n;  //必须强制类型转换,const要是转为非const时,编译器才不会报错
    *p = 99;
  1. 作用域:C语言中 const 全局变量的可见范围是整个程序,在其他文件中使用 extern 声明后就可以使用;而C++中 const 全局变量的可见范围仅限于当前文件,在其他文件中不可见,和添加了static关键字的效果类似。所以它可以定义在头文件中,多次引入后也不会出错。

3. 判断输出题

引用可以作为参数在函数中进行传递,以下程序输出结果为:

#include<iostream>
using namespace std;
void test(int &a)
{
  cout<<&a<<", "<<a<<endl;
}
int main(void)
{
    int a=1;
    cout<<&a<<", "<<a<<endl;
    test(a);
    system("pause");
    return 0;
}

在这里插入图片描述
此题考查&再什么时候代表引用,在什么时候表示取地址。

定义、形参声明时加&表示引用,使用时加&表示取地址。所以第一次 cout<<&a<<", "<<a<<endl;
输出 0x22ff44 , 1
然后将a的引用作为test()函数的形参, 第二次cout<<&a<<", "<<a<<endl;
输出依旧为 0x22ff44 , 1

4. const和指针

const可以用来修饰指针(*),对以下代码理解不正确的是:

const int* a = & [1]          
int const *a = & [2]          
int* const a = & [3]          
const int* const a = & [4]

在这里插入图片描述

const简介

当希望变量在整个作用域中都保持固定时,使用const来定义变量。 const 变量称为常量(Constant)。常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化)。

const和指针

const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

int const * p1; //const修饰的是*p1,所以*p1是个常量,p1还是个变量
//翻译下就是 p1指针本身的值可以修改,但是它指向的数据不能被修改。
const int  * p2; //const修饰的是*p2,所以*p2是个常量,p2还是个变量
int * const  p3; //const修饰的是p3,所以p3是个常量,*p3还是个变量
int const * const p4; //第一个const修饰的是*p4,第二个const修饰的是p4,所以*p4,p4都是常量

int const * p1;const int * p2; 一样

5. 判断输出题

以下c代码输出是?

 #include <stdio.h>
    struct p
     {
        int x;
        int y;
    };
    int main()
    {
        struct p p1[] = {1, 92, 3, 94, 5, 96};
        struct p *ptr1 = p1;
        int x = (sizeof(p1) / 5);
        if (x == 3)
            printf("%d %d\n", ptr1->x, (ptr1 + x - 1)->x);
        else
            printf("false\n");
    }

此题考查sizeof(struct)和结构体初始化方式

sizeof(struct)

详细介绍请见2019卷第28题

简单来讲就是结构体需要考虑内存对齐三原则:
1.对齐基数; 2.结构体内成员存放位置要求;3.结构体总大小。

对于结构体中的每个成员,要满足成员的存放位置必须是 min(成员自身类型的大小,对齐基数) 的倍数,还有结构体总大小必须是min(结构体内最大成员,对齐基数)的倍数这两个条件。在没有#pragma pack宏的情况下,一般默认对齐基数为8

结构体数组的初始化方式

对结构体数组p1定义的同时初始化,可以对所有元素进行初始化,也可以对部分元素进行初始化,其他未初始化的元素,系统会自动赋值为0.

最规范的初始化方式:

struct p p1[3] = {{1, 92}, {3, 94}, {5, 96}};

容许的初始化方式:

struct p p1[3] = {1, 92, 3, 94, 5, 96};//可以不用对每个结构体加大括号
struct p p1[] = {1, 92, 3, 94, 5, 96};//按照分配好的空间依次给结构体数组赋值
struct p p1[3] = {{1}, {3, 94}, {5, 96}};//缺省的位置默认为0
struct p p1[3] ={}//默认为{{0,0},{0,0},{0,0}}

会报错的初始化方式:

struct p p1[] = {{1, 92, 3}, {94, 5}, 96};//第一个结构体三个元素超过了结构体的容量
struct p p1[] = {} //没有具体意义

6. 对象指针指向NULL

以下程序片段输出什么内容:

class Demo {
  public:
      Demo():count(0) {}
      ~Demo() {}
      void say(const std::string& msg) {
          fprintf(stderr, "%s\n", msg.c_str());
      }   
  private:
      int count;
};
int main(int argc, char **argv) {
    Demo* v = NULL;
    v->say("hello world");
}

这里会正常输出"hello world"

NULL的定义

NULL 是一个标准规定的宏定义,用来表示空指针常量,当一个指针变量被赋值为NULL时,表示它不再指向任何有效地址,无法在访问任何数据。在对NULL指针进行解引用或者指向操作,会出现coredump或者其他undefined行为。

值为NULL对象指针调用普通成员函数

普通成员函数中未使用成员变量

对于类中的成员函数,隶属于所有类的对象,程序编译后,成员函数的地址已经确定,而成员函数访问类中的成员变量时,需要借助this指针对各个对象进行区分。

对于类Demo的成员函数say原型为void Demo::say();,编译器会在发生函数在调用时,将其解释为void Demo::say(Demo *const this);。注意这里的参数,this指针表示调用此函数的类Demo的对象地址。对于调用端,编译器将进行如下解释:

 Demo *p = NULL;
 p->say();    //->say(p);

例子中传入的p为NULL,而在成员函数say中,并未有用到通过this指针访问成员变量的语句,所以通过NULL指针调用say时,得到了正确的结果。

普通成员函数中使用成员变量

如果我们改一下类Demo的定义,添加成员变量,并且在say中进行访问,那么仍然用p(NULL)指针来调用成员函数say,则会使程序崩溃,因为函数对NULL指针进行了指向操作,产生了为undefined行为。

值为NULL对象指针调用虚函数(函数前加virtual关键字)

虚函数中的地址(函数指针)保存在虚函数表中,可以将它看做一个函数指针数组(列表),含有虚函数的类拥有一张虚函数表,而此类的每一个对象在构造时,由编译器将一个指向虚函数表的指针安插进来,成为虚表指针,而它的作用是在我们调用虚函数时,能更准确的访问到虚函数表中此函数的指针,从而进行调用。回过头来看看之前的例子,我们根据类Demo的NULL指针p调用它的虚函数,而此时由于没有进行初始化,所以虚指针没有安插进去,所以程序崩溃。

7. 死锁的产生条件

死锁的产生的原因有很多,系统资源不足,进程运行推进的顺序不合适,资源分配不当等都会造成死锁,产生死锁的必要条件为:
在这里插入图片描述
2019卷第15题

8. chmod命令

增加用户对test.sh脚本的可执行权限可以使用命令( )
在这里插入图片描述
具体查看linux常用命令总结(一)第三个知识点。

9.静态局部变量

在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。以下关于静态局部变量特点描述错误的是:

  1. 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化 (×)
  2. 静态局部变量在全局数据区分配内存 (×)
  3. 静态局部变量始终驻留在全局数据区,直到程序运行结束。其作用域为全局作用域,当定义它的函数或语句块结束时,其作用域随之结束 (√)
  4. 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0 (×)

在修饰变量的时候,static 修饰的静态局部变量在全局数据区分配内存 、只执行初始化一次。一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0 。而且延长了局部变量的生命周期,直到程序运行结束以后才释放。

3.的错误在于程序运行结束以后静态局部变量才会释放,并不是定义它的函数或语句块结束时释放。

10.linux–grep和sed命令的使用

已知linux系统eth0信息如下:

eth0 Link encap:Ethernet HWaddr 20:56:BC:06:34:24

inet addr:10.18.1.10 Bcast: 10.18.1.255 Mask:255.255.255.0

inet6 addr: fe80::223:beab:cda3:3504/64 Scope:Link

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

执行命令( )时可显示为:10.18.1.10 Bcast: 10.18.1.255 Mask:255.255.255.0
在这里插入图片描述
管道符 “|”:将两个命令分隔开,“|”左边命令的输出就会作为“|”右边命令的输入

/sbin/ifconfig eth0

linux系统中/sbin目录用来存放用于管理员使用的存储二进制系统程序文件。因为其中的大部分文件多是系统管理员使用的基本的系统程序,所以虽然普通用户必要且允许时可以使用,但一般不给普通用户使用。
ifconfig可设置网络设备的状态,或是显示目前的设置。示例:在这里插入图片描述
/sbin/ifconfig eth0给出的信息即题目中给出的信息

grep

grep命令的详细介绍见linux常用命令总结(一)第五个知识点

/sbin/ifconfig eth0 | grep 'inet addr' 

表示以/sbin/ifconfig eth0的输出为输入,查找有字符串’inet addr’的行
得到输出inet addr:10.18.1.10 Bcast: 10.18.1.255 Mask:255.255.255.0

sed

/sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g' 

在输出行 inet addr:10.18.1.10 Bcast: 10.18.1.255 Mask:255.255.255.0 的基础上,将^.*addr:替换为空,即删除inet addr:,得到10.18.1.10 Bcast: 10.18.1.255 Mask:255.255.255.0 。

sed 命令介绍如下:

sed 命令是利用脚本命令来处理文本文件,这些命令要么从命令行中输入,要么存储在一个文本文件中,此命令执行数据的顺序如下:

  1. 每次仅读取一行内容;
  2. 根据提供的规则命令匹配并修改数据。注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据;
  3. 将执行结果输出。
    当一行数据匹配完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。

关于sed的简单用法:

sed [选项] [脚本命令] 文件名
命令常用选项
在这里插入图片描述
脚本命令动作说明
a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何东东;
i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

sed s替换脚本命令总结

s/pattern/replacement/flags

在这里插入图片描述
如果s脚本命令没有flags标记,只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A,则只会替换第一个 A;当s脚本命令有flags标记时,使用例子如下:

  1. sed 's/test/trial/2' test.txt: sed 编辑器只替换每行中第 2 次出现的匹配模式。
  2. sed 's/test/trial/g' test.txt:用新文件替换所有匹配的字符串
  3. sed -n 's/test/trial/p' test.txt: -n 选项会禁止 sed 输出,但 p 标记会输出修改过的行,将二者匹配使用的效果就是只输出被替换命令修改过的行
  4. sed 's/test/trial/w test.txt' data.txt: w 标记会将从data.txt匹配后的结果保存到指定文件test.txt中
  5. sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd:替换类似文件路径的字符串会比较麻烦,需要将路径中的正斜线进行转义。这里表示将/etc/passwd文件中,每一行的的第一个/bin/bash 替换成/bin/csh。
sed d 替换脚本命令

在默认情况下 sed 并不会修改原始文件,这里被删除的行只是从 sed 的输出中消失了,原始文件没做任何改变。

  1. sed 'd' test.txt:没有指定具体行,删除指定行中的所有内容
  2. sed '3d' test.txt:删除指定行,删除 test.txt 文件内容中的第 3 行
  3. sed '1,3d' test.txt:删除行区间,删除 test.txt 文件内容中的第 1~3行
  4. sed '/1/,/3/d' test.txt:也可以使用两个文本模式来删除某个区间内的行,但这么做时要小心,你指定的第一个模式会“打开”行删除功能,第二个模式会“关闭”行删除功能,因此,sed 会删除两个指定行之间的所有行(包括指定的行)
  5. sed '3,$d' test.txt:删除 test.txt 文件内容中第 3 行开始的所有的内容,利用率结尾
sed 其他脚本命令
  1. sed '3i\\This is an inserted line.' test.txt:在第三行前插入’This is an inserted line.',插入动作完成后,'This is an inserted line.‘在第三行;sed '3a\\This is an appended line.' test.txt:在第三行后附加’This is an inserted line.’,附加动作完成后,'This is an appended line.'在第四行;
    a 命令表示在指定行的后面附加一行,i 命令表示在指定行的前面插入一行
  2. sed '3c\This is a changed line of text.' test.txt: 将第三行的内容替换为This is a changed line of text,c 命令表示将指定行中的所有内容,替换成该选项后面的字符串。与sed '/number 3/c\This is a changed line of text.' test.txt 一样
  3. sed 'y/123/789/' test.txt:将文本行中找到的所有1字符替换成7、2字符替换成8、3字符替换成9,这个映射过程会一直持续到处理完指定字符。如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。
  4. sed -n '/number 3/p' test.txt:只输出第三行。p 命令常见的用法是打印包含匹配文本模式的行,用 -n 选项和 p 命令配合使用,我们可以禁止输出其他行,只打印包含匹配文本模式的行。
  5. sed '1,2w test.txt' data.txt:将数据流data.txt中的前两行打印到一个文本文件test.txt中
  6. sed '3r test.txt' data.txt:将test.txt文件中的内容插入到data.txt指定行第三行的后面。r 命令用于将一个独立文件的数据插入到当前数据流的指定位置
  7. sed '2q' test.txt:打印输出第 2 行之后,就停止。q 命令的作用是使 sed 命令在第一次匹配任务结束后,退出 sed 程序,不再进行对后续数据的处理。

11. malloc/free 与 new/delete的区别

以下关于malloc/free 与 new/delete的区别描述错误的是:

  1. new建立的是一个对象;malloc分配的是一块内存 (×)
  2. new可以认为是malloc加构造函数的执行。new出来的指针是void*指针。而malloc返回的是带类型信息的 (√)
  3. malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请和释放动态内存(×)
  4. 对于非内部数据类型的对象而言,用maloc/free无法满足动态对象的要求,C++语言需要一个能完成动态内存分配和初始化工作的运算符new,和一个能完成清理与释放内存工作的运算符delete(×)

malloc、free简介

malloc/free为C的标准库函数,函数原型为:

void* malloc(size_t size)//参数代表字节个数
void free(void* pointer)//参数代表内存地址

用malloc分别开辟了1个和4个整型大小的空间和并free释放它们示例:

void func() 
{ 
//开辟一个空间 
int* p1=(int*)malloc(sizeof(int)); 
if(p1==NULL) 
{ 
exit(1); 
} 
free(p1); 
//开辟多个空间 
int*p2=(int*)malloc(sizeof(int)*4); 
if(p2==NULL) 
{ 
exit(1); 
}
free(p2);
}

new/delete简介

new、delete则为C++的操作运算符,它调用的分别为赋值运算符重载operator new()和operator delete();

使用示例:

void func() 
{ 
//开辟一个空间 
int* p1=new int(1); 
delete p1; 
//开辟多个空间 
int*p2=new int[4];
delete []p2;
}
new/delete、new[]/delete[]实现机制:

new/delete则不仅会开辟空间,并调用构造函数和析构函数进行初始化和清理
在这里插入图片描述
在这里插入图片描述
new[]/delete[]在开辟大小会多开辟四个字节,用于存放对象的个数,在返回地址时则会向后偏移4个字节,而在delete时则会查看内存上对象个数,从而根据个数count确定调用几次析构函数,从而完全清理所有对象占用内存。

对于内置类型若new[]但用delete释放时,没有影响,对于底层实现来说malloc()的内存依旧可以free()释放,但若是自定义类型如类时,释放使用 delete时,这时则会只调用一次析构函数,只析构了一个对象,剩下的对象都没有被清理。

malloc/free、new/delete的区别

在这里插入图片描述

  1. 分配内存的位置:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区是否能够是堆(问题等价于new是否能在堆上动态分配内存),这取决于operator new 的实现细节。自由存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。
  2. new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。类型安全的代码不会试图访问自己没被授权的内存区域。
  3. new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL,可以使用异常机制;malloc分配内存失败时返回NULL。
  4. 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
  5. new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。
  6. new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。至于malloc,它并知道你在这块内存上要放的数组还是啥别的东西,反正它就给你一块原始的内存,在给你个内存的地址就完事。
  7. 由图还可以看出new/delete底层是基于malloc/free来实现的,而malloc/free不能基于new/delete实现;
  8. opeartor new /operator delete可以被重载。标准库是定义了operator new函数和operator delete函数的8个重载版本:以决定我们的new与delete如何为对象分配内存,如何回收对象。而malloc/free并不允许重载。

(理由:malloc/free属于C语言标准库函数,C语言中不支持函数的重载,因为C++在底层运行这些函数时,会重新给这些函数起一个包含其参数列表的名字(不同平台命名规则不同),这样一来程序在编译时,根据重载的条件, 形参列表必须不同,底层就会给每个表面上看似同名的函数起一个独一无二的名字,这也就意味着他们变成了不同名的函数,因而也就可以同时运行。而反观C语言环境下,底层重新命名时仅仅是在原来的名字前加了一个下划线(-),因此运行时这些函数时他们依然同名,也就无法达到重载的效果。

  1. 使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。new没有这样直观的配套设施来扩充内存。
  2. operator new 无法分配足够内存时会先调用一个用户指定的错误处理函数,对于malloc,客户并不能够去编程决定内存不足以分配时要干什么事,只能看着malloc返回NULL。

扩展:重载和重写区别

重载(overload): 指函数名相同,但是它的参数表列个数或顺序,
类型不同。 但是不能靠返回类型来判断!

重写(override): 有些书翻译成重定义。它是函数原型一模一样,
但是其函数体不同,也就是它实现不同的功能。

12.linux–top命令的使用

以下命令可以用于获取本机cpu使用率的是:
在这里插入图片描述
详情见linux常用命令总结(一)第九个知识点

13. 数据结构–查找

关于查找,下列说法正确的是____。
在这里插入图片描述

自平衡树

红黑树

14.linux–awk命令

命令:awk ‘BEGIN{OFMT=“%.3f”;print 2/3,int(3.1415926);}’ 的执行结果为( )
答案:
0.667 3

15.类成员默认情况下是什么类型?

在这里插入图片描述
c++中类成员默认是private类型,struct中成员默认是public类型。

16.指针作为函数参数

指针可以作为参数在函数中进行传递,以下程序输出结果为:

#include<iostream>
using namespace std;
void swap(int *a,int *b)
{
  int temp=*a;
  *a=*b;
  *b=temp;
}
int main(void)
{
  int a=1,b=2;
  swap(&a,&b);
  cout<<a<<" "<<b<<endl;
  system("pause");
  return 0;
}

答案:2 1

17. 应用层协议

以下哪些协议工作在应用层?
在这里插入图片描述

18.

已知int占4个字节,unsigned char 占1个字节。

int array[2019] = { 0 }; array[19] = 2019;

unsigned long offset = (unsigned long)((short *)array + 2019) - (unsigned long)(array + *(unsigned char *)(array + 19));

问offset的值是____。
答案:
3130

19.判断输出题

NumberList是一个顺序容器,以下代码执行后,NumberList里的元素依次为()

List<int> NumberList = new List<int>(){2,4,1,3,5};
for(int i = 0;i<NumberList.Count;++i)
{
    int v = NumberList[i];
    if(v%2 == 0)
    {
        NumberList.Remove(v);//删除的是元素,而非下标
    }
}

答案:4,1,3,5

20.变量命名规则

在程序设计中,变量的命名通常符合一定的规则。以下变量命名符合一般规则的是:( )
在这里插入图片描述

21. 十个箱子中找出一个次品问题

有十箱零件,每箱含有零件若干。其中一箱规格生产错了,正常零件每件是10g,出错的零件每件是9g。现有电子称一台,请问最少称量几次一定可以找出不合格的那箱零件?
在这里插入图片描述
认为答案出错了
12个乒乓球称重3次寻找次品的计算题,可真是难为我了
20个乒乓球中有一个是次品,次品比正品轻一点,用天平称,最少几次就能找出来?

22.哈夫曼树

一棵哈夫曼树有5个叶子节点,则该哈夫曼树共有()个结点?
答案:9个

23.红黑树

下列红黑树的说法,错误的是:

  1. 红黑树的时间复杂度为:O(n*lgn)。(√)
  2. 每个红色结点的两个子结点一定都是黑色。
  3. 根节点是黑色,每个节点是黑色或者红色。
  4. 每个叶子节点是黑色的。

24.联合体的内存对齐

下列联合体的sizeof(sampleUnion)的值为多少:

union{

    char flag[3];

    short value;

} sampleUnion;

答案:4

25.指针长度

char *str = “123abc”;求sizeof(str),sizeof(*str),strlen(str)的值依次是
答案:
4 1 6

26.linux–export设置环境变量

以下命令用于设置环境变量的是:
1.env 2.export (√) 3.echo 4.cat

27.排序算法的时间复杂度

下列排序算法的时间复杂度的说法,错误的是:
在这里插入图片描述
在这里插入图片描述

28. 索引失效的情况

数据库创建索引之后,查询效率会有很大提升。不过,某些情况下索引不起作用。下列哪些情况下,数据库创建的索引不起作用:
在这里插入图片描述

29. 脚本加密

执行命令./shc -f test.sh对test.sh脚本加密会生成哪些文件( )
在这里插入图片描述

30.sizeof(struct)

#include <stdio.h>
struct A{
 char a;
 int b;
 short c;
 double e;
};
struct B{
 char a;
 short b;
 int c;
 float e;
};
int main(int argc, char *argv[])
{
 printf("%d,%d", sizeof(struct A), sizeof(struct B));
 return 1;
}

在64位操作系统中,以上程序输出的结果,正确的是()?
答案:24,12

涉及struct结构体的内存对齐,具体知识看京东C++开发工程师 2019校招卷总结第28题

参考

【1】静态函数定义的变量是静态的吗?
【2】C语言中const定义常量和宏常量的区别
【3】值为NULL的对象指针
【4】Linux sed 命令
【5】Linux sed命令完全攻略(超级详细)
【6】new 等于 malloc加构造函数
【7】new/delete与malloc/free的区别与联系详解
【8】new与malloc的10点区别

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值