听说全会能拿12k

从这篇文章开始,准备换一种方式来做面试题,之前做的题相当于只是搜集答案,在整理的过程中没有结合自己做题的过程。接下来笔试题整理的过程中,打算加上对题中知识点的整理,也能顺带着复习基础的知识。

基础题

无符号二进制数100110.101转换成十进制数为:

A、38.625 B、38.315 C、48.625 D、48.815

答案

这道题有两个考点:

  1. 无符号二进制转十进制
  2. 二进制小数转十进制

无符号就意味着给出的二进制数最高位不代表符号位,直接把二进制数整数部分使用8421法进行计算转换为十进制数38

之后处理二进制的小数部分,其实小数部分也不难,就是从低位到高位也是2的负次方。所以0.101可以表示为1*2-1 + 0*2-2 + 1*2-3 = 0.625

最后把整数和小数部分相加得38.625

答案:A、38.625

扩展:

C语言实现进制转换

十进制转换为任意进制算是比较好实现的,只需要用十进制数除以任意进制数,余数取反就是对应进制的结果了,我们只要在代码中创建一个数组用来存储最后结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char *reverse_16(unsigned int a)
{
static char buffer[9] = { 0 };
for (int i = 7; i >= 0; i--)
{
int mod = a % 16;
if (mod < 10)
{
buffer[i] = mod + '0';
}
else
{
buffer[i] = mod - 10 + 'A';
}
a = a / 16;
}
return buffer;
}

void main()
{
unsigned int a = 235;
char *ret = reverse_16(a);
printf("ret = 0x%s\n", ret);
}

在面试中,我们尽可能缩减代码,提高效率,下面提供一种比较简洁的方法

1
2
3
4
5
6
7
8
9
10
char *reverse_16(unsigned int a)
{
static char buffer[9] = { 0 };
for (int i = 7; i >= 0; i--)
{
buffer[i] = "0123456789ABCDEF"[a % 16];//这行代码个人认为不值得学习
a = a / 16;
}
return buffer;
}

要是觉得上面的代码,还是太简单想在面试的时候展现大神风范,也可以使用递归实现


两个带符号的数进行计算时,在什么情况下有可能产生溢出

A、同符号数相加 B、同符号数相减 C、异符号数相加 D、异符号数相“或”

答案

首先要清楚溢出指的是除符号位以外的最高位进位,也就是符号位发生改变

显而易见的是,同符号数相加的情况下是很有可能溢出的

其实带符号整数减法中发生溢出要同时满足以下两个条件:

  1. ab符号不同

  2. a-b与a符号不同

那为什么呢,首先两个符号相同的数相减不可能溢出,如位宽为8时,两正整数相减的范围为0 ~ 126,两负整数相减的范围为-127 ~ 0。

然后我们将减法看成加法来运算,即将两个异号整数的减法a-b看成是两个同号整数相加a+(-b),若结果a-b的符号与a的符号不同,则表示本该是负数的结果变成了正数,正数的结果变成负数,肯定发生了溢出。

上述方法是从运算角度来分析,我们也可以分析运算时最高位和次高位的状态进行分析。

最高位进位状态异或次高位进位状态=1,则溢出

而最后选项中的或运算属于位运算,位运算并不会导致进位,所以不会溢出。

A、同符号数相加


</div>


kij的对应关系是

采用一维数组S存储一个n阶对称矩阵A的下三角部分(按行存放,包括主对角线),设元素A[i][j]放在S[k]中(i,j,k 均从1开始取值),且S[1] = A[1][1]kij的对应关系是_。例如,元素 A[3][2]存在 S[5]中。

A、k=i(i+1)/2+i-1 B、k=i(i+1)/2+i C、k=i(i-1)/2+i-1 D、k=i(i-1)/2+j

答案

对于一个n阶矩阵,从上到下,从左到右,其下三角部分有n(n+1)/2个元素(包括主对角线)。

因此,矩阵A的下三角部分元素的编号k,就是从1到n(n+1)/2的整数。

对于矩阵A的每一行i,它的下三角部分元素的个数是i个(包括第i个对角线元素)。

因此,对于元素A[i][j],它的编号k就是前i-1行的元素的个数加上第i行的第j个元素的位置,即:

1
2
cssCopy code
k = i*(i-1)/2 + j

这就是k与i,j的对应关系。


元素a、b、c、d依次入栈,则不能得到的出栈序列是

A、abcd B、cabd C、dcba D、bcda

答案

栈的特点是先进后出,但是要注意的是出栈和入栈的顺序是位置的,但是还是有规律可循:

  1. 在原序列中相对位置比它小的,必须是逆序
  2. 在原序列中相对位置比它大的,顺序没有要求
  3. 以上两点可以间插进行

依照上面的规律

  • 选项A可以看作是一入栈就出栈
  • 选项B当栈顶为c时栈空间从上至下的顺序是cba,此时a元素在b元素下方,不能出栈,所以选项B错误
  • 选项C是四个元素全部入栈,然后依次出栈
  • 选项D栈中元素是元素a一直在栈底,随后元素入栈就出栈,最后a再出栈


以下定义指针常量正确的形式是

A、const int *p B、int const *p C、int *const p D、const *int p

答案

对于指针常量的定义可以看看

我们只要关注后两个字,指针常量就是一个常量,而想要知道形式就更简单了,我们只要根据名字的顺序写出对应的定义即可指针:int *常量:const合起来就是int * const p

  • 选项A按照上述方法,可以知道时常量指针,常量定义在前指针在后
  • 选项B有些特殊,但是我们可以看到*跟变量在一起,所以这还是个指针,而const的位置在int前后都可以,只是不同的表示方法而已,由此得出选项B是常量指针
  • 选项C指针常量
  • 选项D是一个错误的声明


在函数recv(double arr[5])中,执行 sizeof(arr)/sizeof(double)的结果是

答案

在分析题目之前要注意的是sizeof不是函数而是运算符!!!,计算的是分配空间的实际字节数

而函数recv中定义的arr数组数据类似为double,其在内存中占8bit。double arr[5]相当于在内存中初始化了5个空间,每个空间都是double8bit的大小。

sizeof(arr)就是5个空间的总大小40bit,所以sizeof(arr)/sizeof(double) = 40 / 8 = 5

在写C语言的过程中sizeof(arr)/sizeof(double)经常被用来计算数组的长度,或者我们也可以用strlen()函数来实现,只是我们需要引入头文件#include <string.h>


请用C写一条宏定义MIN,这个宏输入两个参数并返回较小的一个

答案

这题还是很简单的

#define MIN(A,B) ((A)<(B)?(A):(B))

笔试题是笔试题,这道题其中还是有问题的,主要的问题就是宏定义中的参数展开的问题,所以要加上括号保证代码健壮性,具体的我们可以去查看预处理的代码


程序题

写出下面程序的输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream.h>

int main()
{
int x = 2, y = 0, z = 1;
x*=(y=z=3); cout<<x<<endl;
z = 5;
x == (y = z); cout<<x<<endl;
x = (y == z); cout<<x<<endl;
x = (y & z); cout<<x<<endl;
x = (y && z); cout<<x<<endl;
y = 6;
x = (y|z); cout<<x<<endl;
x = (y||z); cout<<x<<endl;
z = 0XFFFFFFFE;
x = ~z<<3; cout<<x<<endl:
}

x的输出值依次为:

答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//x 先与 (y=z=3) 相乘,也就是 x*=(y=z=3),x 变为 2 * 3,等于 6。
x*=(y = z = 3); cout<<x<<endl;
//z 变为 5,y 变为 5,然后 x 和 y 比较,但因为比较的结果是 false,所以 x 不变,还是 6。
x == (y = z); cout<<x<<endl;
//y 和 z 比较,结果为 true,因此 x 变为 1。
x = (y == z); cout<<x<<endl;
//x 变为 y 和 z 按位与的结果,也就是 5 & 5,结果为 5。
x = (y & z); cout<<x<<endl;
//x 变为 y 和 z 的逻辑与,因为都是 true,所以结果为 1。
x = (y && z); cout<<x<<endl;
//y 变为 6,x 变为 y 和 z 按位或的结果,也就是 6 | 5,结果为 7。
x = (y|z); cout<<x<<endl;
//x 变为 y 和 z 的逻辑或,因为都是 true,所以结果为 1
x = (y||z); cout<<x<<endl;
//z 变为 0xFFFFFFFE,x 变为 ~z 左移 3 位的结果,即 -16。
x = ~z<<3; cout<<x<<endl;


写出下面程序的输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>

typedef struct X
{
char a;
double b;
int c;
}x;

void change(int* a, int b, int c)
{
c=*a;
b=3;
*a=2;
}

void main()
{
int a=1, b=2, c=3;
int d[] = {1, 2, 3, 4, 5};
int *ptr;

change(&a, b, c);
ptr = (int *)(&d+1);
printf("%5d%5d\n",*(d+1),*(ptr-1));
printf("%5d %5d %5d\n", a, b, c);
printf("%5ld %5ld %5ld\n", sizeof(d), sizeof(d[1]), sizeof(x));
}
答案
1
2
3
2    5
2 2 3
20 4 24


为一个嵌入式实时系统用C语言写出一个完整的程序

输入实数n和m,计算公式并输出计算结果(只允许包含 stdio.h一个头文件)。

答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main(void) {
double n, m;
double epsilon = 0.00001;
double result;

printf("Enter a value for n: ");
scanf("%lf", &n);
printf("Enter a value for m: ");
scanf("%lf", &m);

result = (n * n * n + 6 * n * n + 12 * n + epsilon) / (m >= 3.0 ? (m - 3.0) : (3.0 - m));

printf("The result is: %lf\n", result);

return 0;
}


以下C语言代码段中存在部分问题,请指出全部问题,并给出该源程序编译运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "math.h"
#include "stdio.h"
#include <stdlib.h>

struct student
{
unsigned char flag;//生标识 0x100 代表语种为英语 其他:为其他语种
int id;
};

int calculate(int a)
{
int b, c=5;
float f = 2.3, *q;
double d = 0.2;
*q = f+d;
if(a = 1)
{
a = (a-b)*f(rand()-c)+*q;
}
else
{
a = sqrt(rand()- c);
}
}

void main()
{
int a_Main = 2, i;
struct student stuData;
calculate(a_Main);

//获得学生ID编号
stuData.id=20;
getStuld(&stuData);

printf("Id = %d\n", stuData.id);
printf("\n%d", a_Main);
}

//该函数获得学生的ID编号
void getStuId(struct student *stuData)
{
if(stuData->flag == 0x100)
{
stuData->id += 500;
}
else
{
stuData->id += 300;
}
}
答案
  • 第16行指针变量没有定义
  • 17行条件判断中应该使用==
  • 19行表达式 (a-b)*f(rand()-c)+*q 的计算结果是一个浮点数,但将其赋值给整型变量 a,存在精度丢失的风险。
  • 19行对于 a 的赋值语句中使用了未定义的变量 b
  • 函数 getStuld 在调用之前未声明。


专业选做题

简述进程与线程的差别,并简述进程的三种基本状态

答案

根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

进程有三种基本状态:就绪态、运行态和阻塞态。

  1. 就绪态:进程已经准备好运行,但是还没有得到CPU的分配。在多任务系统中,就绪态的进程可以被调度到CPU上执行。
  2. 运行态:进程正在CPU上执行。在多任务系统中,只有一个进程可以处于运行态。
  3. 阻塞态:进程因为等待某种事件(如磁盘IO)而被挂起,无法继续执行。在这种情况下,进程的状态就变成了阻塞态。当等待的事件完成时,进程就可以切换到就绪态,等待CPU的分配。



参考文章: