C/C++指针
int a; int* p = &a; // 指向a地址的指针*p
1、与const一起的时候 char * const p; // 指针不可变,也就是指针只能指向一个地址char* p的指针; char const * p; // 所指内容不可改,也就是p是常量字符串 char const * const p; // 内容和指针都不能改 const char * const p; // 同上...内容和指针不能改 2、str[]和str的区别
#include <iostream>
using namespace std;
int main()
{
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
}
结果是0011, 这可是说是一个深拷贝/浅拷贝的问题.当字符串是数组形式声明并初始化,编译器认为是新数组,分配新空间,但不是深拷贝,因为根本就不算拷贝.而如果是相同的字符串,用指针声明,那就是比较如果有一样的字符串,就直接把新指针指过去,这是正宗的浅拷贝.
3、str[]用sizeof判断会出错么?
#include <iostream>
using namespace std;
int MyStrlen( char str[] )
{
return ( int )( sizeof( str ) - 1 );
}
int main()
{
char str[] = "mimiasd";
cout << MyStrlen( str ) << endl;
}
无论何时,返回的总是3。当用函数传递的数组指针的时候就自动退化为指针了,而指针的长度是4,减去1自然就是3.但是如果按照下面代码就可以得到正常的值:
char str[] = "mimiasd";
int len = sizeof( str ) - 1; // 减1是为了去掉'/0'。
cout << len << endl; // 结果为7。
4、注意数组指针和指针
#include <iostream>
using namespace std;
int main()
{
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int *ptr = ( int* )( &a + 1 );
cout << *( a + 1 ) << " " << *( ptr - 1 ) << endl;
}
答案是2 5,首先,a是一个数组,所以编译器解释&a就是a的全部长度,就是说(&a+1)也就是说移动了一个数组,指向了并不存在的a[5],所以ptr-1才会指向a数组的最后一个元素a[4],而a+1和a[1]是一样的...所以答案是25,如果你去掉了(&a+1)的括号,那么答案就是想当然的21了。
5、注意指针要分配给足够的空间
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char a;
char *str = &a;
strcpy( str, "hello" );
cout << str << endl;
}
运行输出后程序因为访问了没有分配的空间,当然崩溃了.如果你只strcpy(str,"");那程序是可以正常运行的.
6、小心编译器的指针字符串初始化
#include <iostream>
using namespace std;
int main()
{
char *s = "AAA";
cout << s << endl;
s[ 0 ] = 'B';
cout << s << endl;
}
这段程编译器报告正常, 输出AAA后报错,因为当在第一句初始化的时候,编译器就认为这是个字符串常量了...再做数组操作的时候肯定错了罗...最好的习惯是声明一个指针,用new分配空间,然后用库函数操作,比如strcpy,strcat等等...
7、让人一眼看上去迷糊的函数指针
int ( *s[ 10 ] )( int );
其实这是一个函数指针数组,指向了一组int fun(int)的函数,第一眼确实让人有点迷糊...但是请习惯这样...
8、注意函数传递指针的时候的副本
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
void GetMemory( char *p )
{
p = new char[ 100 ];
strcpy( p, "hello world" );
}
int main()
{
char *str = NULL;
GetMemory( str );
cout << str;
delete [] str;
str = NULL;
}
原因很简单...GetMemory这个函数出问题了!函数参数是不能传递分配空间的...因为传递过去实际上是一个副本p...不能返回的...而且你在delete那就是件很危险的。
可以如下修改代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
void GetMemory( char **p )
{
*p = new char[ 100 ];
strcpy( *p, "hello world" );
}
int main()
{
char *str = NULL;
GetMemory( &str );
cout << str;
delete [] str;
str = NULL;
}
9、请时刻记住要初始化字符串
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char a[ 10 ];
cout << strlen( a ) << " " << sizeof( a ) << endl;
}
输出是2 10。其实strlen函数的结果和是否初始化有关的...虽然你分配了空间..但是没有初始化..库函数会出错的..sizeof不受影响...切忌初始化哦....
10、小括号、大区别 char (*str)[20]; // str是一个数组指针,即指向数组的指针. char *str[20]; // str是一个指针数组,其元素为指针型数据.
#include <iostream>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
using namespace std;
typedef struct AA
{
int b1:5;
int b2:2;
} AA;
int main()
{
AA aa;
char cc[ 100 ];
strcpy( cc, "0123456789abcdefghijklmnopqrstuvwxyz" );
memcpy( &aa, cc, sizeof( AA ) );
cout << aa.b1 << endl;
cout << aa.b2 << endl;
}
首 先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.经过strcpy和memcpy后,aa的4个字节所存放的值是: 0,1,2,3的ASC码,即00110000,00110001,00110010,00110011所以,最后一步:显示的是这4个字节的前5位,和 之后的2位分别为:10000,和01,因为int是有正负之分。
预处理器(Preprocessor)
1、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#include <iostream>
#include <string.h>
#define SECONDS_PER_YEARS 60 * 60 * 24 * 365UL
using namespace std;
int main()
{
unsigned long mimiasd = SECONDS_PER_YEARS;
cout << mimiasd << endl;
}
2、写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
#include <iostream>
using namespace std;
#define MIN( a, b ) ( a < b ? a : b )
int main()
{
int a, b;
cin >> a;
cin >> b;
cout << "The min number is : " << MIN( a, b ) << endl;
}
least = MIN(*p++, b);
输出结果为一地址表示的负数。 p++中++的优先级大于, 所以相当与*(p++).
3、预处理器标识#error的目的是什么?
#ifdef XXX
...
#error "XXX has been defined"
#else
#endif
这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。
死循环(Infinite loops)
4、 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢? 首选的方案是:
while(1)
{
}
一些程序员更喜欢如下方案:
for(;;)
{
}
这个实现方式让人为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。
第三个方案是用 goto
Loop:
...
goto Loop;
应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。
数据声明(Data declarations)
- 用变量a给出下面的定义 a) 一个整型数(An integer) b)一个指向整型数的指针( A pointer to an integer) c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r d)一个有10个整型数的数组( An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
Static
6、 关键字static的作用是什么? 这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:
- 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
- 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
- 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
Const
7、下面的声明都是什么意思? const int a; int const a; const int a; int * const a; int const * a const; /*****/ 前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
- 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
- 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
- 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
8、关键字volatile有什么含意?并给出三个不同的例子。 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
- 并行设备的硬件寄存器(如:状态寄存器)
- 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
- 多线程应用中被几个任务共享的变量
位操作(Bit manipulation)
9、嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。
#define BIT3 (0x1 访问固定的内存位置(Accessing fixed memory locations)
10、嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。 这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
A more obscure approach is: 一个较晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二种方案,但建议你在面试时使用第一种方案。
中断(Interrupts)
- 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了: 1)ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。 2) ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。 3) 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。 4) 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。
12、下面的代码输出是什么,为什么?
#include <iostream>
#include <stdio.h>
using namespace std;
void foo(void)
{
unsigned int a = 6;
int b = -20;
( a + b > 6 ) ? puts( "> 6" ) : puts( "6" );
}
int main()
{
foo();
}
输出>6。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。
- 评价下面的代码片断:
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */
对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:
unsigned int compzero = ~0;
动态内存分配(Dynamic memory allocation)
- 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么? 下面的代码片段的输出是什么,为什么?
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");
这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是"Got a valid pointer"。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。
Typedef
15 Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么? 这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子: dPS p1,p2; tPS p3,p4; 第一个扩展为 struct s * p1, p2 上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
16 . C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
int a = 5, b = 7, c;
c = a+++b;
这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:
c = a++ + b;
因此, 这段代码持行后a = 6, b = 7, c = 12。 如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题。
1、局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
2、如何引用一个已经定义过的全局变量?
答:extern
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答:可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错.
4、语句for( ;1 ;)有什么问题?它是什么意思?
答:和while(1)相同。
5、do……while和while……do有什么区别?
答:前一个循环一遍再判断,后一个判断以后再循环
6、请写出下列代码的输出内容
以下是引用片段:
#include <stdio.h>
int 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
7、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
8、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
9、设有以下说明和定义:
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, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.
所以结果是 20 + 32 = 52.
当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20
10、队列和栈有什么区别?
队列先进先出,栈后进先出
- static有什么用途?(请至少说明两种) 1).限制变量的作用域 2).设置变量的存储域
12、引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。
13、描述实时系统的基本特性 在特定时间内完成特定的任务,实时性与可靠性
14、 全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈
15、 什么是平衡二叉树? 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1
16、堆栈溢出一般是由什么原因导致的? 没有回收垃圾资源
17、 什么函数不能声明为虚函数? constructor
18、冒泡排序算法的时间复杂度是什么? O(n^2)
19、写出float x 与“零值”比较的if语句。 if(x>0.000001&&x<-0.000001)
-
Internet采用哪种网络协议?该协议的主要层次结构? tcp/ip 应用层/传输层/网络层/数据链路层/物理层
-
Internet物理地址和IP地址转换采用什么协议? ARP (Address Resolution Protocol)(地址解析協議)
22.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。
23.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。 循环链表,用取余操作做
24.不能做switch()的参数类型是: switch的参数不能为实型。
25、写出下列代码的输出内容
#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 )
{
FUNC1* p = &inc;
int temp = p( arg1 );
fun( &temp, &arg1, arg2 );
printf( "%d\n", *arg2 );
}
int main()
{
int a;
show( multi, 10, &a );
return 0;
}
结果是110.
26、请找出下面代码中的所以错误
说明:以下代码是把一个字符串倒序,如“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: int main(){ char* src = "hello,world"; int len = strlen(src); char* dest = (char*)malloc(len+1);//要为\0分配一个空间 char* d = dest; char* s = &src[len-1];//指向最后一个字符 while( len-- != 0 ) *d++=*s--; *d = 0;//尾部要加\0 printf("%s\n",dest); free(dest);// 使用完,应当释放空间,以免造成内存汇泄露 return 0; } 方法2: #include <stdio.h> #include <string.h> main() { char str[]="hello,world"; int len=strlen(str); char t; for(int i=0; i<len/2; i++) { t=str[i]; str[i]=str[len-i-1]; str[len-i-1]=t; } printf("%s",str); return 0; }
1 、-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、用两个栈实现一个队列的功能?要求给出算法和思路! 设2个栈为A,B, 一开始均为空.
入队: 将新元素push入栈A;
出队: (1)判断栈B是否为空; (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出;
这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。
3、在c语言库函数中将一个字符转换成整型的函数是atol()吗,这个函数的原型是什么? 函数名: 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); }
2.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现? c用宏定义,c++用inline
3.直接链接两个信令点的一组链路称作什么? PPP点到点连接
4、软件测试都有那些种类? 黑盒:针对系统功能的测试 白盒:测试函数功能,各函数接口
5、确定模块的功能和模块的接口是在软件设计的那个队段完成的? 概要设计阶段
1.进程和线程的差别。 线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位 (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行 (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
2.测试方法 人工测试:个人复查、抽查和会审 机器测试:黑盒测试和白盒测试
3.列举几种进程的同步机制,并比较其优缺点。 原子操作 信号量机制 自旋锁 管程,会合,分布式系统
4.进程之间通信的途径 共享存储系统 消息传递系统 管道:以文件系统为基础
5.进程死锁的原因 资源竞争及进程推进顺序非法
12.死锁的4个必要条件 互斥、请求保持、不可剥夺、环路
- 操作系统中进程调度策略有哪几种? FCFS(先来先服务),优先级,时间片轮转,多级反馈
14.类的静态成员和非静态成员有何区别? 类的静态成员每个类只有一个,非静态成员每个对象一个
15.纯虚函数如何定义?使用时应注意什么? virtual void f()=0; 是接口,子类必须要实现
16.数组和链表的区别 数组:数据顺序存储,固定大小 连表:数据可以随机存储,大小可动态改变
17.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点? 应用层 表示层 会话层 运输层 网络层 物理链路层 物理层 tcp /udp属于运输层 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。 与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。 tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好 udp: 不提供稳定的服务,包头小,开销小
1、(void )ptr 和 ((void**))ptr的结果是否相同?其中ptr为同一个指针 .(void )ptr 和 ((void**))ptr值是相同的
2、int main() { int x=3; printf("%d",x); return 1;
} 问函数既然不会被其它函数调用,为什么要返回1? mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息
3、要对绝对地址0x100000赋值,我们可以用 (unsigned int*)0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做? ((void ()( ))0x100000 ) ( ); 首先要将0x100000强制转换成函数指针,即: (void ()())0x100000 然后再调用它: ((void ()())0x100000)(); 用typedef可以看得更直观些: typedef void()() voidFuncPtr; *((voidFuncPtr)0x100000)();
4、已知一个数组table,用一个宏定义,求出数据的元素个数 #define NTBL #define NTBL (sizeof(table)/sizeof(table[0]))
5、线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈? 进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。 每个线程有自己的堆栈。 DLL 中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是 EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?
以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃
6、unsigned short A = 10; printf("~A = %u\n", ~A);
char c=128; printf("c=%d\n",c);
输出多少?并分析过程 第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285 第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。 这两道题都是在考察二进制向int或uint转换时的最高位处理。
7、long a=0x801010; a+5=? 0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725
8、给定结构struct A { char t:4; char k:4; unsigned short i:8; unsigned long m; };问sizeof(A) = ? 给定结构struct A { char t:4; 4位 char k:4; 4位 unsigned short i:8; 8位 unsigned long m; // 偏移2字节保证4字节对齐 }; // 共8字节
9、下面的函数实现在一个数上加一个数,有什么错误?请改正。 int add_n ( int n ) { static int i = 100; i += n; return i; } 当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static上?
10、求函数返回值,输入x=9999; int func ( x ) { int countx = 0; while ( x ) { countx ++; x = x&(x-1); } return countx; } 结果呢? 知道了这是统计9999的二进制数值中有多少个1的函数,且有 9999=9×1024+512+256+15
9×1024中含有1的个数为2; 512中含有1的个数为1; 256中含有1的个数为1; 15中含有1的个数为4; 故共有1的个数为8,结果为8。 1000 - 1 = 0111,正好是原数取反。这就是原理。 用这种方法来求1的个数是很效率很高的。 不必去一个一个地移位。循环次数最少。
11、int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题 bool add (int a, int b,int *c) { *c=a+b; return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b))); }
12、分析: struct bit { int a:3; int b:2; int c:3; }; int main() { bit s; char c=(char)&s; cout<<sizeof(bit)<<endl; *c=0x99; cout << s.a <<endl <<s.b<<endl<<s.c<<endl; int a=-1; printf("%x",a); return 0; } 输出为什么是 4 1 -1 -4 ffffffff 因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100 当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理 b = -1; 当c为有符合数时, c = 100,即 c = 4,同理 b = 3
来源:oschina
链接:https://my.oschina.net/u/2537915/blog/750355