c++面试常见问题总结

2023-05-16

近来在面试的过程,发现面试官在c++方面总是喜欢问及的一些相关问题总结,当时没怎么答出来,或者是答的不怎么全面,故而查询相关资料总结下。(后面实际工作会进行实时更新信息)

<一>c++虚函数方面

    虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表指针被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

那么虚函数表的指针存放在哪里呢?

上述已经描述过了,存放在具体的实例对象中,通过虚函数指针来操控虚函数表,在进行多态的时候,需要用到,根据具体的实例对象就能确定所要调用的时哪一个具体类的具体方法。都是通过虚函数表来完成相应的操作的。在虚函数表中存放的是具体实例类重写的父类的虚函数方法地址。当调用时,根据具体的实例即可访问到具体方法。综上所述虚函数可以概括为以下几点:

a>虚函数表父类子类都有一个,并且子类根据继承将从父类将继承来的虚函数进行覆盖,通过基类指针指向派生类对象调用方法时,根据派生类对象类型调用其方法。(采用的是动态联编方式,在运行时实现)。

b>虚函数表好比是一个类似数组的东西,在类对象中存储vptr(虚函数指针),并指向虚函数表,因为其不属于方法,也不属于代码,所以不能存放在代码段,虚函数表存放在全局区。

c>虚函数表中存储的是虚函数的方法的地址,其大小在编译节点就已经确定好了,根据的继承关系,就能确定好虚函数表的大小。所以不用动态的分配内存,不在堆中。

d>虚函数表父子类各一份,并且子类覆盖父类继承来的虚函数。虚函数表指针放在对象内存开头的四个字节。如下可获取出来:

typedef void (*PFUN)();B b;  PFUN* ptr = (PFUN*)(int*)*(int*)(&b);

e>通过父类指针指向子类对象,在调用的时候通过动态联编实现多态方法的调用。

f>析构函数也定义成虚析构函数,为了避免继承过程,在释放资源的时候,避免只时调用了基类的析构,从而导致了派生类的析构没有被调用,从而造成资源泄漏的影响。

g>构造函数不能被定义为虚函数,因为虚函数通过虚函数指针调用的,创建对象需要调用构造函数,此时对象还没创建完成,虚函数指针不存在。另外调用虚函数就须要通过 vtable来实现,但是此刻对象还没有实例化,也就是内存空间还没有,无法找到虚指针,所以构造函数不能是虚函数

<二>有关c++类占用内存的多少计算

 在c++中一个空类所占内存的大小为1字节,例如:

  class A{};  计算其占用内存大小:sizeof(A) = 1;为什么一个空类的大小占用1字节呢?是因为类的实例化实质上就是在内存中分配一块独一无二地址,这样保证了实例是唯一存在的。所以,给空类分配一个字节,就相当于给实例分配了一个地址。如果不隐含包含一个字节的话,就不能进行实例化。当该类作为基类被继承的时候,系统会优化该类成为0字节,这个被称为空白基类最优化过程。

以下几种类型的类占用内存字节的大小,在32位系统下:

class A{};  sizeof(A) = 1;该大小上述已经具体化介绍。

//只包含普通成员函数的类,成员函数不占用内存空间

class B{

  public:

     B(){}

     ~B(){}

};

sizeof(B) = 1;  

//包含普通成员变量的类,根据变量实际大小计算占用内存大小

class C{

  public:

     C(){}

     ~C(){}

 private:

   int c;

};

sizeof(C) = 4 ;

//包含虚函数的类,包含虚函数指针,虚函数指针变量本身占用内存大小

class D{

  public:

     D(){}

     virtual ~D(){}

 private:

   int d;

};

sizeof(D) =  8; (64位机器,一共是16字节,指针变量&整型变量都是8字节)

//包含继承关系的类

class E:public D{

    public:

      E(){}

      ~E(){}

    private:

      int e;

};

sizeof(E) = 8;

从以上A到E几个实例来解释该类所占用内存大小的原因。

A类,是一个空类,因为空类也可以进行实例化,实例化就需要系统分配一块唯一地址的内存,所有系统隐含添加一个字节大小。

B类,虽然包含有构造函数和析构函数,但是在类中,成员函数是不占用内存的,另外该类并无成员变量,所以占用的内存大小和仍旧是1字节。同样是需要实例化所需要的。

C类,包含成员变量,系统给成员变量按照实际类型来分配具体内存大小的。例如,一个int型变量,占用4字节,所有sizeof(C) = 4.

D类,存在虚函数的类都有一个一维的虚函数表也也称为虚表,虚表里存放的就是虚函数的地址,因此,虚表是属于类的。这样的类对象的前四个字节是一个指向虚表的指针,类内部必须得保存这个虚表的起始指针。在32位的系统分配给虚表指针的大小为4个字节,得到类D的大小为4,所以在算上成员变量d所占用的字节数,sizeof(D) = 8;

E类,继承了D类,E类和D类共享一个虚函数指针,在E类中自身的一个成员变量e,加上继承D中的成员d,sizeof(E) = 8。(共享一个虚函数指针,所以在E类中不计数)

综上所述:

 空类:占用一个字节大小,因为每一个类都需要实例化时分配一块独一无二的内存空间。

 类内部:普通成员变量根据各自类型占用相应的内存大小,但是static成员变量以及静态方法均不占用类内存大小,其存放在全局区域。子类继承父类,则将父类的成员变量计算进入子类占用的大小。非虚的成员函数不占用内存大小,但是虚函数,需要维护一张虚函数表存放相应的虚函数地址,所以虚函数指针在类内部,指针占用相应的内存大小,并且继承之后,父子类共享此虚指针。(32位指针4字节,64位指针,8字节字节)

<三>c++中的虚继承的作用?

 在c++中需要通一个继承是一个特性,常使用的都是一些继承虚函数,为了实现多态的过程。但是往往存在一种情况,为了提高代码的复用性,有一个基类,其自身有很多方法,是很多子类都能使用,所以往往就让子类直接将该类继承过来使用,避免了子类自己在实现一边,避免造成大量的代码冗余,维护也不方便。但是,如果大量的子类都继承同一个基类,在大量子类中在派生一个共同的子类,会出现一些问题的,比如从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,占用内存大小。所以,使用虚继承实现将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射,从而避免调用该方法时出现数据二义性以及节省相应内存空间。

虚继承的原理?

虚继承的原理过程是通过虚基类指针和虚基类表来实现,一个虚基类指针占用四个字节的大小,虚基类表不占用类存储空间大小,在虚基类表中存储的是虚基类相对于派生类的偏移量,这样就根据偏移量找到虚基类成员。如果虚继承的类被继承,该派生类同样有一份虚基类指针的拷贝。这样就能保证虚基类中在子类中存在一份拷贝。避免有多分拷贝造成二义性。

语法:

class 派生类: virtual 基类1,virtual 基类2,...,virtual 基类n

{

...//派生类成员声明

};

如图所示:

构造函数的和析构函数的执行顺序

首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;

执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;

执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;

执行派生类自己的构造函数;

析构以与构造相反的顺序执行;

注:

从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象时,在最后派生类的构造函数处调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。(在最派生类的成员初始化类表中,中间的初始化列表成员会被忽略,从而保证对虚基类子对象初始化一次)。

在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行

例如:如下代码所示:

一个派生类继承多个基类,多个基类中包含重复名称的方法。(普通继承)

class A{

    public:

        A(){cout<<"A is been called"<<endl;}

        void fun(){cout<<"A fun been called"<<endl;}

};

class B{

    public:

        B(){cout<<"B is been called"<<endl;}

        void fun(){cout<<"B fun been called"<<endl;}

};

class C:public  A,public B{

    public:

        C(){cout<<"C is been called"<<endl;}

};

此种方法会导致同名方法存在多分拷贝,导致调用时会产生二义性,只能使用该种方法调用,如下:

int main(void){

    C c;

  //c.fun()错误,会产生二义性

    c.A::fun();

    c.B::fun();

    return 0;

}

2,继承一个多层的类

class F{

    public:

        F(){cout<<"F been called"<<end;}

        void gun(){cout<<"F gun been called"<<endl;}

};

class S1:public F{

    public:

        S1(){cout<<"S1 been called"<<endl;}

};

class S2:public F{

    public:

           S2(){cout<<"S2 been called"<<endl;}

};

class Son:public S1,public S2{

    public:

        Son(){cout<<"Son been called"<<endl;}

};

int main(){

    Son son;

    //son.gun();有二义性,因为该方法在S1和S2中各有一份备份

    son.S1::gun();

    son.S2::gun();

    return 0;

}

虚继承就避免了这样的二义性,也节省了空间

(1)

class F{

    public:

        F(){cout<<"F been called"<<end;}

        void gun(){cout<<"F gun been called"<<endl;}

};

class S1:public virtual F{

    public:

        S1(){cout<<"S1 been called"<<endl;}

};

class S2:public virtual F{

    public:

           S2(){cout<<"S2 been called"<<endl;}

};

class Son:public S1,public S2{

    public:

        Son(){cout<<"Son been called"<<endl;}

};

int main(){

    Son son;

    son.gun();//也可使用先前的方法调用

    return 0;

}

<四>为什么构造函数不能写成虚函数,析构函数需要写成虚函数?以及什么情况下,子类的析构不会被调用?

   因为虚函数的是通过虚函数指针操控虚函数表来实现的,且虚函数指针存放在实例对象的头部位置,在创建一个实例对象时,需要调用对应的构造函数,此刻对象还未生成,是不能调用虚函数的,故而构造函数不能为虚函数。(如果设置了构造函数为虚函数,编译时会报错)。

   对于析构函数,是实例对象将要释放资源,需要调用调用析构函数,在继承关系中,为了防止在释放对象的时候调用析构函数,只调用了基类的析构而没有对派生类的析构进行调用,所以,将基类的析构函数进行虚化,从而保证基类和派生类的析构函数都被调用,确保释放其所占用的资源。(调用析构顺序,虚析构函数,调用基类析构的时候,子类对象已经全部销毁)

当基类指针指向子类对象,但是子类析构函数不是虚函数,当调用析构函数的时候,子类的析构函数是不会被调用的

<五>volatile作用

访问寄存器要比访问内存要块,因此CPU会优先访问该数据在寄存器中的存储结果,但是内存中的数据可能已经发生了改变,而寄存器中还保留着原来的结果。为了避免这种情况的发生将该变量声明为volatile,告诉CPU每次都从内存去读取数据。

注:一个参数可以即是const又是volatile的吗?可以,一个例子是只读状态寄存器,是volatile是因为它可能被意想不到的被改变,是const告诉程序不应该试图去修改他。

<六>析构函数能抛出异常吗

答案:肯定是不能。
C++标准指明析构函数不能、也不应该抛出异常。C++异常处理模型最大的特点和优势就是对C++中的面向对象提供了最强大的无缝支持。那么如果对象在运行期间出现了异常,C++异常处理模型有责任清除那些由于出现异常所导致的已经失效了的对象(也即对象超出了它原来的作用域),并释放对象原来所分配的资源, 这就需要调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数已经变成了异常处理的一部分。如果在析构函数中抛出了异常,可能会导致析构函数没有完全执行,从而导致某些对象所占用的资源没有被回收掉,从而导致资源泄漏。

<七>避免在基类的构造函数和析构函数中调用虚函数?

  例如:

class A{

    public:
        A(){
            fun();
        }
        virtual void fun(){
            cout<<"Afun"<<endl;
        }
};

class B:public A{

    public:
        virtual void fun(){
            cout<<"Bfun"<<endl;
        }
};

int main(){

    B b;
    
    return 0;
}


如上所示,调用结果是输出Afun,这是因为在创建对象b的时候,因为B继承A,在进行构造函数的调用的时候,优先调用基类的构造函数,此时的派生类对象尚未完成初始化,此刻虚函数指针还未完成初始化,不能够去检索对应的虚函数表,所以此时进行构造调用的时候为基类的方法。同样析构中的虚函数,等价于调用本类中的方法,从而失去虚函数的效果多态性,无实际存在的意义,(本身析构的调用顺序跟构造相反)。

构造函数的调用顺序是从基类到派生类,逐层构造。在构造的过程中,vptr被指向本层的vtable。而虚函数的行为依赖于vptr。因此,在本层构造函数中,编译器无法获知派生类的任何信息,因此无法形成正确的vtable访问。

<.八>c++中const的用法介绍

        在c++模型中,const关键字通常使用的是防止变量对象意外的改变的功能,即只读变量,在c++中const可以用来修饰的对象有变量,函数返回值,函数参数,以及函数本身,下面介逐一介绍其方式;

const修饰变量:通常是用来定义个常量的属性,表示在该变量在使用范围内是一个常量,不能进行修改的,如果强制修改的话,会出现错误。例如:const int a = 10;

const修饰函数参数:在函数的参数传递中有三种类型的传递方式,值传递,指针传递,引用传递,只有值传递的时候会出现临时变量的产生,其余两种的传递都是相当于调用所传的对象的本身。在这三种传递方式中,需要注意的是,在和const结合使用的时候的一些注意事项:

        函数参数为传入参数,不管是指针传递和引用传递,为了防止意外更改该参数,加上const修饰,可以起到保护作用。例如:void fun(const int *p) or  void fun(const int & x).

        函数参数为传出参数,此时的参数为输出参数,不能使用const进行修饰,否则,此刻该参数将失去输出参数的功能。例如:void fun( char* in,char * out ) or  void fun(char* in,char* & out).

 const修饰函数的返回值:

           当函数的返回值为指针,使用const修饰,表明函数的返回的指针指向的内容是不可变,但是指针本身的指向是可以改变,并且,返回的指针必须使用一个对应的const修饰的指针进行接收,

           例如:const char* GetString(), const char* ptr = GetString()

           当函数的返回值为值传递的方式,使用const没有价值的,因为返回的是一个临时对象。

           如果函数返回值是引用,需要格外注意的是,根据实际情况来区分是要获取该对象的一份拷贝,还是该对象的一个别名使用。要根据实际情况做判断。通常参数返回引用为了使用在类赋值函数中使用,用于链式表达式的调用,a=b=c;具体可参考string类的赋值函数。

const修饰函数:

      在类中,任何不会修改成员的函数都应该定义成const成员函数,如果在const成员函数中修改了成员,会出现错误。通过此种类型提高程序的健壮性。有关const成员函数的几个特性:

      const对象只能访问const成员函数,非const对象两者都可访问;

      const对象的成员是不可修改,但是通过指针维护的对象是可以修改的

      const成员函数不可以修改对象成员,不管对象是否具有const属性,在编译是以是否修改成员为依据,进行检查

      如果一个成员被mutable修饰,那个任何方式都可以修改该成员,即便是const成员函数,也可以修改他

例如:

#include <iostream>
#include <string.h>
using namespace std;
//const修饰函数的返回值
const char* getString(char* str){

    char *p = str;
    return p;

}

void GetInfo(const char* src, char* dst){

  memcpy(dst,src,strlen(src));

}

class A{

public:
  A(int a,int b,int c):a(a),b(b),c(c){
  }
  ~A(){}


  //非const方法,都可以修改
  void fun(int a,int b,int c){

      cout<<"修改之前"<<endl;
      cout<<"this->a "<<this->a<<endl;
      cout<<"this->b "<<this->b<<endl;
      cout<<"this->c "<<this->c<<endl;
      //this->a = a;   //const成员不可更改
      this->b = b;
      this->c = c;
      cout<<"修改之后"<<endl;
      cout<<"this->a "<<this->a<<endl;
      cout<<"this->b "<<this->b<<endl;
      cout<<"this->c "<<this->c<<endl;
  }

  //const成员方法
  void gun(int a,int b,int c) const{
    cout<<"修改之前"<<endl;
    cout<<"this->a "<<this->a<<endl;
    cout<<"this->b "<<this->b<<endl;
    cout<<"this->c "<<this->c<<endl;
    //cosnt成员不可以修改成员
    //this->a = a;  //本身是cosnt成员,不能修改
    //this->b = b; //普通成员,但是在const函数中不可修改
    this->c = c;   //使用了mutable修饰,任何地方丢可修改
    cout<<"修改之后"<<endl;
    cout<<"this->a "<<this->a<<endl;
    cout<<"this->b "<<this->b<<endl;
    cout<<"this->c "<<this->c<<endl;

  }
private:
  const int a;
  int b;
  mutable int c;

};


 int main(int argc, char const *argv[]) {

   //此刻返回的指针的内容是不可更改的
  const char* p = getString("liux");
  cout<<"p = "<<p<<endl;
  char c[12] = {"0"};
  char *dst = c;
  GetInfo(p,dst);
  cout<<"dst = "<<dst<<endl;

  A* a = new A(1,2,3);
  a->fun(7,8,9);
  a->gun(10,11,12);

  const A *a1= new A(11,22,33);
  //a1->fun(0,0,0);//const对象只能访问const成员
  a1->gun(21,31,41);

  delete a;

  return 0;
}

<九>static关键字修饰总结

   static关键字修饰变量,表示该变量为一个静态变量,并且全局共享(在全局作用于中定义,并且变量作用范围仅限于定义改变量的文件中)

    static 关键字在函数体中修饰变量,表示该变量只进行一次初始化,之后每次调用进入该函数,该变量的值仍旧是上一次调用时的值,如果更能该了个变量的值,就保持了该值,拥有一种持久化保存的性质。而函数体中普通的变量生命周期在函数返回时会被销毁,之后从新调用的时候才会重新定义。

   static在类中修饰数据成员,表示该变量不属类中的某个实例,所有的实例共享此变量,即该成员隶属类所有,修改变量需要在类外进行初始化,实际使用中,尽量避免在.h文件初始化该变量,容易造成重复定义。除此之外,类的静态变量可以被类的const成员方法合法更改,见如下代码演示:

   static 修饰的类成员方法的地址,可以直接使用普通的函数指针来存储,而普通的成员方法的地址必须使用类成员函数指针来存储,另外,静态方法只能访问静态成员,详情将如下代码所示:

注:static修饰的函数在内存中只有一份,而普通函数在每个调用者中都维持一份拷贝。

以上几种总结方式示例代码如下:

#include <iostream>
using namespace std;


class A{

public:
  A(){}
  ~A(){}

  void gun(int m){
    cout<<"gun修改前: "<<val<<endl;
    val = m;
    cout<<"gun修改前: "<<val<<endl;
  }
  //const成员函数可以更改静态成员变量的值
  void fun(int m) const{
    cout<<"fun修改前: "<<val<<endl;
    val = m;
    cout<<"fun修改前: "<<val<<endl;
  }

  //静态成员可以作为静态成员方法的默认参数,普通方法不允许
  static void hun(int m = val){
      cout<<"hun() = "<<m<<endl;
      /*
      静态方法只能访问静态成员,不能访问非静态成员,否则会报错,如下
      cout<<" hun() nal =  "<<nal<<endl;
      */
  }

  //静态方法和普通方法的函数指针
 static void s_fun(){ cout<<"++++++++++++++"<<endl;}
 void f_fun(){cout<<"******************"<<endl;}

 //函数内使用static修饰变量让其持久化
 void last(){
    static int lt = 888;
    cout<<"lt value is "<<lt--<<endl;

 }

private:
  static int val;
  int nal;

};

//在类外初始化静态成员变量,注尽量在.cpp文件中初始化静态成员变量,不然头文件的相互包含很容易引起定义冲突的错误
//该出是为了实现方便,都在.cpp文件中
int A::val = 100;

int main(){
  A* a = new A();
  //通过const成员变量修改静态成员变量
  //a->fun(222);

  //使用静态成员变量作为静态方法的默认参数
  a->hun();

  /**
  静态成员函数的地址可以使用普通的函数指针来存储,而普通成员函数的地址
  必须使用成员函数指针来存储,如下所示:
  **/
  void (*s_ptr)() = &A::s_fun;
  void (A::*f_ptr)() = &A::f_fun;
  f_ptr = &A::f_fun;
  s_ptr();    //通过普通的函数指针可以直接调用类中的静态方法
  (a->*f_ptr)(); //通过类成员函数指针调用类中的成员方法,利用对象调用成员方式调用函数指针成员方法
  //============================================
  /*
  以下写法错误,涉及到运算符的优先级,如下几种写法,因括号优先级最高,编译是报错,正确写法附上所示
  a->*f_ptr(); or (a->*f_ptr()());报错:must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f_ptr (...)’, e.g. ‘(... ->* f_ptr) (...)’
  a->(*f_ptr)();报错:invalid use of unary ‘*’ on pointer to member
  */
  //============================================


  //函数内使用static修饰变量持久化
  int i;
  for(i = 0;i < 5;++i){
      a->last();
  }
  return 0;
}

<十>explcit关键字

  该关键字用来修饰单参或者除了第一个参数其余都是取胜参数的构造函数,避免构造函数进行隐式转化。

例如:

class A{

    public:

          explcit A(int i){n = i;}

         void print(){cout<<"n = "<<n<<endl;}

    private:

        int n;

};

int main(){

    A a(1);

    a.print();

  //此时因为构造函数被explcit修饰,不能隐士转化,如下不能使用此方法调用,否则会报错。

   //A b = 2;

    // b.print();

    return 0;

}

<十一>流操作符重载为什么返回引用

在程序中,流操作符>>和<<经常连续使用。因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用。其他的数据类型都无法做到这一点。所以返回引用仍旧保持相应的操作。
注意:除了在赋值操作符和流操作符之外的其他的一些操作符中,如+、-、*、/等却千万不能返回引用。因为这四个操作符的对象都是右值,因此,它们必须构造一个对象作为返回值。这样其自身在使用这些运算符操作室,作为左值从而将右值计算进来。

<十二>c++的初始化列表在什么情况使用。

  有三种情景需要使用初始化列表:

  1>当类中存在类数据成员(包含继承的情景),需要带类数据成员的构造函数来进行数据的初始化。

  2>类中有const修饰的类数据成员或普通数据成员,需要使用初始化列表(因为const修饰的成员是只读性,不能初始化作为左值来进行赋值操作,例如,不能在构造函数值使用=进行赋值)。

  3>子类需要初始化父类的私有成员,通过初始化列表显示(且只能显示)调用父类的构造函数进行初始化

<十三>c++默认无参构造跟拷贝构避坑

如图:

 使用中,结合实际情况,显示自己实现对应的拷贝构造函数,避免上图中的错误理论。

     

    

   

       

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++面试常见问题总结 的相关文章

  • PS 开启GPU加速图片处理

    还认为你的电脑的速度效果比不上苹果吗 xff1f 还在嫌电脑渲染速度慢吗 xff1f 试一下 xff0c 电脑开启GPU硬件加速吧 xff01 只要有独显轻松加速 xff08 毕竟苹果笔记本要配独显电脑的价格基本上在15000以上 xff0
  • 管道鸟cortex-M4(TM4C1294)

    看到满屏的贪吃蛇 xff0c 我也来开源一个Ti开发板 xff08 TM4C1294 xff09 的游戏 将简化版的管道鸟 xff0c 根据自己玩的经历 xff0c 在cortexm4开发板上重新撸了一边 xff0c 设计思路 xff1a
  • C#连接MYSQL数据库并进行查询

    之前用MFC开发结果界面太难看被pass了 要求用C 重新来开发 gt lt 不过终于摆脱VC6 0的蛋疼操作了Y 先来连接数据库 xff08 1 xff09 用c 连接MYSQL数据库需要用到mysql connector net xff
  • binascii.Error: Incorrect padding 报错解决

    输入的base64编码字符串必须符合base64的padding规则 当原数据长度不是3的整数倍时 如果最后剩下两个输入数据 xff0c 在编码结果后加1个 61 xff1b 如果最后剩下一个输入数据 xff0c 编码结果后加2个 61 x
  • 通过过滤器链了解spring security + oauth2实现单点登录的过程

    一 系统 注意部署在同一机器 xff08 localhost xff09 上的三个应用 xff0c 为了防止存放在cookie中的JSESSIONID不被覆盖 xff0c 需要设置不同的path xff0c 可以在配置文件中指定不同的上下文
  • jetson tx2开箱上电

    期待已久的jetson tx2终于到了 xff0c 来做一个开箱 jetson tx2是英伟达的第三代GPU嵌入式开发板 前两代分别是jetson tk1和jetson tx1 jetson tk1 xff1a 绿色的版板子接口丰富 jet
  • Jetson tx2刷机过程中的坑

    暑假各种事忙得差不多后 xff0c 终于有时间拿出早就申请到的tx2 xff0c 开始刷机教程 xff0c 这两天几乎踩边了所有的坑 第一个坑 xff0c 虚拟机 一般在安装VMware虚拟机时 xff0c 建议的安装空间20GB xff0
  • python词云实现

    python的一个蛮酷炫的功能是可以轻松地实现词云 github上有关于这个项目的开源代码 xff1a https github com amueller word cloud 注意跑例程时要删除里面的wordcloud文件夹 词云的功能有
  • docker中accessTokens拉取私有git仓库

    背景 当需要git clone拉取私有库时 xff0c 传统的做法为将本机的ssh配置到gitlab中 但在docker中执行程序时需要拉取私有库 xff0c 此时无法为每个docker容器配置ssh 网上的一种方案为 xff0c 将配置好
  • Docker世界 -- 进阶篇(入门)

    一 Docker Compose 1 1 Docker Compose 介绍 1 1 1 简介 xff1a 传统的 docker 服务 xff0c 我们一般通过编写 Dockerfile 文件 xff0c 通过 build 命令创建一个镜像
  • 树莓派pico CMake工程 直接添加 .c .h文件

    假设工程名test1 xff0c 带main 的源代码文件 main c xff0c 要往工程里添加oled c oled h之类的源代码 直接添加为可执行文件 xff1a 编辑工程根目录的 CmakeLists txt add execu
  • 张量的通俗理解

    1 关于张量的四种定义 张量 在不同的运用场景下有不同的定义 xff08 1 xff09 张量是多维数组 xff0c 这个定义常见于各种人工智能软件 听起来还好理解 xff08 2 xff09 张量是某种几何对象 xff0c 不会随着坐标系
  • 如何搭建node_exporter

    如何搭建node exporter 1 观看条件 1 假设你已经看过上一篇文章 如何搭建普罗米修斯 Prometheus 2 假设你已经会搭建普罗米修斯 xff08 promethus xff09 3 上面两个假设 xff0c 只要满足一个
  • python类中初始化形式:def __init__(self)和def __init__(self, 参数1,参数2,···,参数n)区别

    前言 这两种初始化形式 xff0c 就类似于C 43 43 类中的构造函数 形式1 def init self span class token keyword class span span class token class name
  • Go语言操作grpc详细使用

    Go语言操作grpc详细使用 零 参考链接一 protobuf的详细使用二 grpc与protobuf的go文件的生成1 安装两个插件2 写proto文件3 编译proto文件 xff0c 生成go文件 三 grpc的详细使用1 一元RPC
  • Steghide使用教程及其密码爆破

    Steghide使用教程及其密码爆破 工具介绍 Steghide是一款开源的隐写术软件 xff0c 它可以让你在一张图片或者音频文件中隐藏你的秘密信息 xff0c 而且你不会注意到图片或音频文件发生了任何的改变 而且 xff0c 你的秘密文
  • 一道Gloang并发、锁的面试题,你会吗?

    Gloang并发 锁的面试题 1 题目描述2 问题分析2 1问题一2 2问题二2 3问题三2 4问题四2 5问题五 3 问题解决方法4 代码实现4 1 map前后加锁的方式4 2 sync map解决方式 1 题目描述 源地址 xff1a
  • 阿里云、腾讯云centos7安装mysql

    阿里云 腾讯云centos7安装mysql 1 下载2 解压与准备3 安装4 配置4 1配置数据库4 2查看默认密码4 3启动mysql4 4设置密码 5 开启远程登录5 1开放3306端口5 2开启远程登录6 参考链接 1 下载 镜像网站
  • go语言gin、net/http的优雅关机

    gin net http的优雅关机 什么是优雅关机 xff1f 优雅关机的实现参考链接 什么是优雅关机 xff1f http server运行过程中 xff0c 若进程被关闭 xff0c 那么正在处理的请求可能只被处理了一半就停止了 xff

随机推荐

  • C语言不详细记录

    C记录 1 内存管理2 结构体内存对其规则3 字符串函数4 二维数组5 const 指针6 字符串7 图片记录8 函数指针 1 内存管理 C语言内存讲解 详说内存分布和heap空间 2 结构体内存对其规则 C语言结构体对齐规则 C语言 结构
  • 【web压测】压测常用工具、压测指标到底是什么?

    压测常用工具 压测指标到底是什么 xff1f 一 压测指标 I1 QPS xff0c 每秒查询2 TPS xff0c 每秒事务3 RT xff0c 响应时间 二 压测指标 II三 压测工具1 ab2 go wrk 在window上压测 一
  • C语言结构体字节对其规则简述

    C语言结构体字节对其规则简述 规则描述示例示例一示例二 字节对齐规则 xff0c 一直不是很理解 xff0c 网上的答案也是参差不齐 规则描述 首先 xff0c 预处理指令 pragma pack n 可以改变默认对齐数进行字节对齐 n 取
  • 【STM32学习】SysTick定时器(嘀嗒定时器)

    SysTick定时器 一 参考资料二 时钟源选择与定时时间计算1 时钟源选择2 定时时间计算 三 SysTick Handler中断服务函数 一 参考资料 嘀嗒定时器 xff1a 时钟源 寄存器 二 时钟源选择与定时时间计算 结合正点原子的
  • 【STM32学习】GPIO口的八种工作模式

    GPIO口的八种工作模式 一 参考资料二 GPIO八种模式1 输入模式2 输出模式 三 施密特触发器1 电路2 电路计算 一 参考资料 GPIO原理图详解 强烈建议观看 xff1a GPIO为什么这样设计 xff1f 施密特触发器 原理 施
  • 【STM32学习】WWDG窗口看门狗

    STM32学习 WWDG窗口看门狗 x1f415 1 图展示WWDG原理2 复位 中断条件3 溢出时间计算4 与独立看门狗 x1f415 的对比 1 图展示WWDG原理 2 复位 中断条件 产生复位的情况 xff1a 当递减计数器数值递减到
  • 【STM32学习】时钟配置详解

    STM32学习 时钟配置详解 看懂时钟图结合代码外部高速时钟修改 看懂时钟图 在刚开始学习32的时候 xff0c 并不会在意这些 xff0c 或者即使看了也看的不是很明白 随着学习的深入 xff0c 我们发现看门狗 定时器 ADC很多外设都
  • vnc远程访问ubuntu18.04桌面系统 vncserver开机自启动

    文章目录 一 windows端准备二 ubuntu端准备三 远程连接桌面四 配置vncserver开机自启动 一 windows端准备 下载TightVNC xff1a https www tightvnc com 二 ubuntu端准备
  • 【STM32学习】定时器寄存器配置、功能工作过程详解

    STM32学习 定时器寄存器配置 功能工作过程详解 零 参考一 引言二 功能以及寄存器说明1 最基本的定时功能 xff08 时基单元 xff09 1 1 框图1 2 工作流程1 3 寄存器介绍1 3 1 CR1寄存器1 3 2 CNT PS
  • 【STM32学习】实时时钟 —— RTC

    STM32学习 实时时钟 RTC 零 参考一 工作原理1 RTC介绍2 工作过程 二 相关寄存器三 代码说明1 rtc初始化2 关于中断3 中断配置代码 xff08 仅供参考 xff09 3 1 秒中断 43 普通闹钟功能3 2 待机模式唤
  • 【JLink仿真器】盗版检测、连接故障、检测不到芯片问题

    JLink仿真器 盗版检测 连接故障 检测不到芯片问题 一 问题描述二 解决方法1 降低驱动 xff08 解决非法问题以及连接故障 xff09 2 SWD引脚被锁 xff08 解决检测不到芯片 xff09 三 说明 一 问题描述 盗版检测
  • 【STM32学习】直接存储器访问——DMA

    STM32学习 直接存储器访问 DMA 零 参考一 对DMA的理解二 DMA通道优先级三 DMA通道x传输数量寄存器 DMA CNDTRx 四 DMA缓冲区设计 零 参考 一个严谨的STM32串口DMA发送 amp 接收 xff08 1 5
  • 【STM32学习】模数转换器——ADC

    STM32学习 模数转换器 ADC 零 参考一 ADC转换耗时二 转换模式三 对某些寄存器的理解1 ADC CR22 ADC SQRX 四 库函数注意事项 零 参考 STM32固件库 xff08 标准外设库 xff09 入门学习 第七章 A
  • 【面试】嵌入式C语言题目整理

    面试 嵌入式C语言题目整理 描述内存四区 内存四区分为 xff1a 代码区 静态区 堆区 栈区 代码区就是用来存放代码的 静态区用来存放全局变量 静态变量 常量 xff08 字符串常量 const修饰的全局变量 xff09 堆区中的内存是由
  • 【总线】IIC学习笔记

    总线 IIC学习笔记 参考链接IIC总线介绍IIC总线时序1 空闲信号2 启动信号与停止信号3 数据的有效性4 应答信号5 七位地址传输 IIC读写过程 xff08 AT24C02举例 xff09 IIC读过程IIC写过程 正点原子IIC驱
  • 树莓派下载及安装PyCharm软件

    运行 PyCharm 需要 Java 环境 xff0c 如果树莓派上还没有安装过 JRE xff0c 可以使用以下命令安装即可 xff1a sudo apt install default jre y PyCharm 有专业版和社区版 专业
  • QT 建立透明背景图像QPixmap

    列将下面背景透明图片1转变成图片2 图1 图2 span class hljs preprocessor include 34 mainwindow h 34 span span class hljs preprocessor includ
  • putty 登录出现Network error: connection time out 解决方案

    今天用putty登录我的linux主机 出现Networkerror connection time out 然后我从linux系统上登录 xff0c 当是没法联网 xff0c pingwww baidu com 则提示 xff1a pin
  • 大端字节序与小端字节序的转换

    逐步加深对字节操作的理解 xff0c 记录一下大端字节序与小端字节序的转换 xff0c 开发环境是vs2010 xff0c 项目类型是控制台输出程序 xff0c 下面是代码实现 xff1a span class token comment
  • c++面试常见问题总结

    近来在面试的过程 xff0c 发现面试官在c 43 43 方面总是喜欢问及的一些相关问题总结 xff0c 当时没怎么答出来 xff0c 或者是答的不怎么全面 xff0c 故而查询相关资料总结下 后面实际工作会进行实时更新信息 lt 一 gt