1.交换两个值的大小
A. a=a+b ; b = a-b; a = a-b; B. a = a*b; b = a/b; a = a/b C. a = a^b; b = a^b; a = a^b
2.int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
假定x = 9999. 答案:8思路:将x转化为2进制,看含有的1的个数。
3.
const int* c=new int;
int * e = c ; 出错,指针不能指向一个常量,在这里c所指向的值不能改变
int* const c=new int;
int * e = c ; 正确
4.
#include <stdio.h>
union
{
int i;
char x[2];
}a;
void main()
{
a.x[0] = 10;
a.x[1] = 1;
printf("%d",a.i);
}
答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)
5.String的实现(虽然简单,但要注意细节)
class String
{
public:
String(const char *str = NULL); // 通用构造函数
String(const String &another); // 拷贝构造函数
~ String(); // 析构函数
String & operater =(const String &rhs); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
String::String(const char *str)
{
if ( str == NULL ) //strlen在参数为NULL时会抛异常才会有这步判断
{
m_data = new char[1] ;
m_data[0] = '\0' ;
}
else
{
m_data = new char[strlen(str) + 1];
strcpy(m_data,str);
}
}
String::String(const String &another)
{
m_data = new char[strlen(another.m_data) + 1];
strcpy(m_data,other.m_data);
}
String& String::operator =(const String &rhs)
{
if ( this == &rhs)
return *this ;
delete []m_data; //删除原来的数据,新开一块内存
m_data = new char[strlen(rhs.m_data) + 1];
strcpy(m_data,rhs.m_data);
return *this ;
}
String::~String()
{
delete []m_data ;
}
6.操作系统的组成(一道让我误解的题目)
(1)对CPU的使用进行管理的进程调度程序
(2)对内存分配进行管理的内存管理程序
(3)对输入输出设备进行管理的设备驱动程序
(4)对外存中信息进行管理的文件系统
7.ping是否可以查看端口21是否可用,为什么?
不能,ping只能pingIP,不能ping端口.
8.说出A、B、C类网络的子网号有几位?
注意,这里的子网号是等于网络号的,我一时没有反应过来,晕。
A: 0 网络号7位 主机号24位
B:10 网络号16位 主机号16位
C:110 网络号23位 主机号8位
10.函数压栈的方式(只列举常考的)
函数名 参数压栈 清栈 备注
(1)_cdcel _function 右到左 调用者清栈 可变参数列表的定义方式
(2)_fastcall @function@8 右到左 函数内部清栈 利用了寄存器ecx、eax、edx
(3)_stdcall _function@8 右到左 函数内部清栈
11.多线程同步的方式及比较
主要有下面几种:
1)如果同步的是一个32位或者64位的数,我们用原子方式实现同步,旋转锁就是用原子函数实现的,通过不停地调用原子函数对一个变量赋值,并返回变量的原值,如下:
while(InterlockedExchange(&g,true) == true);
由于返回的是原值,会不断循环,直至在别的地方改变为止。这种方式非常消耗CPU资源,在单处理器上不能使用,会一直占用着,多处理器上也不建议使用。也可以用一
个volatile的变量实现同步,但效率不高。
2)如果同步的是一段代码,我们用关键代码段。在我们运行函数时,会以原子方式运行,也就是说在函数调用时会对资源进行原子方式处理,别的线程只能等待,并从用户模
式切换到内核模式,进入等待状态,由于此过程开销很大,所以微软出了一个与关键代码段相结合的旋转锁,在一段很小的周期内不断询问是否可以调用资源,在里面有一
个计数,记录着旋转次数,当次数转为0时也是会进入内核模式。关键段速度快,非内对象, 只能用于同一进程之中,且容易处于死锁状态。
3)有另一种方式跟关键代码段差不多,就是Slim读写锁。它也是对资源以原子的形式保护起来,不过,在进行读操作时,允许别的线程读取该资源,只是在写操作时独占资源
而已。
4)利用事件内核对象。让一个事件处于触发或者非触发状态,当事件处于触发时,等待的事件就变成可调度状态了。这里有一点值得注意,事件分为两种,手动重置和自动重
置。手动重置是事件触发时,所有等待的线程变为可调度状态,而自动的话就只有一个。事件对象属于内核对象,系统耗费大量资源,但是可用于多进程间。
5)信号量内核对象。对某一资源设置一个访问上限值,只允许上限值的个数访问,当计数等于0时,信号量就变成未触发状态。信号量属于内核对象,耗费大量资源,但可用
于多进程间。
6)互斥量内核对象。独占对一个资源的访问,里面有一个线程ID,为0时表示该对象可触发。信号量属于内核对象,耗费大量资源,但可用于多进程间。
12、线程终止运行时系统的处理
1)释放线程栈对象 2)返回退出代码 3)线程的内核对象减一,并置为触发状态(互斥量或者事件对象时有用) 4)倘若结束线程为进程最后线程则结束进程
13.PostMessage 与SendMessage区别
相同点:参数相同,函数作用相同
不同点:1)返回值不同
2)前者是异步的,把消息放在消息循环队列里面后就返回,不管有无处理。而后者是同步的,等待消息被处理后再返回
3)同一线程时, SendMessage不把消息放进循环队列,而是调用目标窗体的消息处理程序进行处理,之后等待结果返回。而PostMessage 就直接放在消息循环队
列,然后通过循环分配到相应的窗口。
4)不同线程时,SendMessage把消息放进消息循环队列,然后在目标窗体的消息处理程序里面监视消息的处理,等待返回,而PostMessage 一样。