1、关键字 static 的作用是什么?
答:(1)设置变量的存储域,函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
(2)限制变量的作用域,在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3)限制函数的作用域,在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
2、局部变量能否和全局变量重名? 答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: "
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
3、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
答:
1) 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
2) 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
3) static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
综上所述:
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
4、一个由C/C++编译到程序占用的内存分为以下几个部分:
-
管理方式不同
栈是由编译器自动管理,不需要程序员手工控制;而堆需要程序员进行释放,如果不释放即有可能发生内存泄漏。 -
空间大小不同
-
能否产生碎片
频繁的new/delete的操作会造成对应内存空间的不连续,就会产生大量的碎片;而栈是先进后出队列,所以不会产生碎片问题。 -
生长方向不同
堆的生长方向向上,及地址越来越大;栈的生长方向向下,即地址越来越小。 -
分配方式不同
堆都是动态分配的,没有静态分配的堆;
栈有两种分配方式,可以动态分配,也可以静态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配与堆的动态分配不同,栈的动态分配是由编译器进行释放,无需程序员手工实现。 -
分配效率不同
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系 统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就 有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
前者是指向数组第一个元素的指针,后者是指向整个数组的指针。
7、字符串和数组有什么不同?
数组的元素可以是任意一种类型,长度可以使任意的,而字符串最后一个字符是‘\0’。
8、什么是回调函数?
回调函数是一个通过函数指针调用的函数,如果把函数指针传给另一个函数,当这个函数被用来调用它所指向的函数时,我们就说这个函数是回调函数。
C语言函数的返回值是通过函数中的return语句来实现的,但是每调用一次该函数,return语句只能返回一个值,所以当我们在编写C语言代码时,想返回多个返回值,直接用return语句是无法实现的。
1)利用全局变量:
全局变量的作用域是从定义变量开始到程序结束,所以对于编写多个返回值的C语言函数,我们可以考虑把要返回的多个值定义成全局变量当函数被调用时,全局变量被更改,再把更改后的全局变量应用于主调函数中。函数被调用后,被更改后的全局变量值即为函数所要返回的多个返回值。
注意点:该方法虽然可以实现有多个返回值的函数,但由于全局变量不能保证值的正确性(因为其作用域是全局,所以程序范围内都可以修改它程序间模块的耦合。的值,如果出现错误将很难发现),并且全局变量增加了
2)传递数组指针:
C语言函数参数的传递方法有值传递和地址传递。当进行值传递时,主调函数把实参的值复制给形参,形参获得从主调函数传递过来的值运行函数。在值传递过程中,被调函数参数值的更改不能导致实参值的更改。而如果是地址传递,由于传递过程中从实参传递过来的是地址,所以被调函数中形参值更改会直接导致实参值的更改。因此,可以把多个返回值作为数组元素定义成一个数组的形式,并使该数组的地址作为函数的形参,以传址方式传递数组参数。函数被调用后,形参数组元素改变导致实参改变,再从改变后的实参数组元素中获得函数的多个返回值。
3)传递结构体指针:
如果要返回的数个数值的数据类型不一致,可以把要求返回的数个数定义为一个结构体,然后传递结构体指针的方式把指针传递给形参结构体指针,函数中对形参结构体的修改也是对实参结构体的修改,函数被调用后获得的实参结构体成员即函数的多个返回值。
10、形参与实参
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。
2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
5.当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。
而如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身。所以在函数体内部可以改变实参的值。