zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

面试八股文

2023-04-18 15:02:56 时间
    • 普通局部变量:在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。普通局部变量存储于进程栈空间,使用完毕会立即释放。当定义它的函数结束时,其作用域也随之结束。
    • 静态局部变量:静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变
    • 全局变量:全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
      在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
    • 静态函数:函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下——
      • 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
      • 不同的文件可以使用相同名字的静态函数,互不影响
      非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明
    • 面向对象中的静态数据成员:存储在全局数据域,在定义时即分配了存储空间,是类的成员,不属于任何对象,在没有类的实例时其作用域就可见,在没有任何对象时就可以进行操作,对于这个类之存在一个拷贝——也就是在这个类下任一实例化的对象都可以对静态数据成员进行操作;而相对而言,非静态数据成员,每个对象都有自己的一份拷贝
    • 面向对象中的静态成员函数:属于整个类,不属于某个对象,没有this指针,无法访问属于类对象的非静态数据成员或成员函数,只能调用其余的静态成员函数,但非静态成员函数可以任意访问静态成员函数和静态数据成员
    • 来源:https://blog.csdn.net/guotianqing/article/details/79828100
    • C++面向对象的特征:封装、继承、多态。
      •   其中,封装可以隐藏实现细节,使得代码模块化;
      •   继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。
      •   而多态则是为了实现另一个目的——接口重用!

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

注意函数重载是C++语言特性,是静态的,和面向对象、多态无关,在编译器间就已经确定,而多态无法确定

 

java和C/C++区别:

1)java语言给开发人员提供了更为简洁的语法;取消了指针带来更高的代码质量;完全面向对象,独特的运行机制是其具有天然的可移植性;Java语言不需要程序对内存进行分配和回收。Java语言不使用指针,并提供了自动的废料收集,在Java语言中,内存的分配和回收都是自动进行的,程序员无须考虑内存碎片的问题。

2)C/C++开发语言,C语言更偏向硬件底层开发,C++语言是目前为止我认为语法内容最多的一种语言。c++用析构函数回收垃圾,C/C++在执行速度上要快很多,毕竟其他类型的语言大都是C开发的,更多应用于网络编程和嵌入式编程。

 

解释const

1)在定义的时候必须进行初始化

2)指针可以是const 指针,也可以是指向const对象的指针

3)定义为const的形参(形参是函数被调用时用于接收实参值的变量),在函数内部是不能被修改的

4)类的成员函数可以被声明为常成员函数,不能修改类的成员变量

5)类的成员函数可以返回的是常对象,即被const声明的对象

6)类的成员变量是常成员变量时,不能在声明时初始化,必须在构造函数的列表里进行初始化

const如何做到只读?

这些在编译期间完成,对于内置类型,如int, 编译器可能使用常数直接替换掉对此变量的引用。而对于结构体不一定(因为结构体类型不是内置数据类型,编译器不知道如何直接替换,因此必须要访问内存去取数据)。

static用法

1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用

4)类内的static成员变量属于整个类所拥有,不能在类内进行定义,只能在类的作用域内进行定义

5)类内的static成员函数属于整个类所拥有,不能包含this指针,只能调用static成员函数(“this”指针能找到对象的所有非静态成员变量的地址)

 

指针和引用的区别

1)引用是直接访问,指针是间接访问。

2)引用是变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间

3)引用绑定内存空间(必须赋初值),一个变量别名不能更改绑定,可以改变对象的值。

总的来说:引用既具有指针的效率,又具有变量使用的方便性和直观性

 

头文件中的 ifndef/define/endif 干什么用?

预处理,防止头文件被重复使用

 

关于静态内存分配和动态内存分配的区别及过程

1)静态内存分配是在编译时完成的,不占用CPU资源;动态分配内存运行时完成,分配与释放需要占用CPU资源;

2)静态内存分配是在栈上分配的,动态内存是堆上分配的;

3)动态内存分配需要指针或引用数据类型的支持,而静态内存分配不需要;

4)静态内存分配是按计划分配,在编译前确定内存块的大小,动态内存分配运行时按需分配。

5)静态分配内存是把内存的控制权交给了编译器,动态内存把内存的控制权交给了程序员;

6)静态分配内存的运行效率要比动态分配内存的效率要高,因为动态内存分配与释放需要额外的开销;动态内存管理水平严重依赖于程序员的水平,处理不当容易造成内存泄漏。

 

string的c++实现

class String{

public:
	//普通构造函数
	String(const char *str = NULL);

	//拷贝构造函数
	String(const String &other);

	//赋值函数
	String & operator=(String &other) ;

//析构函数
~String(void);
private:
	char* m_str;
};

  

//普通构造函数

String::String(const char* str){
    if(str==NULL) //如果str为NULL,存空字符串{
        m_str = new char[1]; //分配一个字节
        *m_str = ‘0′; //赋一个’′
    }
    else{
       str = new char[strlen(str) + 1];//分配空间容纳str内容
        strcpy(m_str, str); //复制str到私有成员m_str中
    }
}

//析构函数
String::~String(){
    if(m_str!=NULL){ //如果m_str不为NULL,释放堆内存
        delete [] m_str;
        m_str = NULL;
    }
}

//拷贝构造函数
String::String(const String &other){
    m_str = new char[strlen(other.m_str)+1]; //分配空间容纳str内容
    strcpy(m_str, other.m_str); //复制other.m_str到私有成员m_str中 
}

//赋值函数
String & String::operator=(String &other){
    if(this == &other) //若对象与other是同一个对象,直接返回本{
        return *this
}
    delete [] m_str; //否则,先释放当前对象堆内存
    m_str = new char[strlen(other.m_str)+1]; //分配空间容纳str内容
    strcpy(m_str, other.m_str); //复制other.m_str到私有成员m_str中
    return *this;

}