能够操作内存中数据类型的是?

  • a、修饰全局变量:表明一个全局变量只对定义在同一文件中的函数可见。
    b、修饰局部变量:表明该变量的值不会因为函数终止而丢失。
    c、修饰函数:表明该函数只在同一文件中调用。
    d、修饰类的数据成员:表明对该类所有对象这个数据成员都只有一个实例。即该实例归所有对象共有。
    e、修饰类的成员函数:这意味着一个静态成员函数只能访问它的参数、类的静态数据成员和全局变量。
    2)静态成员函数与非静态成员函数的区别
    静态成员函数只属于类本身,随着类的加载而存在,不属于任何对象,是独立存在的。静态成员函数不存在this指针,不能访问非静态成员变量。静态变量和函数必须在类内声明,在类外初始化。
    3)静态变量和函数的优点
    a、实现共享:因为静态成员函数和静态成员变量属于类,不属于类的实体,这样可以被多个对象所共享
    b、静态成员函数主要为了调用方便,不需要生成对象就能调用。
    4)为什么静态成员函数不能申明为const
    const修饰符用于表示函数不能修改成员变量的值,该函数必须是含有this指针的类成员函数

  • b、修饰指针 指针常量和常量指针
    常量指针表示常量(指针内容)不可变,指针常量表示指针(指针地址)不可变
    ①、指针常量:指针类型的常量(int *const p)
    指针类型的常量,必须初始化,一旦初始化后指针的地址不能改变
    ②、常量指针:指向常量的指针(int const *p)
    所谓指向常量的指针仅仅要求不能通过该指针改变对象的值,但是对象的值可以通过其它途径进行改变。
    写在参数中,修饰参数中的形参、指针和引用,防止修改
    写在开头,修饰返回值变量或指针
    const修饰类的成员常量,不能被修改,同时它只能在初始化列表中赋值。
    写在成员函数后,不改变对象的成员变量,只能调用常量成员函数,不能调用类中任何非const成员函数,能够访问对象的const成员,而其他成员函数不可以。非常量成员函数既可以调用常量成员函数也可以调用非常量成员函数
    f、修饰类对象、类指针、类引用
    const类对象/指针/引用,表示该对象为常量对象,只能调用类的const成员函数,类其中的任何成员都不能被修改。非常量类对象既可以调用常量成员函数,也可以调用非常量成员函数
    2)常量函数成员为什么无法调用非常量数据成员 关于类的常量成员函数和非常量成员函数之间的可调用关系
    底层 const的 this指针,无法传参拷贝给非底层 const的指针对象
    define定义的只是个常数不带类型,const定义的常数是变量也带类型。
    define是在编译的预处理阶段起作用,而const是在编译运行的时候起作用。
    define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的。
    define占用代码段空间,const占用数据段空间
    define是不能进行调试的,因为在预编译阶段就已经替换掉了,const常量可以进行调试的。
    define可以通过#undef取消某个符号的定义,再重新定义,const不能重定义。
    define可以防止头文件重复引用,const不行

  • 假设有读、写两条语句,依次对同一个 volatile 变量进行操作,那么后一条的读操作不会直接使用前一条的写操作对应的 volatile 变量的寄存器内容,而是重新从内存中读取该 volatile 变量的值。
    在 C/C++ 语言中,volatile 的第二个特性是“不可优化性”。volatile 会告诉编译器,不要对 volatile 声明的变量进行各种激进的优化(甚至将变量直接消除),从而保证程序员写在代码中的指令一定会被执行。
    能够保证 volatile 变量间的顺序性,不会被编译器进行乱序优化。

  • mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。
    在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

  • 关键字final:C++如何防止一个类被继承 如何防止一个类被继承、 C++ final关键字
    私有构造函数类的友元函数,该友元函数类虚拟继承自私有构造函数类,该类可以实例化,但无法被继承,继承该类的类无法调用构造函数而实例化失败

  • class这个关键字还可用于定义模板参数,就像typename。但是strcut不用与定义模板参数

  • 关键字inline 内联函数 —— C 中关键字 inline 用法解析、面试—内联函数和宏定义的区别、关于c内联函数不能有循环递归
    在系统下栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足所造成的程式出错的问题。为了解决这个问题,特别的引入了inline修饰符,表示为内联函数。将递归部分替换为程序代码
    2)内联函数与宏的区别
    内联函数在运行时可调试,而宏定义不可以;
    编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会;
    内联函数可以访问类的成员变量,宏定义则不能;
    在类中声明同时定义的成员函数,自动转化为内联函数。
    3)内联函数可以递归吗?
    不能递归。不是内联函数中不能有循环和递归语句,而是当内联函数中出现了复杂的逻辑控制语句后,编译器会不再认为它是一个内联函数。

  • 用来保存指针的对象,就是指针对象。定义指针变量时,在变量名前写一个 * 星号,这个变量就变成了对应变量类型的指针变量。指针变量可以指向变量、结构体、类、数组、函数
    对于结构体和类,两者的差别很小,所以几乎可以等同,则使用->符号访问内部成员
    3)野指针 C++中的空指针和野指针、C++空指针调用成员函数
    a、未经初始化的指针是个野指针,所以在定义指针变量的时候一定要进行初始化。如果实在是不知道指针的指向,则使用nullptr或NULL进行赋值。
    b、free和delete后指针没有设置为NULL,让人误以为这是合法的指针
    c、指针访问越界,访问了一个不该访问的内存
    4)指针赋值(浅拷贝)
    指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。
    将递增递减操作符用于指针时,将把指针的值增加其指向的数据类型占用的字节数
    一种特殊的指针类型,可用于存放任意对象的地址,但是丢失了类型信息。如果想要完整的提取指向的数据,程序员就必须对这个指针做出正确的类型转换,然后再解指针。因为,编译器不允许直接对void*类型的指针做解指针操作(提示非法的间接寻址)。常用于输入输出。
    8)值传递和指针传递 C/C++语言中值传递、指针传递和引用传递、为什么传递类类型参数时尽量用引用传递
    a、无法回传:实参传递给形参,是按值传递的,被调函数无法修改传递的参数达到回传的效果。传递变量的指针可以轻松解决上述问题。
    b、传递类:有时我们会传递类或者结构体对象,而类或者结构体占用的内存有时会比较大,通过值传递的方式会拷贝完整的数据,降低程序的效率。而指针只是固定大小的空间,效率比较高。当然如果你用C++,使用引用效率比指针更高。所以C++中,传递类或结构时,引用>指针>值传递
    9)函数指针和指针函数 函数指针和指针函数用法和区别
    ①、原理:函数指针本质是一个指针,其指向一个函数。
    每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区。既然是存放在内存中,那么函数也是有自己的指针的。函数名单独进行使用时就是这个函数的指针。
    ①、原理:指针函数本质是一个函数,其返回值为指针。
    这里唯一需要注意的是不要把非静态局部变量的地址返回。我们知道局部变量是在栈中的,由系统创建和销毁,返回之后的地址有可能有效也有可能无效,这样会造成bug。可以返回全局变量、静态的局部变量、动态内存等的地址返回。

  • 指针和引用的区别 C++中引用和指针的区别、引用与指针有什么区别?
    程序为指针变量分配内存区域,而不为引用分配内存区域。
    指针使用时要在前加 * ,引用可以直接使用。
    引用在定义时就被初始化,之后无法改变;指针可以发生改变。 即引用的对象不能改变,指针的对象可以改变。
    没有空引用,但有空指针。这使得使用引用的代码效率比使用指针的更高。因为在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。
    对引用使用“sizeof”得到的是变量的大小,对指针使用“sizeof”得到的是变量的地址的大小。
    6)多级引用和多级指针
    理论上指针的级数没有限制,但引用只有一级。即不存在引用的引用,但可以有指针的指针。
    ++引用与++指针的效果不一样。
    例如就++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。

  • 类型转换 C++四种强制类型转换
    这应该四种中是最常见的,但没有运行时类型检查来保证转换的安全性。
    进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的
    a、其他三种都是编译时完成的,dynamic_cast 是运行时处理的,运行时要进行类型检查
    b、不能用于内置的基本数据类型的强制转换
    c、dynamic_cast 要求 内所描述的目标类型必须为指针或引用。dynamic_cast 转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回 nullptr
    d、在类的转换时,在类层次间进行上行转换(子类指针指向父类指针)时,dynamic_cast 和 static_cast 的效果是一样的。在进行下行转换(父类指针转化为子类指针)时,dynamic_cast 具有类型检查的功能比 static_cast 进行转换的,基类中一定要有虚函数,否则编译不通过(类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义)。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表
    用于去掉const属性,目标类型只能是指针或者引用
    reinterpret_cast是简单的二进制拷贝,用于任何指针向任何指针的转换,可以用于将指针类型和整型类型相互转换,但是不可用于浮点和整型之间的转换,也不可以用于枚举和整型的转换,他不进行类型检查,是四种转换中最危险的,需要谨慎使用。
    a、改变指针或引用的类型
    b、将指针或引用转换为一个足够长度的整形
    c、将整型转换为指针或引用类型。

  • 内存分区 C/C++程序内存的分配、C++内存管理(面试版)
    从下往上,从低地址往高地址依次为:
    1)代码区(.text):主要是用来存储代码的区域,也就是计算机所要执行的指令,如上述例子中的所有代码。
    2)静态数据区和已初始化全局区(.data):存储静态变量和已经初始化的全局变量,如int y = 15;。
    3)未初始化全局区(.bss):用来存储为未初始化的全局变量,如int x;。
    5)进程间的文件共享区域:使用mmap映射的一块内存用于进程间的文件共享。
    6)栈(.stack):用来存储局部变量,比如函数参数或者等等,在执行完后会释放这部分内存。

  • 内存池 一文看懂内存池原理及创建(C++实现)、揭秘——STL空间配置器

  • 堆和栈的区别 堆与栈的区别、C++为什么栈比堆快
    栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏
    每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;
    堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低
    堆都是动态分配的,没有静态分配的堆栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放。
    栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。所以栈比堆快。
    栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,一般情况下是按照从右向左的顺序入栈,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

  • 内存泄漏 C++中内存泄漏的几种情况
    没有匹配的调用new和delete函数
    释放对象数组时在delete中没有使用方括号
    3)没有将基类的析构函数定义为虚函数
    当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露
    两次释放相同的内存是一种错误的做法,同时可能会造成堆的奔溃。按值传递会调用(拷贝)构造函数,引用传递不会调用。

  • 内存对齐的长度取决于三个值:系统默认值(64位下位8字节,32位下位4字节),最大数据成员长度,pragma pack指定长度。
    大于系统默认值时=min(最大数据成员长度,指定长度),小于系统默认值时=min(系统默认值,指定长度)
    不是所有的硬件平台(特别是嵌入式系统中使用的低端处理器)都能访问任意地址上的任意数据,某些硬件平台只能访问对齐的地址,否则会出现硬件异常。
    如果数据存放在未对齐的内存空间中,则处理器访问变量时需要进行两次内存访问才能完整读取该变量的值,而对齐的内存访问仅需一次访问
    3)如何压缩 struct,不会产生内存对齐?

  • new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持。
    使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸
    new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void *** ,需要通过强制类型转换将void*指针转换成我们需要的类型。
    new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后
    调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。
    malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
    new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。

  • 面向对象 c++面向对象的三个特点
    封装、继承、多态。其中,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用

  • 类的访问权限 C++三种继承方式下的访问权限控制

  • 类的内存模型、成员函数、数据成员和类大小 类的成员函数和数据成员分别存在哪里,类大小的计算、【C++】类中成员函数的存储方式以及计算类的大小
    类的成员函数和非成员函数代码存放在代码区,数据成员分为静态变量和非静态变量,静态变量在类定义的时候,就分配好了,存放在数据区,然后非静态变量时在构造对象的时候,存放在堆栈中。
    每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间。
    所有对象有着各自的数据成员,但调用公共的函数代码段
    成员函数存在一个隐藏变量是什么?this指针
    类为什么只能直接调用静态类成员函数,而非静态类成员函数只有类对象才能调用呢?不同的对象使用的是同一个函数代码段,它怎么能够分别对不同对象中的数据进行操作呢
    原因是类的非静态类成员函数其实都内含了一个指向类对象的指针型参数(即this指针),因而只有类对象才能调用(此时this指针有实值),调用非静态成员函数和数据成员需要通过this指针
    类中包括成员变量和成员函数。new出来的只是成员变量,成员函数始终存在,所以如果成员函数未使用任何成员变量的话,不管是不是static的,都能正常工作。 即空的对象指针能直接调用该成员函数而不崩溃:A a=NULL,a->func();
    6)如何禁止类实例化时候的动态分配方式?如何建立一个只在栈或者堆上生成的类? 面试题:实现一个只能在堆上(栈上)生成对象的类
    a、实现一个只能在堆上生成对象的类
    编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。
    b、实现一个只能在栈上生成对象的类
    重载new和delete的函数设置为私有即可

  • 1)构造函数可以抛异常吗?构造函数中抛异常
    2)析构函数可以抛异常吗?不能在析构函数里面抛出异常
    不可以,因为函数发生了异常而导致函数的局部变量的析构函数被调用,析构函数又抛出异常,本来局部对象抛出的异常应该是由它所在的函数负责捕获的,现在函数既然已经发生了异常,必定不能捕获
    3)能否在有参构造函数中调用无参构造函数?无参构造函数修改类成员是否对正在构造的类产生影响?优缺点?面试总结—2、C++中构造函数调用构造函数
    不能在构造函数体中调用自己,会出现无限递归调用。默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时对象,将这个匿名临时对象初始化自己的数据成员,但是原对象的数据成员并没有得到初始化,因此其值也是不确定的
    4)实例派生类构造和析构顺序 基类、派生类、派生类成员变量的构造和析构顺序
    a、执行基类的构造函数;
    b、初始化派生类的成员变量,由于B是一个类类型,所以会调用B的默认构造函数,此时如果B没有默认构造函数会报错;
    c、执行派生类的构造函数。
    d、析构与构造顺序相反
    5)空类包含哪些函数 C++中一个空类含有哪些默认的成员函数
    默认构造函数、析构函数、拷贝构造函数、赋值运算符(等号:operator=)、取址运算符(operator&)

  • 拷贝构造函数,深拷贝和浅拷贝 C++拷贝构造函数详解 、C++浅拷贝和深拷贝的区别
    拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。
    a、对象以值传递的方式传入函数参数
    b、对象以值传递的方式从函数返回
    c、对象需要通过另外一个对象进行初始化
    3)类的浅拷贝和深拷贝
    浅拷贝没有处理静态数据成员和堆上的指针,只对对象中的数据成员进行简单的赋值
    深拷贝对于对象中动态成员,就不是仅仅简单地赋值了,而是重新动态分配空间
    对象的复制大多在进行值传递时发生,声明一个私有拷贝构造函数可以防止按值传递。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。
    5)拷贝构造的参数能不能是值传递 拷贝构造函数为什么不能用值传递
    不能。因为对象值传递的时候调用拷贝构造函数,所以拷贝构造的的参数为值传递会循环调用拷贝构造,导致死循环。

  • 模板 C++重要知识清单:泛型编程(函数模板和类模板机制)包含模板机制的底层实现原理、C++模板编译、006模板的编译机制_对模板进行两次编译
    C++提供两种模板机制:函数模板、类模板
    template ,template 告诉C++编译器我们要开始泛型编程了,看到T不要报错,它指得是一种数据类型
    函数模板可以像普通函数一样被重载,C++编译器优先考虑普通函数,如果函数模板可以产生更好的匹配,则选择函数模板,可以通过空模板实参列表的语法限定编译器只通过模板匹配。
    a、编译器并不是把函数模板处理成能够处理任何类型的函数,编译器从函数模板通过具体类型产生不同的函数
    b、编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译;在调用的地方对参数进行替换后的代码进行编译,其实就是C++编译器帮程序员根据函数模板生成了需要参数类型的函数原型
    3)模板函数声明和定义为什么要放在一起
    关于C++模板函数声明与定义的问题、为什么C++编译器不能支持对模板的分离式编译

  • 多态、静态绑定和动态绑定 C++多态、C++的动态绑定和静态绑定
    1)静态多态(静态绑定)
    静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数
    在同一个作用域下,函数名相同,函数的参数不同。
    使用泛型来定义函数,其中泛型可用具体的类型(int 、double等)替换。通过将类型作为参数,传递给模板
    2)动态多态(动态绑定)
    即运行时的多态,在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。
    3)不用指针和引用赋值会不会引发动态绑定 为什么要使用父类指针和引用实现多态,而不能使用对象?
    不会。参数如果不是指针或者引用,会进行拷贝传参。子类对象赋值给父类对象,把子类中包含的父类成员变量的值拷贝过去,但是子类的虚表不会给拷贝过去(虚表是指针),则函数中这个父类对象的虚表是父类的,所以无法实现多态。而指针或者引用是直接指向子类对象,不会进行拷贝赋值,这样虚函数表是子类的虚函数表,故能实现多态。

  • 重载、重定义和重写C++重载、重定义、重写的区别、C++重载操作符(operator)介绍
    在同一个作用域下,函数名相同,函数的参数不同,函数返回值可能不同
    a、在不同的作用域下(这里不同的作用域指一个在子类,一个在父类 ),函数名相同的两个函数构成重定义
    b、当两个函数构成重定义时,父类的同名函数会被隐藏,当用子类的对象调用同名的函数时,如果不指定类作用符,就只会调用子类的同名函数。
    在不同的作用域下(一个在父类,一个在子类),函数的函数名、参数、返回值完全相同,父类必须含有virtual关键字
    带virtual关键字的就是虚函数,只有重写了虚函数才算实现了多态。

  • 1)虚函数怎么实现的 C++虚函数表剖析
    虚函数表和虚函数表指针
    2)纯虚函数 C++纯虚函数和抽象类
    将函数定义为纯虚函数,则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。
    3)构造函数中能否调用虚函数 构造函数中是否可以调用虚函数
    a、从语法上讲,调用完全没有问题。
    b、派生类对象构造期间进入基类的构造函数时,对象类型变成了基类类型,而不是派生类类型。 同样,进入基类析构函数时,对象也是基类类型。 所以,虚函数始终仅仅调用基类的虚函数(如果是基类调用虚函数),不能达到多态的效果,所以放在构造函数中是没有意义的,而且往往不能达到本来想要的效果。
    4)基类的析构函数为什么是虚函数 C++基类析构函数为什么要定义为虚函数
    基类指针指向派生类的时候,若基类析构函数不声明为虚函数,在析构时,只会调用基类而不会调用派生类的析构函数,从而导致内存泄露

  • C++11常用新特性快速一览
    关于C++14:你需要知道的新特性
    返回类型推导auto、泛型lambda(参数可用auto)、lambda捕获值可初始化、二进制常量和单引号用作数字分位符
    泛型模板(参数可用auto)、std:variant代替多元组tuple、结构化绑定(使用auto推导多类型返回值tuple)、if和switch中可以像for语句中声明
    C++20新特性个人总结

  • 临时对象被使用完之后会被立即析构,在析构函数中free掉申请的内存资源。 如果能够直接使用临时对象已经申请的资源,并在其析构函数中取消对资源的释放,这样既能节省资源,有能节省资源申请和释放的时间。
    通过加入定义转移构造函数(&&)和转移赋值操作符重载来实现右值引用
    准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
    在泛型函数中,必须为每一个参数必须重载两种类型,T& 和 const T&以满足所有类型。而右值引用能够将所有的参数类型原封不动的传递给目标函数。

  • lamda表达式可以递归调用吗 C++lambda递归的三种写法

  • 智能指针 C++ STL 四种智能指针
    智能指针主要解决忘记delete、拷贝构造或复制带来的问题,所有智能指针都未采用深拷贝,由于开销太大。
    缺点:auto_ptr 有拷贝语义,拷贝后原对象无效,再次访问原对象会导致程序崩溃,并且过期时会删除两次。
    使用场景:任何情况下都不应该使用 auto_ptr。
    a、unique_ptr 比 auto_ptr 更加安全,因为 unique_ptr 则禁止了拷贝构造函数和赋值运算符,但提供了移动语义,即可以使用 std::move() 进行控制权限的转移。使用auto_ptr赋值编译成功,运行报错;unique_ptr编译失败。
    b、如果 unique_ptr 是个临时右值,编译器允许拷贝语义。如函数返回值为unique_ptr,还没机会访问就析构
    d、可以管理数组成员,使用delete[]析构
    e、可以自定义析构函数
    使用场景:如果程序不需要多个指向同一个对象的指针,则可使用 unique_ptr。
    shared_ptr使用引用计数机制,允许多个指针指向同一个对象
    拷贝构造时增加现有计数,赋值操作符时减少原有计数,增加现有计数
    使用场景:多个指向同一对象的指针,或将指针作为参数或者函数的返回值进行传递,应选择 shared_ptr
    使用场景:解决 shared_ptr 的两个对象互相引用导致的循环引用问题,将对方声明为weak_ptr即可自动析构
    a、当创建智能指针类的新对象时,初始化指针,并将引用计数设置为1;
    b、当能智能指针类对象作为另一个对象的副本时,拷贝构造函数复制副本的指向辅助类对象的指针,并增加辅助类对象对基础类对象的引用计数(加1);
    c、使用赋值操作符对一个智能指针类对象进行赋值时,处理复杂一点:先使左操作数的引用计数减 1(为何减 1:因为指针已经指向别的地方),如果减1后引用计数为 0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(为何增加:因为此时做操作数指向对象即右操作数指向对象);
    d、完成析构函数:调用析构函数时,析构函数先使引用计数减 1,如果减至 0 则 delete 对象。

  • shared_ptr的引用计数是线程安全的,在手段上使用了atomic原子操作
    shared_ptr对象所管理的资源存放在堆上,它可以由多个shared_ptr所访问,所以这也是一个临界资源。因此当多个线程访问它时,会出现线程安全的问题。
    shared_ptr对象有两个变量,一个是指向的对象的指针,还有一个就是我们上面看到的引用计数, 当shared_ptr发生拷贝的时候,是先拷贝智能指针,然后再拷贝引用计数,也就是说,shared_ptr的拷贝并不是一个原子操作。
    ①、加锁:当我们多个线程访问同一个shared_ptr时,应该要进行加锁操作
    ②、使用侵入式智能指针:因为不涉及引用计数的拷贝,对引用计数的增减是原子的,只用拷贝对象指针,所以是线程安全的。

  • 侵入式智能指针模板类 C++侵入式智能指针的实现
    一个资源对象无论被多少个侵入式智能指针包含,从始至终只有一个引用计数变量,不需要在每一个使用智能指针对象的地方都new一个计数对象,这样子效率比较高,使用内存也比较少,也比较安全
    因为引用计数存储在对象本身,所以在函数调用的时候可以直接传递资源对象地址,而不用传递智能指针
    非侵入式智能指针对象的拷贝,必须带着智能指针模板,否则就会出现对象引用计数丢失
    将引用计数变量从资源类中抽离出来,封装成一个基类,该基类包含了引用计数变量。如果一个类想使用智能指针,则只需要继承自该基类即可;
    引用计数的基类,设计成模板类,接受引用计数类型作为参数,比如使用int类型或者原子计数类型作为引用计数变量。默认情况下应该使用原子计数类型作为引用计数变量。
    引用计数基类的构造函数、拷贝构造函数、析构函数应为protected,即该类只能通过继承关系被使用。
    拷贝构造函数并不拷贝引用计数基类的数据成员,而是重新将原子计数_atomic置为0——因为每个对象都有一个自己的引用计数,当发生对象拷贝构造时,新的对象的计数应该置为0,而不应该拷贝旧对象的计数。
    赋值操作operator=,比如A=B,同上面一样,只对资源类的成员进行拷贝,而不拷贝其引用计数基类的数据成员。也就是说,将B的值赋给A,A的引用计数应该保持不变,而不能将B的引用计数拷贝过来——这是对象的拷贝,而不是智能指针的拷贝。

  • 正常的shared_ptr只能传递智能指针模板类,该机制提供了一个传递对象的能力,并且两个智能指针
    对象需继承std::enable_shared_from_this该基类,并且使用shared_from_this()返回一个新的共用对象,两个智能指针共享该对象的所有权,并且引用计数都相同
    并不是侵入式智能指针类,引用计数并非保存在对象中,仍然保存在智能指针类中

  • std::atomic的每个实例化和完全特化表示一种类型,不同的线程可以同时操作(该类型实例),而不会引发未定义的行为,该类重载了常用的运算符,并且包括特殊的运算函数
    使用互斥锁大约2000ms,使用原子操作大约10ms,大大提升程序运行效率
    4)底层原理 atomic的底层实现
    原子操作是由底层硬件支持的一种特性,在汇编语言中加入一个lock前缀,方法包括锁bus和锁cache

  • 原子内存顺序 C++11的原子量与内存序浅析、C++ 并行编程之原子操作的内存顺序

  • NULL在C++中就是0,这是因为在C++中void* 类型是不允许隐式转换成其他类型的,所以之前C++中用0来代表空指针,但是在重载整形的情况下,NULL会被当成int型的0而不是void*。所以,C++11加入了nullptr,可以保证在任何情况下都代表空指针,而不会出现上述的情况

  • STL六大组件 C++_STL六大组件详解、仿函数 ( 函数对象 ) 详解、STL之仿函数实现详解、C++迭代器 iterator详解
    a、序列式容器:向量(vector)、双端队列(deque)、列表(list)
    b、关联式容器:集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)
    用来在容器的元素上遍历
    a、为所有容器提供了一组很小的公共接口
    b、迭代器是一种智能指针,智能指针定义为存储指向动态分配对象指针的类,迭代器封装了指针的同时,还对指针的一些基本操作如*、->、++、==、!=、=进行了重载,使其具有了遍历复杂数据结构的能力
    c、迭代器失效的情况? 迭代器失效的几种情况总结
    该数据结构的元素是分配在连续的内存中,insert和erase操作,都会使得删除点和插入点之后的元素挪位置,所以,插入点和删除点之后的迭代器全部失效,也就是说insert(*iter)(或erase(*iter)),然后在iter++,是没有意义的。解决方法:erase(*iter)的返回值是下一个有效迭代器的值。 iter 对于关联容器(如map, set,multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。
    用来处理群集内的元素。它们可以出于不同的目的而搜寻、排序、修改、使用那些元素。通过迭代器的协助,我们可以只需编写一次算法,就可以将它应用于任意容器,这是因为所有的容器迭代器都提供一致的接口。
    适配器是一种类,为已有的类提供新的接口,目的是简化、约束、使之安全、隐藏或者改变被修改类提供的服务集合
    b、C++中定义了3种容器适配器,它们让容器提供的接口变成了我们常用的的3种数据结构:栈stack,队列queue和优先队列priority_queue。默认情况下,栈和队列都是基于deque实现的,而优先级队列则是基于vector实现的。
    a、负责空间配置与管理。从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template。
    b、默认的allocator是一个由两级分配器构成的内存管理器,当申请的内存大小大于128byte时,就启动第一级分配器通过malloc/free直接向系统的堆空间分配,如果申请的内存大小小于128byte时,就启动第二级分配器,从一个预先分配好的内存池中取一块内存交付给用户,这个内存池由16个不同大小(8的倍数,8~128byte)的空闲列表组成,allocator会根据申请内存的大小(将这个大小round up成8的倍数)从对应的空闲块列表取表头块给用户。
    ②、避免了内存碎片的生成
    一个行为类似函数的类对象,它可以没有参数,也可以带有若干参数,任何重载了调用运算符operator()的类的对象都满足函数对象的特征,函数对象可以把它称之为smart function。

  • a、vector为存储的对象分配一块连续的地址空间 ,随机访问效率很高。但是插入和删除需要移动大量的数据,效率较低。尤其当vector中存储的对象较大,或者构造函数复杂,则在对现有的元素进行拷贝的时候会执行拷贝构造函数
    b、list中的对象是离散的,随机访问需要遍历整个链表, 访问效率比vector低。但是在list中插入元素,尤其在首尾插入,效率很高,只需要改变元素的指针
    2)C中数组越界怎么解决?给数组扩容的几种方式
    a、创建一个扩容的临时数组,然后赋值给原数组,使用循环遍历方式
    b、创建一个扩容的临时数组,然后赋值给原数组,使用Array的静态方法
    3)在插入多查询少时使用哪种数据结构?
    4)有序链表如何查找某个元素?
    链表:顺序查找O(N)、建立跳跃表查找O(logN)
    关于vector简单的讲就是一个动态增长的数组,里面有一个指针指向一片连续的内存空间,当空间装不下的时候会自动申请一片更大的空间(空间配置器)将原来的数据拷贝到新的空间,然后就会释放旧的空间。当删除的时候空间并不会被释放只是清空了里面的数据。
    a、reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
    b、resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
    c、参数不同:reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素
    7)双端数组deque的底层实现?STL源码剖析——deque的实现原理和使用方法详解
    deque采用一块map作为主控,map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。为了维持整体连续的假象,deque的设计及迭代器前进后退等操作都颇为繁琐。
    8)数组vector和双端数组deque插入删除效率?关于C++中vector和deque的使用效率测试记录
    vector的优势是对中间的操作速度快,deque优势是对两端的操作速度快
    数组下标、迭代器、范围for、foreach方法、at方法

  • 哈夫曼树和哈夫曼编码 最全哈夫曼树哈夫曼编码讲解,兄弟你值得拥有
    哈夫曼树(Huffman Tree)是在叶子结点和权重确定的情况下,带权路径长度最小的二叉树,也被称为最优二叉树。
    用于压缩编码,把左分支权值改为0,右分支权值改为1,按照路径重新给每个子节点分配编码
    3)什么树要么没有节点,要么只有俩节点?

  • 字典树或trie树 从Trie树(字典树)谈到后缀树(10.28修订)、剑指Offer——Trie树(字典树)、搜索引擎关键字智能提示的一种实现
    Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。
    a、根节点不包含字符,除根节点外每一个节点都只包含一个字符。
    b、从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
    c、每个节点的所有子节点包含的字符都不相同。
    最大限度地减少无谓的字符串比较,查询效率比哈希表高。 Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
    是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
    Trie树的平均高度h为len,所以Trie树的查询复杂度为O(h)=O(len),总的复杂度为O(n*len),

  • 红黑树和map 红黑树动画在线演示、教你初步了解红黑树、浅析红黑树(RBTree)原理及实现、浅谈AVL树,红黑树,B树,B+树原理及应用
    STL的map中所有操作的复杂度? 二叉查找树与红黑树概念性质及操作时间复杂度
    等于红黑树的所有操作复杂度,都是O(lgn)
    在插入和查询差不多的情况下选择哪种数据结构?红黑树
    红黑树和哈希表比较 哈希表和红黑树的对比
    HashMap用红黑树而非B+树原因? 为什么HashMap使用红黑树而不是AVL树或者B+树

  • 哈希表和unorderedmap 哈希表(散列表)原理详解
    1)哈希冲突 哈希表冲突及处理冲突的方法
    a、开放定址法(再散列法)
    ①、线性探测再散列:顺序往下查找
    ②、二次探测再散列:在表的左右查找
    ③、伪随机探测再散列:设置一个固定的随机数列,每次冲突都按该数列查找
    b、再哈希法同时构造多个不同的哈希函数,
    优点:这种方法不易产生聚集
    将所有哈希地址为i的元素构成一个称为同义词链的单链表,大于8转为红黑树存储
    凡是和基本表发生冲突的元素,一律填入溢出表
    2)如何改善Hash表性能?哈希扩容 【数据结构之哈希表(二)】 哈希表的扩容实现机制
    a、原理:当表的实际装载因子达到默认的负载因子值(负载极限)时,就会触发哈希表的扩容。
    b、Java中的哈希扩容:
    每次扩容时,哈希表的容量增加为原先的两倍。于是在扩容被触发时(实际装载因子达到默认装载因子时),增加一个元素的性能是比较差的,因为要等待原先的表rehash之后才能增加该元素。
    c、Redis中的哈希扩容:渐进式哈希
    在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。
    增加只增加在新哈希表,新插入的键值对会放在链表的头部,而不是在尾部继续插入,头插法的时间复杂度为O(1),并且最新插入的数据往往更可能频繁地被获取
    查找一个key的话,会先在ht[0]里面进行查找,如果没有找到的话,就会继续到ht[1]里面进行查找。
    删除和修改都在两个表进行

  • 八大排序 八大排序算法、快速排序算法——C/C++、堆排序算法(图解详细流程)
    将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
    先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
    在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
    初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n 个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n 个元素中次小(或次大)的元素。
    在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。比较相邻两数发现它们的排序与排序要求相反时,就将它们互换。
    选择一个基准元素,通过一趟排序讲待排序的记录分割成独立的两部分,此时基准元素在其排好序后的正确位置,然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序
    归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
    8)快排和归并的时间复杂度为什么是nlogn? 归并排序的时间复杂度为什么为nlogn
    快排和归并的递归次数都约为nlogn,每一次排序比较约为n,所以时间复杂度是nlogn
    9)对于一个基本有序的数组进行排序用什么最快? 对于一个基本有序的数组进行排序、如何对一个几乎有序的数列进行排序最好
    插入排序、增强冒泡排序(每一轮不从下一个开始,而是从无序的开始)、k+1的最小堆(保证前k+1个有最小值且调整次数少)

  • 排序算法稳定性 排序算法稳定性
    1)稳定的排序算法:冒泡排序、插入排序、归并排序、基数排序
    a、冒泡排序:比较的是相邻元素,将较小或较大的向后移动,可以人为控制相等不交换
    b、插入排序:比较是从有序序列的末尾开 始,可以人为控制把数插在相等的数后面
    c、归并排序:可以人为控制两个数相等时合并不改变顺序
    d、基数排序:按照数字的位数进行排序,可以人为控制相等数的顺序
    2)不稳定的排序算法:堆排序、快速排序、希尔排序、直接选择排序
    a、选择排序:序列5 8 5 2 9, 第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了
    b、快速排序:不稳定发生在中枢元素和a[j] 交换的时刻
    c、堆排序:父子节点调整顺序可能跳过相等的节点
    d、希尔排序:在各自不同步长的序列里交换,可能导致相等的数位置被打乱

  • 快排的优化方法 快速排序的4种优化
    1)随机选取基准值或使用头尾中三数取中选取基准值,提升平均性能
    2)当范围在5-20小范围间选择插入排序,提升算法效率
    3)尾递归优化,将纵向递归调用改为横向迭代循环,减少栈深度避免崩溃
    4)聚集元素,将一次划分后与基准值相同的元素移到基准值附近,提升重复数组排序效率
    5)使用多线程分组快排,再使用归并排序合并

  • sort()底层实现 C++一道深坑面试题:STL里sort算法用的是什么排序算法?
    STL的sort算法,数据量大时采用QuickSort快排算法,分段归并排序。一旦分段后的数据量小于某个门槛(16),为避免QuickSort快排的递归调用带来过大的额外负荷,就改用Insertion Sort插入排序。如果递归层次过深,还会改用HeapSort堆排序

  • 海量数据处理 教你如何迅速秒杀掉:99%的海量数据处理面试题、海量数据处理技巧、面试必须掌握的十个海量数据问题及解决方案、海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)
    1)top-k问题:最大的100个数、出现次数最多的100个数、AB大文件找出重复数据、
    先借助哈希算法,计算每一条数据的hash值,按照hash值将海量数据分布存储到多个桶中,所谓桶,一般可以用小文件实现,每个小文件的大小比内存限制要小。根据hash函数的唯一性,相同的数据一定在同一个桶中。如此,我们再依次处理这些小文件,用最小堆求每个小文件内的top-k,最后用归并排序做多个文件的top-k合并
    若内存能放下所有数据,直接hash_map+堆排
    适用范围:数据量大,重复多,但是数据种类小可以放入内存
    3)位图和布隆过滤器 布隆过滤器究竟是什么,这一篇给讲的明明白白的
    如何找到海量数据出现次数大于2的数?2-Bitmap 位图(bitmap)的理解及应用实例 布隆过滤
    位图适合处理出现大于两次、出现一次=是否重复、出现个数的问题
    集合求交、判断数是否存在大数据集中、数据字典,进行数据的判重,或者集合求交集
    8)蓄水池算法 蓄水池采样算法(Reservoir Sampling)原理,证明和代码、大数据工程师必备之蓄水池抽样算法
    a、题目:给出一个数据流,这个数据流的长度很大或者未知。并且对该数据流中数据只能访问一次。请写出一个随机选择算法,使得数据流中所有数据被选中的概率相等
    b、算法:首先构建一个可容纳 k个元素的数组,将序列的前 k个元素放入数组中。然后对于第 j(j>k)个元素开始,以k/j的概率来决定该元素是否被替换到数组中(数组中的 k个元素被替换的概率是相同的)。当遍历完所有元素之后,数组中剩下的元素即为所需采取的样本。

  • 动态规划 告别动态规划,连刷40道动规算法题,我总结了动规的套路
    第一步骤:定义数组元素的含义,上面说了,我们会用一个数组,来保存历史数组,假设用一维数组 dp[] 吧。这个时候有一个非常非常重要的点,就是规定你这个数组元素的含义,例如你的 dp[i] 是代表什么意思?
    第二步骤:找出数组元素之间的关系式,我觉得动态规划,还是有一点类似于我们高中学习时的归纳法的,当我们要计算 dp[n] 时,是可以利用 dp[n-1],dp[n-2]……dp[1],来推出 dp[n] 的,也就是可以利用历史数据来推出新的元素值,所以我们要找出数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。而这一步,也是最难的一步,后面我会讲几种类型的题来说。
    是不能再分解的了,所以我们必须要能够直接获得 dp[2] 和 dp[1] 的值,而这,就是所谓的初始值。

  • 手撕字符串 经典面试题之手撕字符串函数

  • 如何设计一个长链接压缩成短连接的服务?如何避免冲突,最后能有加密性质,防止短连接被盗用? 如何实现 "长"链接变 “短” 链接?、短链接、短网址使用的是什么算法?

编译原理、设计模式、智力题

  • 编译流程 一个C++源文件从文本到可执行文件经历的过程
    1)预处理(产生.i文件,-E)
    a、将所有**#define删除**,并将宏定义展开
    c、处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。这个过程是递归进行的,因为被包含的文件可能也包含其他文件。
    d、预处理过程还会过滤掉所有注释/**/和//里面的内容,另外还会添加行号和文件名标识,最后会保留#pragma编译器指令,因为编译器需要使用它们。
    2)编译(产生.s文件,-s)
    编译就是将预处理的文件进行一系列的词法分析,语法分析,语义分析,以及优化后产生相应的汇编代码文件
    词法分析,语法分析,语义分析,源代码优化,代码生成和目标代码优化
    3)汇编(产生.o或.obj文件,-c)
    汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程,即生成目标文件
    链接就是把每个源代码独立的编译,然后按照它们的要求将它们组装起来,链接主要解决的是源代码之间的相互依赖问题
    将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,因此对应的链接方式称为静态链接
    动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。

  • 动态库和静态库 windows中静态库lib和动态dll的区别及使用方法
    1)静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中,最终的可执行文件exe会比较大。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件
    2)静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

  • C++函数参数入栈顺序和调用约定 C语言中函数参数入栈的顺序
    C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式

  • 设计模式的七大原则 设计模式的六大原则
    开闭原则就是说对扩展开放,对修改关闭。
    每个类应该实现单一的职责。
    任何基类可以出现的地方,子类一定可以出现。
    写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
    使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
    一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部
    原则是尽量首先使用组合的方式,其次考虑继承,继承要依赖里氏替换原则。

  • 常见设计模式 C++各类设计模式及实现详解
    优点:代码量较少,逻辑简单。
    缺点:违背了开闭原则。客户把需要生产的产品名字传给工厂,工厂内部用if语句进行判断并生产对应产品。
    当新增产品类型时,需要修改原来的工厂代码。
    优点:符合开闭原则。一个工厂对应生产一种产品,用户只需要找到对应工厂,不需要传入产品名字。
    缺点:每增加一种产品,需要新增一类工厂和产品,相比于简答工厂需要更多类定义。工厂之间没有关系。
    在工厂方法上,每个工厂继承自抽象工厂类,每个工厂可以生产多种产品。
    2)单例模式及应用场景 C++中的单例模式、C++的三种单例模式-----深度解析、C++实现单例的5种方法总结

  • 智力题之【老鼠吃毒药问题】
    12个球,其中有1个坏球和其他11个重量不一样,给你一个天平,称3次,找出不一样的那个
    (规定时间过桥问题)A、B、C、D 四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时 1、2、5、10 分钟

下列表述错误的是?()

  • int是基本类型,直接存数值,Integer是对象,用一个引用指向这个对象。
  • 在子类构造方法中使用super()显示调用父类的构造方法,super()必须写在子类构造方法的第一行,否则编译不通过
  • 封装的主要作用在于对外隐藏内部实现细节,可以增强程序的安全性
  • final是java中的修饰符,可以修饰类、接口、抽象类、方法和属性。

final不能修饰接口


下面这三条语句输出结果:

在java中,“+” 和 “+=” 是经过重载的运算符,而java不允许程序员进行运算符的重载。

如果 “+” 之前是String,那么此时,“+” 的作用就是连接两个字符串;若此时 “+” 后面是基本数据类型的话,可以直接进行连接,若是引用数据类型的话,则会调用该对象的toString()方法。


要使某个类能被同一个包中的其他类访问,但不能被这个包以外的类访问,可以( )

  • 让该类不使用任何关键字

default和protected的区别是:前者只要是外部包,就不允许访问;后者只要是子类就允许访问,即使子类位于外部包。
总结:default拒绝一切包外访问;protected接受包外的子类访问


以下描述错误的一项是( )?

  • 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行 到了第几行,是线程隔离的
  • 原则上讲,所有的对象都是在堆区上分配内存,是线程之间共享的
  • 方法区用于存储JVM加载的类信息、常量、静态变量,即使编译器编译后的代码等数据,是线程隔离的
  • Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的

方法区和堆内存是线程共享的;程序计数器、虚拟机栈是线程隔离的


假设如下代码中,若t1线程在t2线程启动之前已经完成启动。代码的输出是()

new URL()时必须捕获检查异常,但这个异常是由于字符串格式和URL不符导致的,与网址是否存在无关。
URL的toString方法返回字符串,无论网址是否存在


从内存实现或者反射的角度来看,关于继承的说法正确的是()。 注:此处的继承不代表能调用

  • 子类将继承父类的所有的数据域和方法
  • 子类将继承父类的其可见的数据域和方法
  • 子类只继承父类public方法和数据域
  • 子类只继承父类的方法,而不继承数据域

在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。
所以所谓的继承使子类拥有父类所有的属性和方法其实可以这样理解,子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用


jdk1.8版本之前的前提下,接口和抽象类描述正确的有( )

  • 接口中的方法可以有方法体

下面的类哪些可以处理Unicode字符?

字符流是字节流根据字节流所要求的编码集解析获得的,可以理解为字符流=字节流+编码集;后缀是Stream的都是字节流,其他的都是字符流。


下面选项中,哪些是interface中合法方法定义?()



  • final类的方法肯定不能被同一个包的类访问
  • final类的方法能否被同一个包的类访问不是由final决定
  • final对象本身的引用和值都不能改变

final变量:如果是基本数据类型,则其数值一旦初始化后就不能被改变;
如果是引用类型的变量,则对其初始化后,便不能再指向另一个对象,但是其里面的值是可以改变的。



以下Java程序运行的结果是:

java中引用类型的实参向形参的传递,只是传递的引用,而不是传递的对象本身。


在各自最优条件下,对N个数进行排序,哪个算法复杂度最低的是? ()



以下哪些对长度为50的字符串数组声明是正确的

声明一个数组时,不能直接限定数组长度,只有在创建实例化对象时,才能对给定数组长度


以下哪个类包含方法flush()?()

  • A 和B 选项都不包含

一般在读写流(stream)的时候,数据是先被读到了内存中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。
这时候如果你调用了close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()


静态内部类不可以直接访问外围类的非静态数据,而非静态内部类可以直接访问外围类的数据,包括私有数据。( )


一个Java源程序文件中定义几个类和接口,则编译该文件后生成几个以.class为后缀的字节码文件。



Java.Thread的方法resume()负责重新开始被以下哪个方法中断的线程的执行()。

suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume() 被调用,才能使得线程重新进入可执行状态


下面关于面向对象的一些理解哪些是错误的( )

  • 面向对象的最重要的特性是支持继承、封装和多态
  • 系统设计应该遵循开闭原则,系统应该稳定不不可修改,但应支持通过继承、组合等方式进行扩展
  • 函数式的语言必然是面向对象的语言
  • 面向对象设计时,每个类的职责应该单一,不要再一个类中引入过多的接口
  • 过程式语言和面向对象的语言各有其优势,过程式语言更加灵活,面向对象语言更加强调抽象和封装
  • Java和C++都是静态类型的面向对象编程语言

  • Collection是java.util下的类,它包含有各种有关集合操作的静态方法
  • Collections是java.util下的类,它包含有各种有关集合操作的静态方法

下面的代码运行后,输出结果是什么?

  • 静态语句块中x为局部变量,不影响静态变量x的值——即x=5没有用
  • x和y为静态变量,默认初始值为0
  • java中自增操作非原子性

instanceof运算符能够用来判断一个对象是否为:

  • 一个实现指定接口的类的实例

一个对象是不是一个类的实例,是不是一个类的子类,是不是一个接口的实现类


下面代码运行结果是()

在运行sout这一行时:

  • 但在返回前,先将43存储在栈内,然后执行finally内的代码块——输出“finally语句块”;
  • 然后才返回43,输出“和是:43”

同理:try代码块中会返回1,在执行finally代码块前,将a=1存在临时栈中;finally中虽然a又赋值为2,但并没有改变临时栈中的值。所以最后返回的仍是栈中的“a=1”


以下java程序代码,执行后的结果是()

1、使用了匿名内部类,并重写了Object中的重写了equals()方法
2、o对象调用了equals方法,无论如何都是返回true



如果子类要调用父类的构造函数,则通过super()调用来实现。

  • 子类的每一个构造方法都必须显式或隐式调用父类的一个构造方法
  • 如果不显式调用, 则系统隐式调用super()
  • 调用父类构造方法(父类没有,系统提供)、被重写的方法是需要super关键字;其他不需要

抽象类方法的访问权限默认都是public。( )

  • JDK 1.8时,抽象类的方法默认访问权限变为default

下列Java代码中的变量a、b、c分别在内存的____存储区存放。

  • 堆区:只存放类对象,线程共享
  • 栈区:存放方法局部变量,基本类型变量区、执行环境上下文、操作指令区,线程不共享
  • 方法区:又叫静态存储区,存放class文件和静态数据,线程共享


以下类型为Final类型的为()

  • string的字符数组是final修饰的,所以字符数组不可以修改
  • stringbuffer的字符数组没有final修饰,所以字符数组可以修改
  • string与stringbuffer都是final修饰,只是限制他们所存储的引用地址不可修改

有如下一段代码,请选择其运行结果()

hotspot中 编译时"tao"+“bao"将直接变成"taobao”,b+c则不会优化,因为不知道在之前的步骤中bc会不会发生改变,而针对b+c则是用语法糖,新建一个StringBuilder来处理


  • 编译能通过,但是没有输出结果

当一个实体类继承于一个抽象类,必须实现抽象类的抽象方法,抽象类本身没有错误,但是cat类编译通不过


下面程序的运行结果是:( )**

t.run是调用的Thead类中的run()方法,t.start才是执行线程,所以这题就是执行普通run()方法,先输出pong,在输出ping

(答案仅供参考,不喜勿喷~~)
(本人比较懒,后面的就没仔细整)

1、 什么是嵌入式系统?他和人们日常使用的 PC 有什么区别和联系?
(1) 以应用为中心,计算机技术为基础,软硬件可裁减,从而能够适应实际应用中对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。
  ①嵌入式系统是专用的计算机系统,而PC是通用的计算机系统。
  ②技术要求不同,通用PC追求高速、海量的数据运算;嵌入式要求对象体系的智能化控制。
  ③发展方向不同,PC追求总线速度的不断提升,存储容量不断扩大;嵌入式追求特定对象系统的智能性,嵌入式,专用性。

2、 列举嵌入式系统的主要特点。
专用性、可裁剪行、实时性、可靠性、具有较长的生命周期、不易被垄断。

3、 比较嵌入式微处理器 MPU 和嵌入式微控制器 MCU 之间的区别和联系。
(1) (MPU)嵌入式微处理器以通用处理器(CPU)为基础。将微处理器装配在专门设计的电路 板上,只保留和嵌入式应用有关的功能;外接电路必须包括 ROM、RAM、总线接口、各 种外设等器件。
(2)(MCU)嵌入式微控制器又称单片机,是将整个计算机系统浓缩集成到一块芯片中。一般 以某一种微处理器内核为核心,芯片内部集成 ROM/EPROM、RAM、总线、总线逻辑、 定时/计数器、看门狗、I/O、串行口、脉宽调制输出、A/D、D/A、Flash 等各种必要功能和外设。

4、 什么是冯诺伊曼结构?什么是哈佛结构?
(1)冯诺伊曼体系结构:指令和数据不加以区分,都通过数据总线进行传输。因此,指令读 取和数据访问不能同时进行,数据吞吐量低,但总线数量相对较少且管理统一。大多数通用计算机的处理器(如 Intel X86)和嵌入式系统中的 ARM7 处理器均采用冯诺依曼结构。
(2)哈佛体系结构:指令与数据分开存储在不同的存储空间,使得指令读取和数据访问可以 并行处理,显著提高了系统性能,但需要较多数量的总线。大多数嵌入式处理器都采用哈佛结构。

5、 简述嵌入式 I/O 接口的功能、组成和编制方式。
(1)功能:嵌入式 I/O 接口连接和控制嵌入式 I\O 设备,负责完成嵌入式处理器和嵌入式 I\O 设备间的信号转换、数据传输和速度匹配。
(2)组成:寄存器(数据寄存器、控制寄存器、状态寄存器)、I\O 控制逻辑部件、外设接口 逻辑。
(3)编制方式:为寄存器指定端口地址的方法被称为 I\O 接口的编制方式,一般来说 I\O 接 口编制方式有统一编址和独立编址。

6、 无操作系统的嵌入式软件主要有哪几种实现方式?
循环轮询系统、前后台系统。

7、 什么是引导加载程序?它的主要功能是什么?
引导程序一般由汇编语言编写,在嵌入式系统上电后运行,完成自检、存储映射、时钟系统 和外设接口配置等一系列硬件初试化工作。

8、 列举嵌入式系统的主要分类?
(1)按硬件划分:根据嵌入式处理器的字长,可分为 4,8,16,32,64 位嵌入式系统。
(2)按软件复杂度划分:无操作系统控制、小型操作系统控制、大型操作系统控制的嵌入式 系统。
(3)按实时性划分:非实时嵌入式系统、硬实时嵌入式系统、软实时嵌入式系统。

9、 列举嵌入式系统的主要应用领域。
国防军事、工业控制、消费电子、办公自动化产品、网络和通信设备、汽车电子、金融商业、 生物医学、信息家电。

1、 概述嵌入式系统的开发环境。
嵌入式系统的开发环境称为交叉开发环境,有宿主机、目标机以及它们之间的连接构成。 首先,在宿主机上建立开发环境,进行应用程序编写和交叉编译,然后,在宿主机目标机之间建立连接,将应用程序下载到目标机上进行交叉调试最后,将应用程序固化到目标机中实际运行

2、 简述嵌入式软件开发工具的构成。
编辑器、编译器、链接器、调试和下载工具。

3、 列举目前常用的嵌入式软件集成开发工具。

4、 嵌入式调试方式有哪些? 答:
软件模拟器、ROM 监控器、ROM 仿真器、在线仿真器、片上调试

5、 什么是 JTAG?它属于哪种嵌入式调试方式?简述 JTAG 接口的引脚定义。
(1)JTAG 是一种关于测试访问和边界扫描结构的标准,用于芯片内部测试及对程序进行调试、 下载。

6、 目前常用的嵌入式软件开法语言有哪些?他们分别具有什么特点?
汇编语言、C 语言、Java 语言
(1)汇编语言:对底层设备操控性好、效率高但编程复杂功能有限、可读性、可移植性差。
(2)C 语言:语言简洁紧凑,使用方便灵活、表达能力强代码质量高、执行效率高等。
(3)Java 语言:面向对象、解释性、平台无关、分布式、健壮、安全、动态、支持多线程。

7、 嵌入式系统的开发过程可以分为哪几个阶段?
需求分析、系统规划、系统实现、系统测试、系统发布

2、 ARM Cortex 处理器分为哪几个系列?每个系列又分别面向哪些应用场合?
(1)Cortex-A:面向高端的基于虚拟内存的复杂操作系统应用。
(2)Cortex-R:面向实时领域的应用。
(3)Cortex-M:面向低成本低功耗的传统单片机应用场合。

ARM Cortex-M3 处理器由 Cortex-M3 内核和调试系统构成,Cortex-M3 内核主要由 core 中央 处理器核心、NVIC 嵌套向量中断控制器、SYSTICK 系统定时器、MPU 存储保护单元和总线矩 阵等组成。调试系统包括停机和调试监控器两种模式、指令断点、寄存器、存储访问以及性 能分析此外还具有指令跟踪、数据跟踪、调试信息跟踪。

主要有 I-Code 总线、D-Code 总线、系统总线、外部私有外设总线和调试访问端口总线 DAP。

5、 ARM Cortex-M3 处理器有几种工作状态?支持哪些数据类型?
两种工作状态:Thumb 状态和调试状态。 数据类型:字(32b)、半字(16b)、字节(8b)

(1)通用寄存器(R0~R12):数据操作。
(2)堆栈指针寄存器(SP):用作堆栈指针。
(3)链接寄存器(LR):调用子程序时保存返回地址。
(4)程序计数器(PC):用于存放下一条执行的指令地址。
(5)特殊功能寄存器组:预定义的功能。

7、 概述 ARM Cortex-M3 处理器的两种操作模式及其切换机制。
线程模式和处理者模式,异常产生使中断用户应用程序执行从线程模式切换到处理者模式, 执行异常服务程序,异常返回,由处理者模式切换到线程模式,继续执行被打断的用户应用 程序。

8、 异常和中断有什么联系和区别?ARM Cortex-M3 处理器最多能支持多少种异常?他们的 优先级是如何规定的?
(1)在 ARM 中凡是发生打断程序正常执行流程的事件,都被称作异常。中断是一种特殊的 异常且是异步事件,异常还包括同步事件。
(3) 优先级通过抢占优先级和子优先级划分。

9、 假设 ARM Cortex-M3 处理器要将以下数据以小端格式写入存储器,依次写出实现以下功 能的 C 语句,并画出这些数据在 ARM 存储器中的存储空间分布图:
(1) 大写字母’E’存放在地址 0x 上。

ARM Cortex 内核是 ARM 公司设计,而基于 ARM Cortex 内核的微控制器是各大厂商根据 ARM 公司的内核,设计各具特色的微控制器。其中 MPU 由 ARM Cortex 内核、调试系统、内部总 线、外设、存储器、时钟复位、IO 等封装而成。(MCU=CPU+RAM/ROM+I/O)

2、 简述 STM32 系列微控制器的适合场合、命名规则和主要产品线。
替代绝大部分 10 元以上的 8/16MCU 的应用 替代目前常用的 32 位 MCU(ARM7)的应用 小型 OS 相关的应用 简单图形和语音相关的应用
(2)命名规则: 名称主要有以下部分组成产品系列名、产品类型名、产品子系列名、引脚数、Flash 存储器 容量、封装方式、温度范围。
(3)主要产品线: 产品线包括高性能、主流、超低功耗三大类,分别面向不同的应用。

3、 目前微控制器的开发方法主要有哪些?
答: 寄存器开发、库函数开发、中间件开发

4、 STM32F103 微控制器的主系统由哪几部分构成?画出 STM32F103 微控制器的系统结构图。
主系统由 4 个主动单元和 4 个被动单元构成,它们彼此之间通过一个多级的 AHB 总线架构 相互连接。其中 4 个主动单元包括 Cortex-M3 内核数据总线和系统总线、通用 DMA1 和通用
DMA2,4 个被动单元包括内部 SRAM、内部闪存存储器、FSMC 和连接所有 APB 设备的 AHB

6、 什么是微控制器的最小系统?它通常由哪几部分组成?
(1)一个微控制器的最小系统是指使为控制器正常工作所需的最少原件。
(2)通常由微控制器芯片、电源电路、时钟电路、复位电路、调试和下载电路等部分组成。

(1)主电源 VDD(必需)
(2)实时时钟和一部分备份寄存器的电源 VBAT(可选)
(3)ADC 模块所需的参考电压 VREF+和 VREF-(可选) 其中每个电压供应引脚都需要至少一个去耦电容

高速外部时钟、高速内部时钟、低速外部时钟、低速内部时钟

10、STM32F103 微控制器 AHB 高速总线时钟 HCLK、APB2 外设总线时钟 PCLK2 和 APB1 外设 总线时钟 PCLK1 分别给哪些模块提供时钟信号?当 STM32F103 微控制器复位后,他们默认 的工作频率分别是多少?
(2) APB2 外设总线时钟(PCLK2):为挂载在 APB2 总线上的外设提供时钟信号,72MHz。
(3) APB1 外设总线时钟(PCLK1):为挂载在 APB1 总线上的外设提供时钟信号,36MHz。

11、STM32F103 微控制器有哪些低功耗模式?他们各自有什么特点?如何进入和退出这些低 功耗模式?
(1)睡眠模式:内核停止工作,外设还在继续工作。CPU 停止运行、PLL 关闭、关闭除唤醒 内核的外设外其他所有外设时钟。当内核遇到 WFE 或 WFI 指令进入睡眠模式,直到某个外 设产生事件或中断请求,退出睡眠模式。
(2)停机模式:睡眠模式的基础上,所有外设时钟都被关闭。CPU 停止运行、PLL、HIS、HSE、 关闭、关闭所有外设时钟、调压器低功耗模式。先设置电源控制寄存器 SLEEPDEEP 位置位、 PDDS 清零,一旦遇到 WFE 或 WFI 指令,进入停机模式。通过 EXTI 信号唤醒。EXTI 信号可 以是 16 个外部 I\O 引脚之一、PVD 的输出、RTC 闹钟或 USB (3)待机模式:最低的电能消耗。CPU 停止运行、PLL、HIS、HSE、关闭、关闭所有外设时钟、 调压器关闭。先设置电源控制寄存器 SLEEPDEEP 位置位、PDDS 置位,一旦遇到 WFE 或 WFI 指令,进入待机模式。退出条件是 NRST 引脚上的外部复位信号、IWDG 复位、WKUP 引脚 上的上升沿或 RTC 闹钟事件。

12、STM32F103 微控制器有哪些安全特性?
看门狗、电源检测、时钟安全系统

13、什么是看门狗?STM32F103 微控制器的看门狗有何特性?
(1)看门狗是嵌入式系统中常用的安全保障行机制。
(2)它可以实时监测程序的运行状态,即使由于某种原因微控制器进入一个错误状态,程序 跑飞进入死循环,系统也可以自动恢复。

14、什么是启动代码?它主要执行哪些工作?
(1)启动代码用来初始化系统以及为嵌入式操作系统或者使用高级语言编写的嵌入式应用软 件做好运行前准备的一段汇编语言程序。
(2)初始化异常向量表、初始化时钟系统、初始化存储器系统、初始化堆栈和跳转到 main 函数等。

(1)根据 BOOT0 和 BOOT1 引脚选择启动存储器映射。
(2)从地址 0x 处取出栈顶指针值放入 MSP。
(3)从地址 0x 处取出复位异常服务程序的入口地址放入 PC。
(4)执行复位异常服务程序。

16、使用嵌入式软件开发工具(如 KELL MDK 等)构建基于 STM32F103 微控制器应用的开发 过程,具体可以分为那几步?
(2) 下载安装嵌入式开发工具。
(3) 通过官方控制模板和硬件型号更改相关配置选项。
(6)使用软件模拟仿真或下载硬件运行等方式调试程序。
(7)下载到微控制器,复位从新运行。

微控制器数字输出输出的基本模块

3、 对于 STM32F103 微控制器 GPIO 来说,什么是复用功能重映射?要实现 STM32F103 微控制器某个引脚的复用功能重映射,具体分哪几步操作?
(1) 用户根据实际需要可以把某些外设的复用功能从默认引脚转移到备用引脚上,这就是外设复用功能的 I/O 引脚重映射。
①使能被重新映射到的 I/O 引脚的时钟
③按复用功能的方式配置 I/O 引脚
④使能被重新映射的外设时钟
⑤对外设进行 I/O 引脚重映射

(1)外设复用功能重映射

6、 简述使用库函数开发 STM32 微控制器应用的一般步骤。

1、 嵌入式系统中,定时器的主要功能有哪些?
答:延时、定时、计数、输入捕获、输出比较、PWM 输出等高级功能。

2、 STM32F103 微控制器定时器的类型有哪几种?STM32F103 微控制器不同类型的定时器有什么区别?
答:(P254、P263、P266,三个定时器的主要特性的区别)
(2) 基本定时器只具备基本的定时功能,通用定时器除了基本的定时功能外它主要用于 测量输入脉冲的频率和脉冲宽度以及输出 PWM 脉冲等场合,还具有编码器接口。 高级定时器除了具有通用定时器的所有功能外,还可以被看成是一个分配到 6 个通 道的三相 PWM 发生器,具有带死区插入的互补 PWM 输出。

3、 STM32F103 微控制器通用定时器的常用工作模式有哪些?
(1)计数模式(向上、向下、双向计数)、
(3)PWM 输出模式、
(5)PWM 输入模式、

5、 简述无操作系统下基于无限循环的嵌入式软件架构的组成及应用场合。

1、 中断服务函数与普通的函数相比有何异同?
(1)相同点:结构上两者非常相似
(2)不同点:函数一般有参数和返回值,并在应用程序中被认为显示的调用执行,而中断服 务程序没有参数和返回值,并只有中断发生时才会被自动隐式地调用执行。

2、 什么是中断向量表?它通常存放在存储器的哪个位置?
(1)中断向量表是一块存储区域,中断对应的中断服务程序的入口地址统一存放在中断向量 表中。
(2)中断向量表一般位于存储器的零地址位置。

3、 概述中断处理过程。
(1)中断响应(保护现场、中断向量表中找到该中断对应的中断服务程序的地址)
(2)执行中断服务程序

4、 简述使用中断的优缺点。
(1)优点:协调系统对各种外部事件的响应和处理,使系统能够快速响应紧急事件或优先处 理重要人物,减少 CPU 负荷,加快对事件的响应速度,显著地提高系统效率。

1、中断会增加程序执行的不确定性和时间长度。
2、中断会抢占正在使用的资源。
3、中断嵌套会增加栈空间。

5、 STM32F103 微控制器的中断系统共支持 84 个异常。其中包括 16 个内部异常和 68 个可 屏蔽的非内核异常中断。

6、 STM32F103 微控制器的中断系统,使用 4 位优先级设置,一共支持 16 级可编程异常优先级。

7、 对于不同的中断源,STM32F103 微控制器的响应顺序遵循什么规则?
(1)先比较抢占优先级,抢占优先级高的中断优先响应。
(2)当抢占优先级相同时,比较子优先级,子优先级高的中断优先响应。
(3)当上述两者都相同时,比较它们在中断向量表中的位置,位置低的中断优先响应。

8、 STM32F103 微控制器复位中断服务程序的地址存放在中断向量表中的哪个位置?

9、 STM32F103 微控制器的中断设置过程可以分为哪几步?
(1)建立中断向量表(选择 Flash 或 RAM 中建立中断向量表,默认是 Flash)
(2)分配栈空间并初始化(分配栈空间、初始化栈)
(3)建立中断优先级(设置中断优先级分组的位数、设置中断的抢占优先级和子优先级)
(5)编写对应的中断服务程序

10、STM32F103 微控制器事件和中断有什么区别和联系?
从外部激励信号看中断和事件的请求信号没有区别,只是在 STM32F103 微控制器的内部将 他们分开。中断信号会被送至 NVIC 向 CPU 产生中断请求,至于 CPU 如何响应,有用户编写 或系统默认的对应中断服务程序决定。事件信号会向其他功能模块(如定时器、USART、DMA 等)发送脉冲触发信号,至于其功能模块会如何响应这个脉冲触发信号,则由对应的模块自己决定。

11、STM32F103 微控制器 EXTI 信号线一共有多少根?它们分别对应哪些输入? 答:
(2)除了 EXTI16(PVD 输出)、EXTI17(RTC 闹钟)和 EXTI18(USB 唤醒)外,其他 16 根外部 信号输入线分别对应微控制器的 16 个引脚。

12、若要使用 STM32F103 微控制器的 EXTI 中断,必先使哪个时钟?
APB2 总线上该引脚对应端口时钟以及 AFIO 功能时钟。

13、C 语言的关键字 volatile 有什么作用?主要用于哪些场合?
(1) volatile 意为易变的、不稳定的。不让编译器进行优化,即每次读取或修改 volatile 的值 时,都必须重新从内存或寄存器中读取或修改。

    中断服务程序中修改的供其他程序检测的变量。 多任务环境下各任务间共享的标志。 存储器映射的硬件寄存器。

1、 什么是 DMA?DMA 有哪些传输要素?DMA 的整个传输过程分为哪几个步骤?
(1)DMA(Direct Memory Access,直接存储器存取),是一种完全由硬件执行数据交换的工 作方式。它由 DMA 控制器而不是 CPU 来控制在存储器和存储器、存储器和外设之间的批量数据传输。
(2)传输要素:传输源、传输目标、传输单位数量、触发信号

2、 STM32F103 微控制器 DMA 一共有多少个通道?如何响应在不同通道上同时产生的 DMA请求?
(1)一共具有 12 个独立的可配置的通道,其中 DMA1 有 7 个通道,DMA2 有 5 个通道。
(2)同一时刻,一个 DMA 只能有一个请求有效,通过先判断软件优先级,再判断硬件优先 级的顺序响应 DMA 请求。

3、 STM32F103 微控制器 DMA 通道的软件和硬件触发方式分别用于哪种场合?两者对于通 道的选择是否有所限定?
(1) 硬件通道触发:适用于涉及片上外设的数据传输。当 DMA 传输涉及片上外设时应根据DMA1 和 DMA2 通道映射表的分配情况,选择指定的 DMA 及其通道。
(2) 软件触发:适用于仅涉及存储器之间的数据传输。当 DMA 传输仅涉及存储器时,可任 意选择未被外设占用的 DMA 通道。

5、 STM32F103 微控制器 DMA 传输允许的最大数据量是多少?
DMA 数据传输量(最大为 65535)可编程。

6、 C 语言的关键字 volatile 有什么作用?主要用于哪些场合?
(1)volatile 意为易变的、不稳定的。不让编译器进行优化,即每次读取或修改 volatile 的值时,都必须重新从内存或寄存器中读取或修改。

1、中断服务程序中修改的供其他程序检测的变量。
2、多任务环境下各任务间共享的标志。
3、存储器映射的硬件寄存器。

ADC 模拟数字转换器,是一种将连续变化的模拟信号转换为离散的数字信号的电子器件。

2、 ADC 进行模数转换分为哪三步?

3、 ADC 的性能参数有哪些?分别代表什么意义?
(1)量程:指 ADC 所能转换的模拟输入电压的范围。
(2)分辨率:反映 ADC 对输入信号微小变化的响应能力,描述刻度大小。
(3)精度:指对于 ADC 的数字输出(二进制代码),其实际需要的模拟输入值与理论上要求 的模拟输入值之差,描述物理量的准确程度。
(4)转换时间:ADC 完成一次 A/D 转换所需要的时间,是指从启动 ADC 开始到获得相应数据 所需要的总时间。

4、 ADC 的主要类型有哪些?他们各自有什么特点?
(1)逐次逼近型:规模中等、转换速度较快、转换精度较高、功耗低。
(2)电压时间转换型:工作性能比较稳定且抗干扰能力强,转换速度慢。
(3)电压频率转换型:抗干扰能力强,转换速度慢。

7、 STM32F103 的 ADC 共有几路通道?可分为几组?每组最多可容纳多少路通道?
ADC 最多有 18 路模拟输入通道,除了 ADC1_IN16 与内部温度传感器相连,ADC1_IN17 与内 部参照电压相连,其他的 16 路通道都可用作模拟输入的引脚。可分为规则通道组和注入通
道组 ,其中规则通道组最多包含 16 路请求,注入通道最多包含 4 路通道。注入通道组转换 的启动有两种方式:触发注入和自动注入。

单次转换模式、连续转换模式、扫描模式(规则和注入)、间断模式(规则和注入)

规则通道外部触发事件:TIM1_CC1 等等。 注入通道外部触发事件:TIM1_CC4 等等。

仅有规则通道组可以产生 DMA 请求。

12、常用的软件滤波算法有哪些?

13、外围 I/O 设备与 CPU 交换数据的方式有哪几种?试说明它们各自的特点。
(1)程序直接控制方式:就是由用户进程直接控制内存或 CPU 和外围设备之间的信息传送。 这种方式控制者都是用户进程。
(2)中断控制方式:被用来控制外围设备和内存与 CPU 之间的数据传送。这种方式要求 CPU 与设备(或控制器)之间有相应的中断请求线,而且在设备控制器的控制状态寄存器的相应 的中断允许位。
(3)DMA 方式:又称直接存取方式。其基本思想是在外围设备和内存之间开辟直接的数据 交换通道。
(4)通道方式:与 DMA 方式相类似,也是一种以内存为中心,实现设备和内存直接交换 数据控制方式。

1、 解释以下数据通信相关的基本概念:串行通信、并行通信、单工通信、半双工通信、全 双工通信、同步通信、异步通信。
(1)串行通信:使用一条数据线将数据一位一位的依次传输。
(2)并行通信:使用多条数据线传输数据。
(3)单工通信:在同一通路上,只单向传输。
(4)半双工通信:在同一通路上,双向传输。
(5)全双工通信:在不同通路上,双向传输。
(6)同步通信:发送端与接收端之间使用共同的时钟。
(7)异步通信:发送端与接收端之间不存在共同的时钟。

2、 在数据通信中,波特率和比特率有什么区别和联系?
比特率是指每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,传送数 据速度越快。每秒钟通过信道传输的信息量称为位传输速率,也就是每秒钟传送的二进制位 数,简称比特率。比特率表示有效数据的传输速率,用 b/s 、bit/s、比特/秒,读作:比特每 秒。
在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称 为码元传输速率,简称波特率。波特率是指数据信号对载波的调制速率,它用单位时间内载 波调制状态改变的次数来表示(也就是每秒调制的符号数),其单位是波特(Baud,symbol/s)。 波特率是传输通道频宽的指标。
(3)波特率与比特率的关系:
比特率=波特率 x 单个调制状态对应的二进制位数。
(4)由于 URAT 使用 NRZ 编码,因此 URAT 的波特率和比特率是相同的。

3、 简述 UART 的接口组成及其电平标准。

在 TTL 电平标准中:逻辑1通常用+5V 表示,逻辑0通常用0V表示。
在 CMOS 电平标准中:逻辑1的电平一般接近于电源电压,逻辑0的电平一般接近于0V。

4、 简述 RS232 的接口组成及其电平标准。

通常采用 DB-9 的形式

6、 画出带 UART 接口的微控制器与带 USB 接口的 PC 物理连接图。 答:?

7、 UART 数据帧由哪些部分组成?
UART 数据是按照一定格式打包成帧,以帧为单位在物理链路上进行传输的。
UART 的数据格式由起始位、数据位、校验位、停止位和空闲位等构成。其中,起始位、数据位、校验位和停止位,构成了一个数据帧

USART 结构自上而下可分为波特率控制、收发控制和数据存储转移三大部分。

发送期间:发送完成(TC)、清除发送(CTS)、发送数据寄存器空(TXE)
接收期间:空闲总线检测(IDLE)、溢出错误(ORE)、接收数据寄存器非空(RXNE)、校验错误(PE)、LIN 断开检测(LBD)、噪声错误(NE,仅在多缓冲器通信)和帧错误(FE,仅在多缓冲器通信)。

12、假设 STM32F103 微控制器的 USART1 设定以下数据格式:8 个数据位(低位在前高位在 后),奇校验位,1 个停止位,画出发送字母‘E’时 USART1 发送引脚 TXD 的波形图。

1、 通常,SPI 接口由哪几根线组成?它们分别有什么作用?
(1)SCK,即时钟线,由主设备产生。不同的设备支持的时钟频率不同。但每个时钟周期可 以传输一位数据,经过 8 个时钟周期一个完整的字节数据就传输完成了。
(2)MOSI,即主设备数据输出∕从设备数据输入线。这条信号线上的方向是从主设备到从设 备,即主设备从这条信号线发送数据,从设备从这条信号线上接收数据。 (3)MISO,即主设备数据输入∕从设备数据输出线。这条信号线上的方向是由从设备到主设 备,即从设备从这条信号线发送数据。
(4)SS,SPI 从设备选择信号线。当有多个 SPI 从设备与 SPI 主设备相连(即“一主多从”)时, SS 用来选择激活指定的从设备,由 SPI 主设备(通常是微控制器)驱动,低电平有效。当只 有一个 SPII 从设备与 SPI 主设备相连(即“一主一从”)时,SS 并不是必需的。

4、 假设 SPI 编程设定以下时序(CPOL=0,CPHA=0)和数据帧格式(8 个数据位,高位在前低 位在后),画出 SPI 主设备发送字节数据 ox98(十六进制数)时其引脚 MOSI、SCK 和 CS 的波形图。

5、 假设 SPI 编程设定以下时序(CPOL=0,CPHA=(1)和数据帧格式(8 个数据位,底位在前高 位在后),画出 SPI 主设备发送数字’6’时其引脚 MOSI、SCK 和 CS 的波形图。

6、 假设 SPI 编程设定以下时序(CPOL=1,CPHA=0)和数据帧格式(8 个数据位,高位在前低 位在后),画出 SPI 主设备发送字母’r’(十六进制数)时其引脚 MOSI、SCK 和 CS 的波形 图。

7、 假设 SPI 编程设定以下时序(CPOL=1,CPHA=(1)和数据帧格式(8 个数据位,高位在前低 位在后),画出 SPI 主设备发送字节数据 ox54(十六进制数)时其引脚 MOSI、SCK 和 CS 的波形图。

(1)SPI1 位于高速 APB2 总线上,其他的 SPI(如 SPI2、SPI3 等)位于 APB1 总线上; 既可以作为主设备,也可以作为 SPI 从设备;
(2)主模式和从模式下均可由软件或硬件进行 NSS 管理,动态改变主∕从操作模式;
(3)可编程的 SPI 时序:由时钟极性和时钟相位决定;
(4)可编程的 SPI 数据格式:8 位或 16 位数据帧;LSB 在前或 MSB 在前的数据顺序;
(5)可编程的 SPI 传输速率:最高 SPI 速率可达 18MHz;
(6)可触发中断的两个标志位:发送标志位 TXE(发送缓冲区空)和接收标志位 RXNE(接收 缓冲区非空);
(7)支持 DMA 功能的 1 字节发送和接收缓冲区:分别产生发送和接受请求;
(8)带或不带第三根双向数据线的双线单工同步传输;
(9)支持以多主配置方式工作;

SPI 主要由波特率控制、收发控制和数据存储转移 3 部分构成。

10、分别概述 STM32F103 微控制器 SPI 主模式的配置,以及在主模式下发送一个字节数据和接受一个字节数据的流程(太懒啦)

11、分别概述 STM32F103 微控制器 SPI 从模式的配置,以及在从模式下发送一个字节数据和接受一个字节数据的流程(太懒啦)

14、STM32F103 微控制器的 SPI 有哪些状态标记位?可以产生哪些中断请求?

TXE(发送缓冲区空闲标志)
RXNE(接收缓冲区非空标志)

中断请求 TXE(发送缓冲区空闲中断请求)
RXNE(接收缓冲区非空中断请求)

1、 解释 I2C 通信中的以下常用术语:主机、从机、接受器、发送器。
(1)主机:初始化发送、产生时钟和终止发送的器件,通常是微控制器;
(2)从机:被主机寻址的器件;
(3)发送器:本次传输中发送数据到 I2C 总线的器件,既可以是主机也可是从机,由通信过 程具体确定;
(4)接收器:本次传输中从 I2C 总线上接收数据的器件,既可以是主机也可以从机,由通信 过程具体确定。

2、 I2C 接口由哪几根线组成?它们分别有什么作用?
(1)SCL(Serial Clock,串行时钟线):I2C 通信中用于传输时钟的信号线,通常由主机发出。 SCL 采用集电极开路或漏极开路的输出方式。这样,I2C 器件只能使 SCL 下拉到逻辑 0,而不能强制 SCL 上拉到逻辑 1。
(2)SDA(Serial Data,串行数据线):I2C 通信中用于传输数据的信号线。与 SCL 类似,SDA 也采用集电极开路或漏极开路的输出方式。这样,I2C 器件同样也只能使 SDA 下拉到逻辑 0, 而不能强制 SDA 上拉到逻辑 1。

3、 与 SPI 互连相比,I2C 互联有什么特点?
(1)必须在 I2C 总线上外接上拉电阻。
(2)通过地址区分挂载在 I2C 总线上不同的器件。
(3)支持多主机互连。

4、 I2C 的时序由哪些信号组成?
I2C 的位时序,包括起始条件、数据有效性、停止条件等。

5、 试比较嵌入式系统中常用 3 种通信接口:USRT、SPI 和 I2C。
答:重点 从物理层、协议层、连接方式、主要特性、内部结构等方面讨论。

(2)支持标准(100Kbps)和快速(400Kbps)传输速率;
(3)所有的 I2C 可工作于主模式或从模式,可以作为主发送器、主接收器、从发送器或者从 接收器;
(4)支持 7 位或 10 位寻址和广播呼叫;
(5)具有 3 个状态标志:发送器/接收器模式标志、字节发送结束标志、总线忙标志;
(6)具有 2 个中断向量:1 个中断用于地址∕数据通讯成功,1 个中断用于错误;
(7)具有单字节缓冲器的 DMA

由 SDA 线和 SCL 线展开,主要分为时钟控制、数据控制、控制逻辑等部分?负责实现 I2C 的 时钟产生、数据收发、总线仲裁和中断、DMA 等功能。

10、分别画出 STM32F103 微控制器的 I2C 作为主发送器和从接收器的数据包(含事件)传输序列图。

11、分别画出 STM32F103 微控制器的 I2C 作为主接收器和从发送器的数据包(含事件)传输序列图。

12、STM32F103 微控制器的 I2C 有哪些状态标志位?可以产生哪些中断请求?

我要回帖

更多关于 数据库的数据模型一般分为 的文章

 

随机推荐