C语言面试题

来源:互联网 发布:大数据与企业战略 编辑:程序博客网 时间:2024/06/06 20:33

一、填空选择题 
1、请写出 char *p 与“零值”比较的 if 语句 
if(NULL == p)

2、写出打印结果255 
#include < stdio.h> 
#include < string.h> 
int main() 

char a[1000]; 
int i; 
for(i=0;i<1000;i++) 

a[i]=-1-i; 
}

printf(“%d”,strlen(a)); 
return 0; 
}

分析: 
for 循环内,当i 的值为0 时,a[0]的值为-1。关键就是-1 在内存里面如何存储。 
我们知道在计算机系统中,数值一律用补码来表示(存储)。主要原因是使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。 
按照负数补码的规则,可以知道-1 的补码为0xff,-2 的补码为0xfe……当i 的值为127时,a[127]的值为-128,而-128 是char 类型数据能表示的最小的负数。当i 继续增加,a[128]的值肯定不能是-129。因为这时候发生了溢出,-129 需要9 位才能存储下来,而char 类型数据只有8 位,所以最高位被丢弃。剩下的8 位是原来9 位补码的低8 位的值,即0x7f。 
当i 继续增加到255 的时候,-256 的补码的低8 位为0。然后当i 增加到256 时,-257 的补码的低8 位全为1,即低八位的补码为0xff,如此又开始一轮新的循环…… 
按照上面的分析,a[0]到a[254]里面的值都不为0,而a[255]的值为0。strlen 函数是计算字符串长度的,并不包含字符串最后的‘\0’。而判断一个字符串是否结束的标志就是看是否遇到‘\0’。如果遇到‘\0’,则认为本字符串结束。

3、分析输出结果8,8_ 
int arr[] = {6,7,8,9,10}; 
int *ptr = arr; 
*(ptr++)+=123; 
printf(“ %d %d ”, ptr, (++ptr)); 
分析: 
int *ptr = arr; 
此时指针指向第一个元素,即6 
*(ptr++)+=123; 
此时指针ptr自加表示地址加一,指向第二个元素 
printf(“ %d %d ”, ptr, (++ptr)); 
Printf中是向右的结合方向,所以先执行的是(++ptr),所以此时指针又向后移了一位,(++ptr)的值为8,再执行*ptr,值也为8

4、f(657, 789)723___ 
int f(int x, int y) 

return (x&y)+((x^y)>>1) 
}

分析: 
题目中的&和^都是位运算,所以我们有必要研究数据的对位情况。任何数据只有3中情况。 
1) 0 与 0对应 
2) 0 与 1对应 
3)1 与 1对应 
那么它们分别什么诀窍呢? 
举例子来说:0101 和1101 也就是x和y分别为5、13.这两个数据出现了所谓的3种对应位情况。 
我们可以把数据拆开来看: 5=0000+100+00+1 
13=1000+100+00+1 
他们分为为第一位,第二位,….. 
当0和1对应时,x&y结果为0, x^y的结果呢?是不是就是x和y中那个对应位不为0的数据。 
例如:上面数据的第四位0和1对位。此时x^y的结果就是1000.正是1101的第四位结果。 
再右移一位,相当于除以2,所以当 0和1对位是原函数结果为 (x+y)/2; 
在看1和1对应,1^1的结果为0,所以原函数后半部分不考虑,1&1结果为1,这也是(x+y)/2; 
例如:第一位和第三位的对位,都为100,他们相与的结果和相加除以2相等,即x&y=(x+y)/2; 
0与0对应的时候,无论怎么样都是0,即也符合(x+y)/2. 
综合上述三种情况,我们可以知道其实原函数返回就是(x+y)/2。

5、Linux文件权限一共10位长度,分成四段,第三段表示的内容是C___  
A、文件类型 
B、文件所有者的权限 
C、文件所有者所在组的权限 
D、其他用户的权限

分析: 
Linux用户分为:拥有者、组群(Group)、其他(other) 
linux中的文件属性过分四段,如 -rwzrwz— 
第一段 - 是指文件类型 表示这是个普通文件 
文件类型部分 
-为:表示文件 
d为:表示文件夹 
l为:表示链接文件,可以理解为 windows中的快捷方式(link file) 
b为:表示里面可以供存储周边设备 
c为:表示里面为一次性读取装置

第二段 rwz 是指拥有者具有可读可写可执行的权限 
类似于windows中的所有者权限比如 administrator 对文件具有 修改、读取和执行权限

第三段 rwz 是指所属于这个组的成员对于这个文件具有,可读可写可执行的权限 
类似于windows中的组权限比如administrators组,属于这个组的成员对于文件的都有 可读可写可执行权限

第四段 — 是指其他人对于这个文件没有任何权限 
类似于windows中的 anyone 一样就是说所有人对着个文件都会有一个怎样的权限

二、简答题 
1、用变量a给出下面的定义 
1) int a; 
2) int *a; 
3) int **a; 
4) int a[10]; 
5) int *a[10]; 
6) int (*a)[10]; 
7) int (*a)(int); 
8) int (*a[10])(int);

分析: 
1) 一个整型数 
2)一个指向整型数的指针 
3)一个指向指针的的指针,它指向的指针是指向一个整型数 
4)一个有10个整型数的数组 
5) 一个有10个指针的数组,该指针是指向一个整型数的 
6) 一个指向有10个整型数数组的指针 
7) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 
8) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

2、关键字const的作用是什么? 
(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了; 
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const; 
(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值; 
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量; 
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

3、内存的分配方式的分配方式有几种? 
有三种,分别为静态存储区、栈、堆的内存分配 
1.从静态存储区域分配内存。程序编译的时候内存已经分配好了,并且在程序的整个运行期间都存在,例如全局变量。 
2.在栈上创建。在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数结束时这些存储单元自动被释放。 
处理器的指定集中有关于栈内存的分配运算,因此效率比较高,但是分配的内存容量有限。 
3.在堆上分配内存,亦称动态内存分配,程序在运行的时候用malloc函数或new运算符申请任意大小的内存,程序员

4、进程和线程的区别 
1)进程是程序的一次执行,是资源分配的最小单位,线程可以理解为进程中执行的一段程序片段,是CPU调度的最小单位; 
2)进程间是独立的,一个程序崩溃后,在保护模式下不会对其他进程产生影响。同一进程所产生的线程共享同一内存空间,一个线程挂掉会导致整个进程挂掉; 
3)同一进程中两段代码不能同时执行,除非引入线程;、线程所占用的资源要少于进程所占用资源; 
4)进程间可以通过IPC通信,但线程不可以。

5、进程间通信方式有哪些?各自有哪些优缺点? 
1)管道 
管道分为有名管道和无名管道 
无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系。无明管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。 
有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。

2)信号量 
信号量是一个计数器,可以用来控制多个线程对共享资源的访问.,它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.

3)信号 
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生.

4)消息队列 
消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.

5)共享内存 
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问.共享内存是最快的IPC(进程间通信)方式,它是针对其它进程间通信方式运行效率低而专门设计的.它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步与通信.

6)套接字:可用于不同及其间的进程通信

三、程序题 
1、C语言库函数里是否有将字符串转化为数字的函数,若有则用自己的方式实现它。 
int atoi(const char * str) 

if(str == NULL) //入口参数检查!!! 

return -1; 
}

long long num = 0; //溢出问题有没有考虑 
int temp = 1; 
int flag = 1;

if(*str == ‘-’) //如果遇到正负号 

flag = -1; 

If(*str == ‘+’ || *str == ‘-’) 

str++; 
}

while(*str >= ‘0’ && *str <= ‘9’) 

num = num * 10 + *str - ‘0’; 
str ++; 

num = flag * num; 
return (int)num; 

2、编写一个程序,实现输出链表中倒数第K个结点 
ListNode * FindKthToTail(LisNode *head, unsigned int k) 

if(head == NULL || K == 0) //入口参数检查!!! 

return NULL; 

int i; 
ListNode *pAhead = head; 
ListNode *pBehind = NULL;

for(i = 0; i < k - 1; ++i) 

if(pAhead->next != NULL) 

pAhead = pAhead->next; 

else 

return NULL; 


pBehind = head; 
while(pAhead->next != NULL) 

pAhead = pAhead->next; 
pBehind = pBehind->next; 

Return pBehind; 
}

0 0
原创粉丝点击