-
1
、
“
引用
”
与指针的区别是什么?
答
、
1)
引用必须被初始化,指针不必。
2)
引用初始化以后不能被改变,指针可以改变所指的对象。
3)
不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变
量指向一个对象后,对它所指向的变量间接操作。程
序中使用指针,程序的可
读性
差;而
引用本身就是目标变量的别名,对引用的操作就是对目标变量的操
作。
< br>
流操作符
<<
和
>>
、赋值操作符
p>
=
的返回值、拷贝构造函数的参数、赋值操作符
=
的参数、其它情况都推荐
使用引用
2
p>
、
#include
与
#include
的区别?
答:前者是从
Standard
Library
的路径寻找和引用
file.h
,而后者是从当前工作
路径搜寻并引用
file.h
。
3
、全局变量和局部变量在内存中是
否有区别?如果有,是什么区别?
答
:全局变量储存在静态数据区,局部变量在堆栈中。
4
p>
、堆栈溢出一般是由什么原因导致的?
答
:
1.<
/p>
没有回收垃圾资源
2.
层次太深的递归调用
5
、不能做
switch()
的参数类型
答
:
switch
的参数不能为实型。
6
、如何
引用一个已经定义过的全局变量?
答
、可以用引用头文件的方式,也可以用
extern
关键字,如果用引用头文件
方式来引用某个在头文件中声
明的全局变量,假定你将那
个变量写错了,那么
在编译期间会报错,如果你用
extern
方式引用时,假定你
犯了同样的错误,
那么在编译期间不会报错,而在连接期间报错
。
7
、语句
for(
;
1
;
)
有什么问题?它是什么意思?
答
、和
while(1)
相同,无限循环。
8
、
statac
全局变量、局部变量、函数与普通全局变量、局部变量、函数
static
全局变量与普通的全局变量有什么区别?
static
局部变量和普通局部变量有什
么区别?
sta
tic
函
数与普通函数有什么区别?
答
、全局变量
(
外部变量
)
的说明之前再冠以
p>
static
就构成了静态的全局变量。
全
局变量本身就是静态存储
方式,静态全局变量当然也是静态存储方式。
这
两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是
整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源
文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的
源文件内有效,在同一源程序的其它
源文件中不能使用它。
由于静态全局变量
的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可
以避免
在其它源文件中引起错误。从以上分析可以看出,把局部变量改变为静态变量
p>
后是改变了它的存储方式即改变了它的生存期。把全局变
量改变为静态变量后
是改变了它的作用域,限制了它的使用范围。
static
函数与普通函数作用域不
同。
仅在本文件。只在当前源文件中使用的函数应该说明为内部函数
(static)
,
内部函数应该在当前源文件中说明和定义
。对于可在当前源文件以外使用的函
数,应该在一个头
文件中说明,要使用这些函数的源文件要包含这个头文件
static
全局变量与普通的全局变量有什么区别:
static
全局变量只初使化一次,
防止在其他文件单元中被
引用
; static
局部变量和普通局部变量有什么区别:
static
局部变量只被初始化一次,下一次依据上一次结果值;
static
函数与普通函数有什么区别:
static
< br>函数在内存中只有一份,普通函数在
每个被调用中维持一份拷贝。
9
、解释堆和栈的区别
答:堆(
heap
< br>)和栈
(stack)
的区别
(
1
)申请
方式
stack:
由系统自动分配。
例如,声明在函数中一个局部变量
int
b;
系统自动在栈中为
b
开辟空间
heap:
需要程序员自己申请,并指明大小,在
c
中
malloc
函数
如
p1=(char*)malloc(10);
在
C++
中用
new
运算符
如
p2=(char*)malloc(10);
但是注意
p1
、
p2
本身是在栈中的。
(
2
)申请后系统的响应
<
/p>
栈:只要栈的剩余空间大于所申请空间,系统将为程
序提供内存,
否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记
录空闲内存地址的链表,
当系统收到程序的申请时,会遍历该链表,寻找第一
个空间大于所申请空间的堆结点,然
后将该结点从空闲结点链表中删除,并将
该结
点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首
地址处
记录本次分配的大小,这样,代码中的
delete
语句才能正
确的释放本内
存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统
会
自动的将多余的那部分重新放入空闲链表中。
(
3
)申请
大小的限制栈:在
Windows
下
,
栈是向低地址扩展的数据结构,是一
块连续的内存的区域。这句话的意思是栈顶的地址
和栈的最
大容量是系统预先
规定好的,在
WINDOWS
下,栈的大小是
2M
(也有的说是
< br>1M
,总之是一个
编译时
p>
就确定的常数)
,如果申请的空间超过栈的剩余空间时,将提示
p>
overflow
。因此,能从栈获得的
空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内
存区域。这是由于系统是用
链表来存储的空闲内存地址的,自然是不连续的,而链表的遍
历方向是由低地
址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,
堆获
得的空间比较灵活,也比较大。
(
4
)申请效率的比较:栈
:
由系统自动分配,速度较快。但程序员是无法控制
的。
堆
:
是由
new
分配的内存,一般速度比较慢,而且容易产生内存碎
片
,
不过
用起来最方便
.
另外,在
WINDOWS
下,最好的方式是用
Virtual Alloc
分配
内存,他不是在堆,也不是在栈
,
而是直接在进
程的地址空间中保留一块内
存,虽然用起来最不方便。但是速度快,也最灵活。
(
5
)堆和
栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中
后的
下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个
参数,在大多数的
C
编译器中,参数是由右往左入栈的,然后是函数中的局
部变量。注意
静态变量是不入栈的。当本次函数调用结束后,局部变量先出
栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一
条
指令,程序由该点继续运行。堆:一般是在堆的头部用一个字节存放堆的大
小。堆中的具
体内容由程序员安排。
(
6
)存取效率的比较
char
s1[]=
是在运
行时刻赋值的;而
bbbbbbbbbbb
是在编译时就确定的;
但是,在以后
的存取
中,在栈上的数组比指针所指向的字符串
(
例如堆
)
快。比如:
void main()
{
char a=1;
char c[]=
char *p=
a =
c[1];
a = p[1];
return;
}
对应的汇编代码
10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:
a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
FCmovbyteptr[ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器
cl
中,而第二种则
要先把指针值读
到
edx
中,在根据
e dx
读取字符,显然慢了。
10
、关键字
const
是什么含意?
答:我只要一听到被面试者说:
const
< br>意味着常数
?
,我就知道我正在和一个业
余者打交道。去年
Dan Saks
已经在他的文章里完全概括了
const
的所有用
法,因此
ESP(
译者:
Embedded
Systems Programming)
的每一位读者应该非常熟
< br>悉
const
能做什么和不能做什么
.
如果你从没有读到那篇文章,只要能说出
const
意味着
?
只读<
/p>
?
就可以了。尽管这个答案不是完全的答案,但我接受它作为一个
正确的答案。
(如果你想知道更详细
的答案,仔细读一下
Saks
的文章吧。
)
如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是
什么意思
?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,
a
是一个常整型数。第三个意
味着
a
是一个指向常整型
数的指针(
也就是,整型数是
不可修改的,但指针可以)
。第四个意思
a
是一
p>
个指向整型数的常指针(也就是说,指针指向的整型数是可以
p>
修改的,但指针
是不可修改的)
。最后一个
意味着
a
是一个指向常整型数的常
指针(也就是
说,指针指向的整
型数
是不可修改的,同时指针也是不可修改的)
。如果应试
者能正确
回答这些问题,那么他就给我留下了一个
好印象。顺带提一句
,也许
你可能会问,即使不用关键字
const
,也还是能很容易写出功能正确的程序,
那么我为什
么还要如此看重关键字
const
呢?我也如下的几下理由:
1).
关键字
const
的作用是为给读你代码的人传达非常有用的信息,
实际上,
声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多<
/p>
时间清理其它人留下的垃圾,你就会很快学会感谢这点多余
p>
的信息。
(当然,
懂得用
< br>
const
的程序员很少会留下的垃圾让别人来清理
的。
)
2).
通过给优化器一些附加的信息,使用关键字
const
也许能产生更紧凑的代
码。
3).
合理地使用
关键字
const
可以使编译器很自然地保护那些不希望被改变
的参
数,防止其被无意的代码修
改。简而言之,这样可以减少
bug
的出现
11
、三种基本的数据模型
答:按照数据结构类型的不同,将数据模型划分为层次模型、
网状模型和关系
模型。
12
、描述内存分配方式以及它们的
区别
?
答:
1
)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存
在程序的整个运行期间都存在。例如全局变量,
static
变量。
2
)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创
建,函数执行结束时这些存储
单元自动被释放。栈
内存分配运算内置于处理器
的指令集。
3
)从堆上分配,亦称动态内存分配
。程序在运行的时候用
malloc
或
new
申请
任意多少的内存,程序员自己负责在何时用
free
或
delete
释放内存。动态内
存的
生存期由程序员决定,使用非常灵活,但问题也最多。
13
、简述数组与指针的区别?
答:数组要么在静态存储区被创建(如全局数组)
,要么在栈上被创建。指针可
以随时指向任意类型的内存块。
(1)
修改内容上的差别
char a[] =
“hello”;
a[0] = ‘X’;
char *p =
“world”; //
注意
p
指向常量字符串
p[0] =
‘X’; //
编译器不能发现该错误,运行时错误
(2)
用运算符
sizeof
可以计算出数组的容量(字节数)
。
sizeof(p),p
为指针得到的
是一个<
/p>
指针变量的字节数,而不是
p
所指的内存容量。
C++/C <
/p>
语言没有
办法知道指针所指的内存容量,除非在申请内存时记
p>
住它。注意当数组作
为函数的参数进行传
递时,该数组自动退化为同类型的指针。
char a[] =
char *p = a;
cout<< sizeof(a) << endl;
// 12
字节
cout<< sizeof(p) << endl;
// 4
字节
计算数组和指针的内存容量
void
Func(char a[100])
{
cout<<
sizeof(a) << endl; // 4
字节而不是
100
字节
}
14
、如何判断一段程序是由
C
编译程序还是由
C++
编译程序编译的?
答:
#ifdef
__cplusplus
cout<<
#else
cout<<
#endif
15
、用两个栈实现一个队列的功能
?要求给出算法和思路!
答、设
2
个栈为
A,B,
一开始均为空。
入队
:
将新元素
push
入栈
A;
出队
:
(1)
判断栈
B
是否为空;
(2)
如果不为空,则将栈
A
中所有元素依次
pop
出并
push
到栈
B
;
(3)
将栈
B
的栈顶元素
pop
出;这样实现的队列入
队和出
队的平摊复杂度都还是
O(1),
比上面的几种方法要好。
16
、位操作(
Bit
manipulation
)
答:
嵌入
式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量
a
,写两段代码,第一个设置
a
的
bit 3
,第二个清除
a
的
bit 3
。在以上两个
操作中,要保
持其它位不变。
对这个问题有三种基本的反应
p>
1)
不知道如何下手。该被面者从没做过任何嵌入式系统的工作。<
/p>
2)
用
bit
fields
。
Bit fields
是被扔到
C
语言死角的东西,它保证你的代码在不
同编译器之间是不可移植的,同时也保证了的你
的代码是不可重用的。我最近
不幸看到
Infineon
为其较复杂的通信芯片写的驱动
程序,它用到了
bit
fields
因此完全对我无用,因为我的编译器用其它的方式来实现
bit
fields
的。从
道
德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。
3)
用
#defines
和
bit masks
操作。这是一个有极高可移植性的方法,
是应该被
用到的方法。最佳的解决方案如下:
#define BIT3 (0x1 << 3)
static int a;
void
set_bit3(void)
{
a
|= BIT3;
}
void clear_bit3(void)
{
a
&= ~BIT3;
}
p>
一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也
是可以接受的。我希望看到几个要点:说明常数、
|=
和<
/p>
&=~
操作。
p>
17
、中断(
Interrupts
)
答:中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种
扩展
—
让标准
C
支持中断。具
代表事实是,产生了一个新的关键字
__interrupt
。下面的代码就使用了
__inter
rupt
关键字去定义了一
个中断
服务子
程序
(ISR)
,请评论一下这
段代码的。
__interrupt double compute_area (double
radius)
{
double area = PI * radius *
radius;
printf(
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:
1)ISR
不能返回一个值。如果你
不懂这个,那么你不会被雇用的。
2)ISR
不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一
项。
3)
在许多的处理器
/
编译器中,浮点一般都是不可
重入的。有些处理器
/
编
译器需要让额
处的寄存器入栈,有些处理器
/
编译器就是不允许在
ISR
中做浮点
运算。此外,
ISR
应该是短而有效率的,在
ISR
< br>中做浮点运算
是不明智的。
4)
与第三点一脉相承,
printf()
经常有重入和性能上的问题。如果你丢掉了
第三和第四点,我不会太为难
你的。不用说,如
果你能得到后两点,那么你的
被雇用前景越来越光明了。
18
、
Typedef
答:
Ty
pedef
在
C
语言中频繁用以声明一
个已经存在的数据类型的同义字。也
可以用预处理器做类似的事。例如,思考一下下面的
例子:
#define dPS
struct s *
typedef struct s
* tPS;
以上两种情况的意图都是要定义
dPS
和
tPS
作为一个指向结构
s
指针。
哪种方法更好呢?(如果有的话)为什么?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被
恭喜的。答案是:
typedef
更好。
思考下面的例子:
dPS
p1,p2;
tPS p3,p4;
第一个扩展为
struct s * p1, p2;
上面的代码定义
p>
p1
为一个指向结构的指,
p2
为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了
p3
和
p4
两个指针。
19
、
A.c
和
B.c
两个
c
文件中使用了两个相同名字的
static
变量
,
编译的时候会
不会有问题?这两个
static
变量会保存到哪里(栈还是堆或者其他的)
?
答:
static
的全局变量,表明
这个变量仅在本模块中有意义,不会影响其他模块。
他们都放在数据区,但是编译器对他
们的命名是不同的。如果要使变量在其他
模块也有意义的话,需要使用
< br>extern
关键字。
20<
/p>
、下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts(
}
这个问题测试你是否懂得
C
语言中的整数自动转换原则,我发现有些开发者
懂得极少这些东西。不
管如何,这无符号整型问题的答案是输出是
< br>。原因
是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无
符
号类型。因此
-20
变成了一个非
常大的正整数,所以该表达式计算出的结果大
于
6
。这一点对
于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要
的。如果你答错了这个问
题,你也就到了得不到这份工作的边缘。
21
、
C
语
言同意一些令人震惊的结构
,
下面的结构是合法的吗,如果是它
做些什
么?
int a = 5, b = 7, c;
c = a+++b;
这个问题将
做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是
完全合乎语法的。问题
是编译器如何处理它?水平不高的编译作者实际上会争
论这个问题,根据最处理原则,编
译器应当能处理尽可能所有合法的用法。因
此,上面的代码被处理成:
< br>
c = a++ + b;
因此
,
这段代码持行后
a = 6, b
= 7, c =
12
。
如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不
把这个当作问题。我发现这个问题的最大好处是这是一个关于代码编写风格,
代码的可读
性,代码的可修改性的好的话题。
5
、请写出下列代码的输出内容
#include
int main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf(
< br>,
c
,
d
:
%d
,
%d
,
%d
,
b
,
c
,
d
)<
/p>
;
return 0;
}
-
-
-
-
-
-
-
-
-
上一篇:黑客编程
下一篇:统编九年级英语Unit5知识点总结