面试真题 | 联想
联想嵌入式面经 手撕代码双指针 自我介绍技术特点,面试官主要看你主攻程序语言。(我是C) 然后着重询问程序语言的知识
@[toc]
static有什么用?
一、 static概述
Static,顾名思义是静态、静止的意思,个人理解的含义是私有、静态。
私有就是隐藏。
- static函数只能声明后的本文中调用
- static全局变量只能声明后的本文中调用
- static局部变量只能声明后的本函数调用
静态就是一直存在,相对于每次调用动态分配而言。
- static函数(未验证是否每次调用代码地址都是一致的)
- static全局变量生命周期到程序或进程结束;
- static局部变量生命周期到程序或进程结束。
二、static 全局变量和 static 局部变量的区别
static 全局变量和 static 局部变量在 C 或 C++ 中有几个关键的区别,主要体现在它们的可见性、生命周期以及存储位置等方面。以下是它们之间的主要差异:
可见性(Scope)
-
static 全局变量:尽管 static 全局变量的生命周期是整个程序的执行期间,但其可见性被限制在定义它的源文件中。这意味着其他源文件不能通过外部链接(external linkage)来访问这个变量。它对于其他源文件是隐藏的,只能在本源文件中被访问和使用。
-
static 局部变量:static 局部变量在函数内部定义,但其生命周期贯穿整个程序的执行期间。它们在函数外部是不可见的,即不能从函数外部直接访问。但是,在函数内部,它们可以在多次函数调用之间保持其值。
生命周期(Lifetime)
-
static 全局变量:static 全局变量的生命周期是整个程序的执行期间。从程序开始执行到程序结束,它们一直存在。
-
static 局部变量:同样,static 局部变量的生命周期也是整个程序的执行期间。与普通的局部变量不同,static 局部变量不会在函数返回时被销毁;它们的值在函数调用之间被保留。
存储位置(Storage)
-
static 全局变量:它们存储在程序的静态存储区(static storage area),通常是数据段(data segment)的一部分。这个区域在程序执行期间一直存在,并且其内容是持久的,直到程序结束。
-
static 局部变量:虽然它们的生命周期与全局变量相似,但 static 局部变量也存储在静态存储区。这意味着它们不会像普通的局部变量那样在栈上分配和释放。
用途
-
static 全局变量:通常用于在多个函数之间共享数据,同时又不希望这些数据被其他源文件访问。这有助于封装数据和限制数据的可见性。
-
static 局部变量:常用于需要跨函数调用保持状态的情况,比如计数器或缓存某些计算结果。通过 static 关键字,可以在不增加函数参数或使用全局变量的情况下实现这一点。
总结来说,static 全局变量和 static 局部变量在可见性、生命周期和存储位置等方面有所不同,但它们都通过 static 关键字延长了变量的生命周期,并提供了不同的方式来管理和控制变量的作用域和可见性。
static 局部变量非常适合用于需要跨函数调用保持状态的场景。例如,在编写一个用于计算某个操作发生次数的函数时,你可能希望每次调用这个函数时都能累加次数,而不是每次都从零开始计数。通过使用 static 局部变量作为计数器,你可以在多次函数调用之间维护这个计数。
三、static的好处是什么?
- 隐藏变量或函数、隔离错误,有利于模块化程序
在编程中,难免会用到全局变量,全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,全局变量在所有的源文件中都是有效的。如果希望全局变量仅限于在本源文件中使用,在其他源文件中不能引用,也就是说限制其作用域只在定义该变量的源文件内有效,而在同一源程序的其他源文件中不能使用,这时,就可以通过在全局变量上加static来实现,使全局变量被定义成一个静态全局变量。这样就可以避免其他源文件使用该变量、避免其他源文件因为该变量引起的错误。起到了对其他源文件隐藏该变量和隔离错误的作用,有利于模块化程序。
- 保持变量内容的持久性 有时候,我们希望函数中局部变量的值在函数调用结束之后不会消失,仍然保留函数调用结束的值。即它所在的存储单元不释放。
这时,应该将该局部变量用关关键字static声明为静态局部变量。当局部变量被声明为静态局部变量的时候,也就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区存放,全局变量也存放在静态存储区,静态局部变量与全局变量的主要区别就在于可见性,静态局部变量只在其被声明的代码块中是可见的。
- 默认初始化为 0 其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是 0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置 0,然后把不是 0 的几个元素赋值。
如果定义成静态的,就省去了一开始置 0 的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加 \0 太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是 \0 。
四、static的使用和作用
静态全局变量
-
使用:全局变量前加static,修饰全局变量为静态全局变量。
-
作用:改变全局变量的可见性。静态全局变量的存储位置在静态存储区,未被初始化的静态全局变量会被自动初始化为0。静态全局变量在声明它的文件之外是不可见的,仅在从定义该变量的开始位置到文件结尾可见。
静态局部变量
-
使用:局部变量前加static,修饰局部变量为静态局部变量。
-
作用:改变局部变量的销毁时期。静态局部变量的作用域和局部变量的作用域一样,当定义它的函数或语句块结束的时候,作用域结束。不同的是,静态局部变量存储在静态存储区,当静态局部变量离开作用域后,并没有被销毁。当该函数再次被调用的时候,该变量的值为上次函数调用结束时的值。
静态函数
-
使用:函数返回类型前加static,修饰函数为静态函数。
-
作用:改变函数的可见性。函数的定义和声明在默认情况下都是extern的,但静态函数只在声明它的文件中可见,不能被其他文件使用。
类的静态成员
-
使用:类成员前加static,修饰类的成员为类的静态成员。
-
作用:实现多个对象之间的数据共享,并且使用静态成员不会破坏封装性,也保证了安全性。
类的静态函数
-
使用:类函数前加static,修饰类的函数为静态函数。
-
作用:减少资源消耗,不需要实例化就可以使用。
局部变量和全局变量重名情况。
局部变量能否和全局变量重名?
能,局部会屏蔽全局。
当全局变量和局部变量同名时,在函数或代码块内,局部变量将会遮盖(覆盖)全局变量,即在代码块内使用该变量时,优先使用局部变量,而不是全局变量。
如果您需要在函数或代码块内使用全局变量,可以通过访问全局变量的方式来实现,例如在变量名前加上“global”关键字。
但是这种方式并不推荐,因为会破坏代码的可读性和可维护性,建议避免在同一作用域内使用同名变量。
在同一作用域内使用同名变量指的是在相同的代码区域内(即同一个函数、循环、条件语句等内部)
如何确定数组长度。
直接上代码!
使用关键字 sizeof。
# include <stdio.h>
int main(void)
{
int a[10] = {0};
int cnt = sizeof(a) / sizeof(a[0]);
printf("cnt = %d\n", cnt);
return 0;
}
使用库函数strlen
lenght = strlen(str);
使用while循环遍历计数
int i=0;
while(str[i++] != '\0');
这种问题一般很简单,主要想考的就是你的基础,和你的大脑灵活度,一般回答不止一两个方式,就是比较让面试官满意的结果了。
结构体占的空间如何计算。
一、结构体成员是基本类型
总体上遵循两个原则:
-
(1)、整体空间是占用空间最大的成员(的类型)所占字节数的整数倍。
-
(2)、数据对齐原则---内存按结构体成员的先后顺序排列,当排到该成员时,其前面已摆放的空间大小必须是该成员类型大小的整数倍,如果不够则补齐,依次向后类推。
char | 1 | 1 | |||
short | 2 | 2 | |||
int | 4 | 4 | |||
long int | 4 | 8 | |||
long long | 8 | 8 | |||
char * | 4 | 8 | |||
float | 4 | 4 | |||
double | 8 | 8 | |||
某台机器是32位,即这个机器上char 占1个字节,int占4个字节,double占8字节。
我们举个栗子:
struct A
{
char a;
double b;
int c;
char d;
};
那么,这个结构体占用多少字节呢?
- <1>、它的第一个成员是char 类型的 a,占 1 个字节。放入结构的0地址处:
- <2>、下来要存储的是第二个成员是double 类型的 b,占 8 个字节。它该怎么存放呢?
我们回想到原则(2)中说,存储到某个成员时,前面已经存放的所有成员所占的总空间大小是改成员大小的整数倍,不够则补齐!
也就是<1>图中显示的下一个存储成员起始地址应该是 8 的整数倍,而上图中显示的起始地址为 1 ,并不是 8 的整数倍,所以需要补齐。向后增加地址数到 8 (补齐操作),这时 8 是 8 的整数倍,可以存储。则将成员 b 存放到 8 地址处:
- <3>、下来要存储的是第三个成员是 int 类型的 c,占 4 个字节,由上图所知,下一个存储成员的起始地址是16,刚好是 4 的倍数。所以不用补齐,直接用 4 个字节来存储成员 c:
- <4>、最后存储的是第四个成员是 char 类型的 d,占 1 个字节。由上图所知,下一个存储成员的起始地址是20,刚好是 1 的倍数。所以不用补齐,直接用 1 个字节来存储 成员 d:
- <5>、把所有成员都存储到位,这就完了吗? No!我们还要考虑最后一个要素:原则(1),整体空间是占用空间最大的成员(的类型)所占字节数的整数倍!而这个结构的占用空间最大的成员是 double 类型的 b,占用 8 个字节。而现在整体空间由上图所知是 21 个字节,并不是 8 的倍数,所以仍需要补齐!补多少呢? 比 21 大的最小的 8 的倍数是 24,所以就补到 24 字节:
所以最终算下来,结构体 A 的大小是 24字节!
最后,我们再来用实际代码测试一下:
图片应该是0到7,0到15,0到23,这里不再重新绘图,各位一定能发现的
二、结构体成员是另外一个结构体时
之前的两个原则将做一些修改,我们把本结构体称为父结构体,
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
让实战与真题助你offer满天飞!!! 每周更新!!! 励志做最全ARM/Linux嵌入式面试必考必会的题库。 励志讲清每一个知识点,找到每个问题最好的答案。 让你学懂,掌握,融会贯通。 因为技术知识工作中也会用到,所以踏实学习哦!!!