1、static有什么用途?
在C语言中,static主要定义全局静态变量,定义局部静态变量,定义静态函数
限制变量的作用域,设置变量的存储域。
static 关键字主要有两种作用:
第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。具体而言,在Java语言中,static 主要有 4 种使用情况:成员变量、成员方法、代码块和内部类。
定义全局静态变量 :在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点:
(1) 在全局数据区内分配内存
(2) 如果没有初始化,其默认值为0
(3) 该变量在本文件内从定义开始到文件结束可见
定义局部静态变量:在局部静态变量前面加上关键字static,该局部变量便成了静态局部变量。静态局部变量有以下特点:
(1) 该变量在全局数据区分配内存
(2) 如果不显示初始化,那么将被隐式初始化为0
(3) 它始终驻留在全局数据区,直到程序运行结束
(4) 其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。
定义静态函数:在函数的返回类型加上static关键字,函数即被定义成静态函数。静态函数有以下特点:
(1) 静态函数只能在本源文件中使用
(2) 在文件作用域中声明的inline函数默认为static
说明:静态函数只是一个普通的全局函数,只不过受static限制,他只能在文件坐在的编译单位内使用,不能呢个在其他编译单位内使用。
在C++语言中新增了两种作用:定义静态数据成员或静态函数成员
(1) 定义静态数据成员。静态数据成员有如下特点:
内存分配:在程序的全局数据区分配
初始化和定义:静态数据成员定义时要分配空间,所以不能在类声明中定义
(2) 静态成员函数。静态成员函数与类相联系,不与类的对象相联系。静态成员函数不能访问非静态数据成员。原因很简单,非静态数据成员属于特定的类实例,主要用于对静态数据成员的操作。
静态成员函数和静态数据成员都没有this指针。
2、引用与指针的区别?
指针和引用
指针:指针就是内存地址,指针变量是用来存放内存地址的变量。不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。
引用:引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间.
类型& 引用变量名= 引用实体; 且引用类型必须和引用实体是同种类型的.
引用的主要用途是:修饰函数的形参和返回值.
在C++语言中,函数的参数和返回值的传递方式有三种:值传递,指针传递和引用传递.引用具有指针的效率,又具有变量使用的方便性和直观性.
实际上引用可以做的事,指针都可以做,为什么还要引用呢?
引用体现了最小特权原则,即给予程序元素完成其功能的最小权限. 指针能够毫无约束的操作内存中的任何东西,尽管功能强大,但是非常危险.
区别
1、初始化:引用在定义时必须初始化,指针则没有要求(尽量初始化,防止野指针)
2、引用在初始化引用一个实体后,就不能再引用其它实体,而指针可以在任意时候指向一个同类型实体
3、没有NULL引用,但是有nullptr指针
4、在sizeof中含义不同: 引用结果为引用类型的大小,但指针始终是地址空间,所占字节个数(32位平台占4个字节)
5、引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6、有多级指针,但没有多级引用
7、访问实体的方式不同:指针需要显式解引用,引用编译器自己处理
7、引用比指针使用起来相对安全
3、描述实时系统的基本特征
在特定时间内完成特定的任务,实时性和可靠性。
实时操作系统(RTOS) 是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系 统作出快速响应,并控制所有实时任务协调一致运行的操作系统。因而,提供及时响应和高可靠性是其主要特点。实时操作系统有硬实时和软实时之分,硬实时要求 在规定的时间内必须完成操作,这是在操作系统设计时保证的;软实时则只要按照任务的优先级,尽可能快地完成操作即可。我们通常使用的操作系统在经过一定改 变之后就可以变成实时操作系统。
分时操作系统使一台计算机同时为几个、几十个甚至几百个用户服务的一种操作系统。把计算机与许多终端用户连接起来,分时操作系统将系统处理机时间与内存空 间按一定的时间间隔,轮流地切换给各终端用户的程序使用。由于时间间隔很短,每个用户的感觉就像他独占计算机一样。分时操作系统的特点是可有效增加资源的 使用率。例如UNIX系统就采用剥夺式动态优先的CPU调度,有力地支持分时操作。
4、全局变量和局部变量在内存中是否有区别?什么区别?
全局变量存储在静态数据库,局部变量存储在栈。
局部变量(Local Variable):定义在函数体内部的变量,作用域仅限于函数体内部。离开函数体就会无效。再调用就是出错。
全局变量(Global Variable):定义:所有的函数外部定义的变量,它的作用域是整个程序,也就是所有的源文件,包括.c和.h文件。
5、什么是平衡二叉树?
左右子树都是平衡二叉树且左右子树的深度差值的绝对值不大于1.
6、栈溢出一般是由什么情况导致的?
没有回收垃圾资源。
堆栈工作方式:
堆栈是一个特定的存储区或寄存器,它的一端是固定的,另一端是浮动的 ,也就是所有操作均在堆栈顶端进行,遵循“先进后出”的特征。
原理说明:
2.1:堆区栈区内存分配原则
·栈顶的地址和栈的最大容量是由系统预先规定的,只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常来提示栈发生溢出。
·堆区是由程序员自己申请,指明大小,程序最后进行释放,若程序员不释放,程序结束时可能由操作系统回收(注意,如果是C/C++语言,程序不进行对空间回收,而Java语言中有专门的垃圾回收器进行回收)。
2.2:溢出原理:
堆栈溢出是说堆区和栈区的溢出,二者同属于缓冲区溢出。从上面关于堆区和栈区的解释可以看出,一旦程序确定,堆栈内存空间的大小就是固定的,当数据已经把堆栈的空间占满时,再往里面存放数据就会超出容量,发生上溢;当堆栈中已经没有数据时,再取数据就无法取到了,发生下溢。
3.原因分析:
3.1:堆栈尺寸设置过小:
由堆栈溢出的定义便可知,堆栈尺寸设置过小时,其能储存的内容过小,容易发生溢出。
3.2:递归层次太深或函数调用层次过深导致堆栈溢出
函数递归调用时,系统要在栈中不断保存函数调用时的现场和产生的变量,如果递归调用太深,保存的调用现场和变量太多,当超过栈的空间长度时,即发生溢出就会造成栈溢出,这时递归无法返回。再有,当函数调用层次过深时也可能导致栈无法容纳这些调用的返回地址而造成栈溢出。
int A(int i)
{
if(递归终止条件)
{
return 0;//中止递归
}
else
{
for()
{
A();//使用循环进行递归
}
}
}
这样的递归结构在for循环次数过多,且递归中止条件一直无法满足时,栈内存就会产生溢出。
int B (int j);
int A(int i)
{
if(递归终止条件)
{
return 0;//中止递归
}
else
{
B();
}
}
int B(int j)
{
for()
{
A();
}
}
对比两种结构,一种是不断递归,第二种是将循环部分放到另一个函数中,当程序进入B()函数后,A()函数就已经结束了,它占用的栈内存就可以得到释放,所以不会产生过多的函数嵌套。
3.3:动态申请空间使用之后没有释放。
对于C语言,由于没有垃圾资源自动回收机制,因此,需要程序主动释放已经不再使用的动态地址空间,如果不释放,程序结束后该部分空间依然存在,还可以继续访问,也就是说这部分依然占据着堆空间,剩余的堆空间减少,就可能造成堆区溢出。
3.4:数组访问越界。
C语言没有提供数组下标越界检查,如果在程序中出现数组下标访问超出数组范围,在运行过程中可能会内存访问错误。
3.5:指针非法访问。
指针保存了一个非法的地址,通过这样的指针访问所指向的地址时会产生内存访问错误。
总结:
堆栈溢出其实可以细分为堆溢出和栈溢出,在通常情况下会有如下情况(对应了前面讲的原因中的前三点,后两点为内存访问错误的情况):
1.堆溢出:不断的new 一个对象,一直创建新的对象,
2.栈溢出:死循环或者是递归太深,递归的原因,可能太大,也可能没有终止。