0. static有什么用途?(请至少说明两种)
- 1).限制变量的作用域,全局变量加上static之后全局变量的作用域是定义该变量的单个文件,而不加static的全局变量可以被同一个工程中的其他文件引用
- 2).设置变量的存储域。局部变量加上static之后变量的存储区由栈变为全局区(也可以成为静态区)
- 1) 引用必须被初始化,指针不必。
- 2) 引用初始化以后不能被改变,指针可以改变所指的对象。
- 2) 不存在指向空值的引用,但是存在指向空值的指针。
- 系统能及时响应外部事件的请求,在特定时间内完成特定的任务。具有多路性,独立性,及时性,交互性,可靠性等特点。
3. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
- 全局变量储存在静态数据库,局部变量在堆栈
4. 什么是平衡二叉树?
- 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1
5. 堆栈溢出一般是由什么原因导致的?
- (1)开辟的堆栈内存空间太大。(2)没有回收垃圾资源.
6. 什么函数不能声明为虚函数?
- 构造函数。因为构造函数必须构造一个实际存在的类,所以不能定义为虚函数
7. 冒泡排序算法的时间复杂度是什么?
- O(n^2)
8. 写出float x 与“零值”比较的if语句。
- if(x>0.000001&&x<-0.000001)
9. Internet采用哪种网络协议?该协议的主要层次结构?
- tcp/ip 应用层/传输层/网络层/数据链路层/物理层
10. Internet物理地址和IP地址转换采用什么协议?
- ARP (Address Resolution Protocol)(地址解析協議从IP地址到物理地址的映射)和RARP(逆地址解析协议,从物理地址到IP地址的映射)
11.IP地址的编码分为哪俩部分?
- IP地址由两部分组成,网络号netid和主机号hostid。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。
循环链表,用取余操作做。
- switch的参数不能为实型,包括:float,double,long double。
- 答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
- 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
- 答:extern。可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错
答:
- 可以,在不同的C文件中以static形式来声明同名全局变量。
- 在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
- 答:和while(1)相同。至于有什么问题,我想应该是这样的写法有点别扭,不常用,不太被人理解,执行效率上我网上查了一下说在现在的编译器上两者生成的汇编代码是一样的,所以应该没什么区别。
18、do……while和while……do有什么区别?
- 答:前一个循环一遍再判断,后一个判断以后再循环
19、请写出下列代码的输出内容
#include<stdio.h>
main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答:10,12,120
20、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
- 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
- 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
- static函数与普通函数作用域不同。一般来说不使用类的话是不会使用static函数的 。 一般使用static函数的类都基本上是想记录类对象被引用的次数或者这个函数地址需要被外部使用, 类似回调。
- static函数在内存区域中是在全局函数区, 而普通成员函数则是在代码区的累对象区域中。 调用类中的static函数时只需要前面加上类作用域区分符就可以了, 调用普通成员函数就需要加上类对象实例指针。类中的静态成员函数不能访问普通成员变量以及普通成员函数,但是可以访问静态成员变量和静态成员函数。因为静态成员函数是属于整个类的,所以他不能访问某个对象的 成员变量,因为它没有this指针,但是他可以访问静态成员函数和静态成员变量。另外static函数与普通函数作用域不同。static函数的作用域是文件级,普通函数的作用域是项目级。一般static函数都是用于类中,用于统计该类的对象的数目。
- 另外
- static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
- static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
- static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
21、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
22、设有以下说明和定义:typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:___52____
- 答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20
- data是一个struct, 每个变量分开占用空间. 依次为int(4) + DATE(20) + double(8) = 32.
- 所以结果是 20 + 32 = 52.
- 队列先进先出,栈后进先出
#include<stdio.h>
int inc(int a)
{
return(++a);
}
int multi(int*a,int*b,int*c)
{
return(*c=*a**b);
}
typedef int(FUNC1)(int in);
typedef int(FUNC2) (int*,int*,int*);
void show(FUNC2 fun,int arg1, int*arg2)
{
INCp=&inc;
int temp =p(arg1);
fun(&temp,&arg1, arg2);
printf("%d\n",*arg2);
}
main()
{
int a;
show(multi,10,&a);
return 0;
}
答:110
25、请找出下面代码中的错误
说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”
1、#include"string.h"
2、main()
3、{
4、 char*src="hello,world";
5、 char* dest=NULL;
6、 int len=strlen(src);
7、 dest=(char*)malloc(len);
8、 char* d=dest;
9、 char* s=src[len];
10、 while(len--!=0)
11、 d++=s--;
12、 printf("%s",dest);
13、 return 0;
14、}
答:
方法1:
- #include<string>
- #include<iostream>
- int main()
- {
- char*src="hello,world";
- char* dest=NULL;
- int len=strlen(src);
- dest=(char*)malloc(len+1);
- char* d=dest;
- char* s=&src[len-1];
- while(len--!=0)
- *d++=*s--;
- printf("%s",dest);
- free(dest);
- return 0;
- }
26.-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
- 第一题的答案应该是4^3-1=63
- 规律是n^3-1(当n为偶数0,2,4)
- n^3+1(当n为奇数1,3,5)
- 答案:63
设2个栈为A,B, 一开始均为空.
入队:
将新元素push入栈A;
出队:
(1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
(3)将栈B的栈顶元素pop出;
这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。
28.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么?
- 函数名: atol
- 功 能: 把字符串转换成长整型数
- 用 法: long atol(const char *nptr);
- 程序例:
- #include <stdlib.h>
- #include <stdio.h>
- int main(void)
- {
- long l;
- char *str = "98765432";
- l = atol(lstr);
- printf("string = %s integer = %ld\n", str, l);
- return(0);
- }
28.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
- c用宏定义,c++用inline
- PPP点到点连接
30.软件测试的种类
- 黑盒:针对系统功能的测试 白合:测试函数功能,各函数接口
33.确定模块的功能和模块的接口是在软件设计的那个队段完成的?
- 概要设计阶段
35.unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问p1+5= ;
p2+5= ;
- 答:此题不会,望大牛指点。
36.Ethternet链接到Internet用到以下那个协议?
A.HDLC;B.ARP;C.UDP;D.TCP;E.ID
答案:B,D
37.属于网络层协议的是:B,CA.TCP;B.IP;C.ICMP;D.X.25
38.Windows消息调度机制是:C
A.指令队列;B.指令堆栈;C.消息队列;D.消息堆栈;
40.请问下面程序有什么错误?
int a[60][250][1000],i,j,k;
for(k=0;k<=1000;k++)
for(j=0;j<250;j++)
for(i=0;i<60;i++)
a[i][j][k]=0;
- 答:把循环语句内外换一下
#define SQUARE(a)((a)*(a))
int a=5;
int b;
b=SQUARE(a++);
答:去掉++
43.TCP/IP通信建立的过程怎样,端口有什么作用?
三次握手,确定是哪个应用程序使用该协议
45.进程和线程的差别。
线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
46.测试方法
人工测试:个人复查、抽查和会审
机器测试:黑盒测试和白盒测试
47.Heap与stack的差别。
Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。
Stack空间有限,Heap是很大的自由存储区
C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行
48.Windows下的内存是如何管理的?
- 和大多数现代操作系统一样,Windows实现按需调页的虚拟内存机制。由于操作系统使用了虚拟内存,这就给应用程序造成了一个假象,以为计算机安装的内存远远超过自己所需要的数量。在32位的Windows计算机上,进程具有4GB的虚拟内存地址空间,操作系统通常会把这4GB的地址空间划分为进程和系统两个部分。因此,每个进程可以获得2GB的虚拟内存,根据可用的容量。分配给所有进程的虚拟内存总数不能超过页面文件和大多数物理内存的总和(操作系统本身也要占据一小部分物理内存)。
49.C/C++编译器中虚表是如何完成的?
To implement virtual functions, C++ uses a special form of late binding known as the virtual table. Thevirtual table is a lookup table of functions used to resolve function calls in a dynamic/late binding manner. The virtual table sometimes goes by other names, such as “vtable”, “virtual function table”, “virtual method table”, or “dispatch table”.
Because knowing how the virtual table works is not necessary to use virtual functions, this section can be considered optional reading.
The virtual table is actually quite simple, though it’s a little complex to describe in words. First, every class that uses virtual functions (or is derived from a class that uses virtual functions) is given it’s own virtual table. This table is simply a static array that the compiler sets up at compile time. A virtual table contains one entry for each virtual function that can be called by objects of the class. Each entry in this table is simply a function pointer that points to the most-derived function accessible by that class.
Second, the compiler also adds a hidden pointer to the base class, which we will call *__vptr. *__vptr is set (automatically) when a class instance is created so that it points to the virtual table for that class. Unlike the *this pointer, which is actually a function parameter used by the compiler to resolve self-references, *__vptr is a real pointer. Consequently, it makes each class object allocated bigger by the size of one pointer. It also means that *__vptr is inherited by derived classes, which is important.
By now, you’re probably confused as to how these things all fit together, so let’s take a look at a simple example:
01 | class Base |
02 | { |
03 | public : |
04 | virtual void function1() {}; |
05 | virtual void function2() {}; |
06 | }; |
07 | |
08 | class D1: public Base |
09 | { |
10 | public : |
11 | virtual void function1() {}; |
12 | }; |
13 | |
14 | class D2: public Base |
15 | { |
16 | public : |
17 | virtual void function2() {}; |
18 | }; |
Because there are 3 classes here, the compiler will set up 3 virtual tables: one for Base, one for D1, and one for D2.
The compiler also adds a hidden pointer to the most base class that uses virtual functions. Although the compiler does this automatically, we’ll put it in the next example just to show where it’s added:
01 | class Base |
02 | { |
03 | public : |
04 | FunctionPointer *__vptr; |
05 | virtual void function1() {}; |
06 | virtual void function2() {}; |
07 | }; |
08 | |
09 | class D1: public Base |
10 | { |
11 | public : |
12 | virtual void function1() {}; |
13 | }; |
14 | |
15 | class D2: public Base |
16 | { |
17 | public : |
18 | virtual void function2() {}; |
19 | }; |
When a class object is created, *__vptr is set to point to the virtual table for that class. For example, when a object of type Base is created, *__vptr is set to point to the virtual table for Base. When objects of type D1 or D2 are constructed, *__vptr is set to point to the virtual table for D1 or D2 respectively.
Now, let’s talk about how these virtual tables are filled out. Because there are only two virtual functions here, each virtual table will have two entries (one for function1(), and one for function2()). Remember that when these virtual tables are filled out, each entry is filled out with the most-derived function an object of that class type can call.
Base’s virtual table is simple. An object of type Base can only access the members of Base. Base has no access to D1 or D2 functions. Consequently, the entry for function1 points to Base::function1(), and the entry for function2 points to Base::function2().
D1’s virtual table is slightly more complex. An object of type D1 can access members of both D1 and Base. However, D1 has overridden function1(), making D1::function1() more derived than Base::function1(). Consequently, the entry for function1 points to D1::function1(). D1 hasn’t overridden function2(), so the entry for function2 will point to Base::function2().
D2’s virtual table is similar to D1, except the entry for function1 points to Base::function1(), and the entry for function2 points to D2::function2().
Here’s a picture of this graphically:
Although this diagram is kind of crazy looking, it’s really quite simple: the *__vptr in each class points to the virtual table for that class. The entries in the virtual table point to the most-derived version of the function objects of that class are allowed to call.
So consider what happens when we create an object of type D1:
1 | int main() |
2 | { |
3 | D1 cClass; |
4 | } |
Because cClass is a D1 object, cClass has it’s *__vptr set to the D1 virtual table.
Now, let’s set a base pointer to D1:
1 | int main() |
2 | { |
3 | D1 cClass; |
4 | Base *pClass = &cClass; |
5 | } |
Note that because pClass is a base pointer, it only points to the Base portion of cClass. However, also note that *__vptr is in the Base portion of the class, so pClass has access to this pointer. Finally, note that pClass->__vptr points to the D1 virtual table! Consequently, even though pClass is of type Base, it still has access to D1’s virtual table.
So what happens when we try to call pClass->function1()?
1 | int main() |
2 | { |
3 | D1 cClass; |
4 | Base *pClass = &cClass; |
5 | pClass->function1(); |
6 | } |
First, the program recognizes that function1() is a virtual function. Second, uses pClass->__vptr to get to D1’s virtual table. Third, it looks up which version of function1() to call in D1’s virtual table. This has been set to D1::function1(). Therefore, pClass->function1() resolves to D1::function1()!
Now, you might be saying, “But what if Base really pointed to a Base object instead of a D1 object. Would it still call D1::function1()?”. The answer is no.
1 | int main() |
2 | { |
3 | Base cClass; |
4 | Base *pClass = &cClass; |
5 | pClass->function1(); |
6 | } |
In this case, when cClass is created, __vptr points to Base’s virtual table, not D1’s virtual table. Consequently, pClass->__vptr will also be pointing to Base’s virtual table. Base’s virtual table entry for function1() points to Base::function1(). Thus, pClass->function1() resolves to Base::function1(), which is the most-derived version of function1() that a Base object should be able to call.
By using these tables, the compiler and program are able to ensure function calls resolve to the appropriate virtual function, even if you’re only using a pointer or reference to a base class!
Calling a virtual function is slower than calling a non-virtual function for a couple of reasons: First, we have to use the *__vptr to get to the appropriate virtual table. Second, we have to index the virtual table to find the correct function to call. Only then can we call the function. As a result, we have to do 3 operations to find the function to call, as opposed to 2 operations for a normal indirect function call, or one operation for a direct function call. However, with modern computers, this added time is usually fairly insignificant.