} 输出:12 3
115、int a[2] = {1, 2};
//指向常量的指针,指针可以变,指针指向的内容不可以变 const int *p = a;//与int const *p = a;等价 p++;//ok *p = 10;//error
//常指针,指针不可以变,指针指向的内容可以变 int* const p2 = a; p2++;//error *p2 = 10;//ok
//指向常量的常指针,都不可以改变 p3++;//error *p3 = 10;//error
116、#error 预处理指令的作用是,编译程序时,只要遇到#error 就会生成一个编译错误提 示消息,并停止编译
117、中断活动的全过程大致为:
1、中断请求:中断事件一旦发生或者中断条件一旦构成,中断源提交“申请报告”, 与请求CPU暂时放下目前的工作而转为中断源作为专项服务
2、中断屏蔽:虽然中断源提交了“申请报告”,但是,是否得到CPU的响应, 还要取决于“申请报告”是否能够通过2道或者3道“关卡”(中断屏蔽)送达CPU
(相应的中断屏蔽位等于1,为关卡放行;反之相应的中断屏蔽位等于0,为关卡禁止通行); 3、中断响应:如果一路放行,则CPU响应中断后,将被打断的工作断点记录下来 (把断点地址保护到堆栈),挂起“不再受理其他申请报告牌” (清除全局中断标志位GIE=0),跳转到中断服务子程序
4、保护现场:在处理新任务时可能破坏原有的工作现场,所以需要对工作现场和工作环境进行适当保护;
5、调查中断源:检查“申请报告”是由哪个中断源提交的,以便作出有针对性的服务; 6、中断处理:开始对查明的中断源进行有针对性的中断服务;
7、清除标志:在处理完毕相应的任务之后,需要进行撤消登记(清除中断标志),以避免造成重复响应;
8、恢复现场:恢复前面曾经被保护起来的工作现场,以便继续执行被中断的工作; 9、中断返回:将被打断的工作断点找回来(从堆栈中恢复断点地址), 并摘下“不再受理其他申请报告牌”(GIE=1),继续执行原先被打断的工作。 118、linux进程间通讯的几种方式的特点和优缺点,和适用场合。分类:
#管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,
而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 #有名管道(named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
#信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作
为进程间以及同一进程内不同线程之间的同步手段。
#消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识 符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
#信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 #共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存, 这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式, 它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制, 如信号量,配合使用,来实现进程间的同步和通信。
#套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是, 它可用于不同及其间的进程通信。
119、关键字volatile有什么含意?并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设 这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,
而不是使用保存在寄存器里的备份。 下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下, 看一下这家伙是不是直正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。 2). 一个指针可以是volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) {
return *ptr * *ptr; }
下面是答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。 它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是, 由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: int square(volatile int *ptr) { int a,b; a = *ptr; b = *ptr; return a * b; }
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。 结果,这段代码可能返不是你所期望的平方值!正确的代码如下: long square(volatile int *ptr) { int a; a = *ptr; return a * a; }
Volatile 关键字告诉编译器不要持有变量的临时性拷贝。一般用在多线程程序中, 以避免在其中一个线程操作该变量时,将其拷贝入寄存器。
请看以下情形: A线程将变量复制入寄存器,然后进入循环,反复检测寄存器的值是否满足 一定条件(它期待B线程改变变量的值。在此种情况下,当B线程改变了变量的值时, 已改变的值对其在寄存器的值没有影响。所以A线程进入死循环。 volatile 就是在此种情况下使用。
120、如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提高调度效率和 限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队等候 121、main() {
char *p1=“name”; char *p2;
p2=(char*)malloc(20);
memset (p2, 0, 20); while(*p2++ = *p1++); printf(“%s\\n”,p2); }
答案:Answer:empty string. 因p2++已经指到了'\\0'了;
122、操作系统的内存分配一般有哪几种方式,各有什么优缺点? 定长和变长。
变长:内存时比较灵活,但是易产生内存碎片。 定长:灵活性差,但分配效率较高,不会产生内存碎片
123、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答:可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,
前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
124、确定模块的功能和模块的接口是在软件设计的那个队段完成的?概要设计阶段 125、#define N 500 unsigned char count;
for(count=0;count < N;count++) {
printf(\
}死循环,因为unsigned char 最大为255 126、给定结构struct A {
char t:4; 4位 char k:4; 4位
unsigned short i:8; 8位
unsigned long m; // 偏移2字节保证4字节对齐 }; // 共8字节
127、ICMP(ICMP协议对于网络安全具有极其重要的意义)功能主要有: · 侦测远端主机是否存在。 · 建立及维护路由资料。 · 重导资料传送路径。 · 资料流量控制。
单向、双向链表操作、写一个快速排序算法(原理:找一个基准值,分别将大于和小于基准值
的数据放到基准值左右两边,即一次划分。由于处在两边的数据也是无序的,所以再用同样的划分方法对左右两边的序列进行再次划分,直到划分元素只剩1个时结束,) /******************************************************************/ 1、单向链表逆序
LONDE *link_reverse(LNODE *head) {
LNODE *pb,*pt; if(head == NULL) return head; pb = head->next; head->next=NULL; while(pb != NULL) {
pt = pb->next; pb->next = head; head = pb; pb = pt; }
return head; }
2、快速排序
void quick_sort(int num,int start_num,int end_num) {
if(start_num < end_num) {
int i = start_num; int j = end_num;
int temp = num[start_num]; while(i < j) {
while(i < j && num[j] < temp) j--; if(i < j)
num[i++] = num[j];//把小于基准值放在左边 while(i < j && num[i] >= temp)