大椽科技笔试题

写一个“标准"宏 MIN , 这个宏输入两个参数并返回较小的一个

答案

#define MIN((a),(b)) (((a)<(b))? (a):(b))

具体参考下面的文章:


进程和线程的差别

答案
  1. 概念上的区别:进程是操作系统分配资源的基本单位,它是程序执行的一个实例,具有独立的运行空间,是一次程序运行的基本单位,而线程是进程的一个实体,它是进程中的一个单一顺序控制流,也是一个独立的有资源分配的基本单位。

  2. 功能上的区别:进程有自己的地址空间,而线程可以共享进程的地址空间;进程之间的切换比较耗时,而线程之间的切换则比较快;进程有自己的堆栈空间,而线程共享一个堆栈空间;进程之间的通信比较复杂,而线程之间的通信则比较简单。

  3. 开销上的区别:进程的开销比较大,而线程的开销比较小。


链表和数组有什么区别

答案


用变量 a 给出下面的定义

—个整型数 (An integer) ——-> int a

一个指向整型数的指针 ( A pointer to an integer) ——-> int *a

一个指向指针的指针, 它指向的指针是指向—个整型数 ( A pointer to a pointe to a n integer) ——-> int \**ptr

一个有 10 个整型数的数组 ( An array of 10 integers) ——-> int a[10]

一个有 10 个指针的数组,该指针是指向—个整型数的。 (An array of 10 pointers to integers) ——-> int *a[10]

—个指向有10 个整型数数组的指针 ( A pointer to an array of 10 integers) ——-> int (*a)[10]

—个指向函数的指针, 该函数有—个整型参数并返回—个整型数 (A pointer to a fun ction that takes an integer as anargument and returns an integer) ——-> int (*a)(int)

— 个有10 个指针的数组,该 指 针指向— 个函数,该函数 有—个整型参数并返回一个整型 数 ( An array of ten pointers to functions that take aninteger argument and return an integer ) ——-> int (*a[10])(int)


关键字volatile 有什么含意, 并给出三个不同的例子

答案

volatile 是C语言提供的轻量级的同步机制,它的主要作用是保证共享变量的线程可见性,也就是当一个线程修改了某个共享变量的值,其他线程可以立即看到被修改的值。

  1. 如果一个变量可能被多个线程同时访问,那么这个变量必须用volatile修饰,以确保每个线程都能够看到当前的值,而不是缓存中的旧值。

  2. 如果一个变量可能被多个CPU同时访问,那么这个变量必须用volatile修饰,以确保每个CPU都能够看到当前的值。

  3. 如果一个变量可能被外部硬件访问,那么这个变量必须用volatile修饰,以确保外部硬件能够正确的读取到这个变量。


进程间通信的方式有哪些?

答案
  1. 共享内存:共享内存是把一块内存区域划分出来,供多个进程使用,它是最快的进程间通信方式,但是它的缺点是只能用于具有共同体系结构的机器,而且它的安全性不高。

  2. 消息传递:消息传递是指进程之间使用一种叫做“消息”的数据结构进行通信。一个进程发送消息给另外一个进程,而另一个进程接受这个消息并做出响应。

  3. 管道:管道是一种具有缓冲区的通信机制,允许数据从一个进程传送到另一个进程。它有两种形式:有名管道和无名管道。

  4. 信号量:使用信号量来控制进程之间的通信,它可以帮助进程之间同步数据。

  5. 套接字:socket是一种常用的进程间通信机制,它提供了进程间数据传输的抽象,它可以用于进程间的点对点通信,或者进程间的广播通信。


关键字 static的作用是什么?

答案
  1. 修饰变量:可以使变量的作用范围变为局部变量,只能在声明它的文件或函数中使用,可以防止变量污染全局变量空间。

  2. 修饰函数:可以使函数只能在声明它的文件或函数中使用,防止函数在其他文件中被重复定义。

  3. 修饰类:可以使类的成员只能在声明它的文件或函数中使用,防止类的成员在其他文件中被重复定义。


给定一个整型变最 a, 写两段代码 。第—个设置a 的 bit 3, 第二个清除a 的 bit 3。在以上两个操作中, 要保持其它位不变。

答案


信号量与互斥量的区别

答案
  1. 信号量是一种更高级的同步机制,可以用来控制对共享资源的访问,而互斥量只能用来保证临界区的互斥访问。
  2. 信号量是一种可以动态变化的计数器,可以用来控制多个线程对共享资源的访问,而互斥量只能用来控制一个或多个线程对共享资源的互斥访问。

  3. 信号量是可以在多个线程间共享的,而互斥量一般是不可共享的。

  4. 信号量可以提供更精细的粒度的控制,而互斥量只能提供最基本的控制。


简述网络编程中 tcpudp 的区别

答案
  1. 传输数据的方式不同:TCP是面向连接的,基于字节流的可靠的传输协议;UDP是无连接的,面向报文的不可靠的传输协议。
  2. 拥塞控制不同:TCP使用滑动窗口来进行拥塞控制;UDP不存在拥塞控制。
  3. 头部开销不同:TCP头部比较大,20字节;UDP头部只有8字节。
  4. 流量控制不同:TCP有流量控制;UDP没有流量控制。
  5. 可靠性不同:TCP是可靠的,它能够保证数据的可靠传输;UDP是不可靠的,数据可能会丢失。


简述 selectepoll 的区别

答案

selectepoll都是I/O多路复用的实现,它们的主要区别有以下几点:

  1. select是将所有的socket fd放入一个集合中,每次调用select时会遍历所有的socket fd,而epoll采用的是事件驱动的方式,当有新的请求连接或者有连接产生数据的时候,epoll会把这个socket fd加入到一个队列中,以便下次轮询时处理。

  2. select每次调用都要传入所有的socket fd,当socket fd数量特别多的时候,会对性能造成很大的影响,而epoll只需要在程序启动的时候注册一次,后续调用只需要处理队列中的socket fd就可以了,不会造成性能的影响。

  3. select支持的fd数量有限,而epoll支持的fd数量更多,虽然epollfd也是有限的,但是基本可以满足需求。


如何引用一个已经定义过的全局变量?

答案

可以使用extern关键字来声明。extern关键字表明该变量在其他文件中已经声明,然后可以使用该变量名来引用它,如:

1
2
3
4
5
// 在其他文件中
extern int globalVariableName;

// 访问全局变量
printf("%d\n", globalVariableName);


简述 selectepoll 的区别

答案

selectepoll都是I/O多路复用的实现,它们的主要区别有以下几点:

  1. select是将所有的socket fd放入一个集合中,每次调用select时会遍历所有的socket fd,而epoll采用的是事件驱动的方式,当有新的请求连接或者有连接产生数据的时候,epoll会把这个socket fd加入到一个队列中,以便下次轮询时处理。

  2. select每次调用都要传入所有的socket fd,当socket fd数量特别多的时候,会对性能造成很大的影响,而epoll只需要在程序启动的时候注册一次,后续调用只需要处理队列中的socket fd就可以了,不会造成性能的影响。

  3. select支持的fd数量有限,而epoll支持的fd数量更多,虽然epollfd也是有限的,但是基本可以满足需求。


浅述 GCC 编译器在编译时都有哪几个过程

答案


memcpy 函数的功能实现

答案
1
2
3
4
5
6
7
8
9
10
11
//实现memcpy函数
void *memcpy(void *dest, const void *src, size_t n)
{
char *dest_tmp = dest;
const char *src_tmp = src;
while (n--)
{
*dest_tmp++ = *src_tmp++;
}
return dest;
}


设计—个程序

输入一个字符串以#结尾,则输出此字符串中连续出现最长的数字串及其开始的下标,

例如:

输入:ab125ef1234567#

输出:1234567 开始的下标为 :8

答案
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
#include<stdio.h>

int main(){
char str[100], maxstr[100], ch;
int start = 0, maxstart = 0;
int i = 0, j = 0, len = 0, maxlen = 0;
scanf("%s", str);
while(str[i] != '#'){
if(str[i] >= '0' && str[i] <= '9'){
start = i;
j = i;
len = 0;
while(str[j] >= '0'&&str[j] <= '9'){
len++;
j++;
if(str[j] == '#')
break;
}
if(len > maxlen){
maxlen = len;
maxstart = start + 1;
}
i = j;
}
else
i++;
}
if(maxlen == 0)
printf("没有找到数字串\n");
else
{
j = 0;
for(i = maxstart; i < maxstart + maxlen; i++)
maxstr[j++] = str[i];
printf("%s 开始的下标为:%d\n",maxstr,maxstart);
}
return 0;
}