A 网龙科技笔试:
第一字节对齐:
系统默认的对齐规则,追求的至少两点:1、变量的最高效加工 2、达到目的1的最少空间
按最长规则对齐:
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct T
{
char c; //本身长度1字节
double d; //本身长度8字节
int e; //本身长度4字节
short f; //本身长度2字节
char g; //本身长度1字节
short h; //本身长度2字节
};
int main()
{ int n;
n=sizeof(T);
printf("%d\n",n);// 32
printf("%d\n",sizeof(double));//8
getchar();
getchar();
}
网络字节序:
ARM默认是小端模式 X86结构是小端模式
假设一个32位 unsigned int型数据0x12 34 56 78,大小端8位存储方式如下:
大端存储方式为0x12 34 56 78
小端存储方式为0x78 56 34 12
上文说的网络字节顺序则是表示网络传输时的字节序,按照TCP/IP协议是按照
大端传输方式,也就是高字节先走(先传12,接着34,56,78)
403错误:禁止访问 404 找不到资源
快排的最差时间复杂度为O(N^2),最坏情况出现在数组已经完全有序不必再排列时。你所说的就是这种情况,此时快排会退化成一个相当慢的算法。直接插入排序的时间复杂度为O(N^2),但是当数据有序时,执行效率最好,此时的时间复杂度为O(n)。也就是说,在你所说的数组递增有序的前提下,直接插入排序最快 冒泡排序最好的情况下是在数组基本有序的情况下,复杂度0[n]堆排序对原始的数的顺序不敏感,复杂度始终未0[nlgn]
列出字符串的所有组合:
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<iostream>
using namespace std;
#include<assert.h>
void Permutation(char* pStr, char* pBegin)
{
assert(pStr && pBegin);
if(*pBegin == '\0')
printf("%s\n",pStr);
else
{
for(char* pCh = pBegin; *pCh != '\0'; pCh++)
{
swap(*pBegin,*pCh);
Permutation(pStr, pBegin+1);
swap(*pBegin,*pCh);
}
}
}
int main(void)
{
char str[] = "abcd";
Permutation(str,str);
getchar();
getchar();
return 0;
}
堆栈溢出:
堆栈溢出很可能由无限递归(Infinite recursion)产生(递归深度太深),但也可能仅仅是过多的堆栈层级。
数组申明在函数内部,属于局部变量,存放在了栈上,
看看数组占用的内存大小:1000000=1000*1000然后乘以int型数据长度
1000*1000*4byte约等于4M,
而栈的默认内存空间为1M左右,所以会导致栈溢出
解决这个问题,可以将数组申明在全局存储区或堆上即可
方法一:申明为全局变量
方法二:存放在堆上
VS2010的默认情况下,32位程序可以申请的堆大小最大是2G。实际上只能小于2G
总结一下,在默认情况下,栈只能得到1M大小的内存,全局静态储存可以得到2G,而在32位和64位下的堆则可以得到2G和无限内存(一般不会用到16T)。
在1-39内取随机数 %39 取余数
符号链接与硬链接的区别:
我们可以把符号链接,也就是软连接 当做是 windows系统里的 快捷方式。硬链接 就好像是 又复制了一份.ln 3.txt 4.txt 这是硬链接,相当于复制,不可以跨分区,但修改3,4会跟着变,若删除3,4不受任何影响。ln -s 3.txt 4.txt 这是软连接,相当于快捷方式。修改4,3也会跟着变,若删除3,4就坏掉了。不可以用了
Linux采用什么算法来解决内存碎片问题?
Linux采用了“伙伴系统” 内存池
B 锐捷笔试:
第一: 把3.14输入到buffer中
char buffer[80];
sprintf(buffer, "An approximation of Pi is %f\n",3.14);
第二:有符号的移位和无符号的移位
总之左移就是: 丢弃最高位,0补最低位
右移对符号位的处理和左移不同,对于有符号整数来说,比如int类型,右移会
保持符号位不变
1<<32
int a=1;
int b=32;
a<<b; 答案:0 1
第三 %d %u %u 无符号整数
锐捷面试:
信号量与互坼体的区别
A Linux内核态 用户态:
一、用户态和内核态
现在我们从特权级的调度来理解用户态和内核态就比较好理解了,当程序运行在3级特
权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运
行的特权级,大部分用户直接面对的程序都是运行在用户态;反之,当程序运行在级特权级上时,就可以称之为运行在内核态。虽然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。
二、用户态切换到内核态的3种方式
1) 系统调用:这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系
统调用申请使用操作系统提供的服务程序完成工作。而系统调用的机制其核心还是使
用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
2) 异常:当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常
,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核
态,比如缺页异常。
3) 外围设备的中断:当外围设备完成用户请求的操作后,会向CPU发出相应的中
断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生
了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断
处理程序中执行后续操作等。
B 为什么进程开销比线程开销大?
答: 在进程切换时,涉及到整个当前进程CPU环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作,可见,进程切换的开销也远大于线程切换的开销。Linux中的线程上下文切换比进程切换开销要小很多,因为不需要切换页表、刷新TLB。linux下系统创建线程要比创建进程的开销小得多。 内核无需单独复制进程的内存空间或文件描述符等等,这就节省了大量的CPU时间,也节省很多内在空间。使用多线程,无需使用繁琐的IPC和其它复杂的通信机制。
C 一个指针可以连续free()吗 ?
标准答案:
功 能:
使用malloc分配的内存空间在虚拟地址空间上是连续的,但是转换到物理内存空间
上有可能是不连续的与malloc()函数配对使用,释放malloc函数申请的动态内存。(另:对于free(p)这句语句,如果p 是NULL 指针,那么free 对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。)
free()释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常
重要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这
空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是
垃圾。因此,前面我已经说过了,释放内存后把指针指向NULL,防止指针在后面不小
心又被解引用了。非常重要啊这一点!
还应该注意的是,free和delete只是把指针所指的 内存给释放掉,但并没有把指针
本身干掉。指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃
圾,p成了“野指针”。如果此时不 把p设置为NULL,会让人误以为p是个合法的指针
。用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生“野指针”。内存 被释放了,并不表示指针会消亡或者成了NULL指针
我的答案:
可以 试过没问题
char *str=(char *)malloc(10);
str="aaaa";
printf("%s\n",str);
free(str);
free(str);
free()做的事是什么?
按照原理不行啊?
linux文件系统详解:
递归 递归的优化:
Linux系统从磁盘拷贝一些数据通过网络发出去经历几次数据拷贝:
C 腾讯面试:
内存拷贝函数实现:
内存拷贝其实就是将一个内存中的值复制到一个内存中,这两个内存块可以相同可
以不同
void *memccpy(void *dest, void *src, unsigned char ch, unsigned int
count);
[linux进程的几个状态]
1. Linux进程状态:R (TASK_RUNNING),可执行状态&运行状态(在run_queue队
列里的状态)
2. Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态, 可处理
signal
3. Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态, 可处
理signal, 有延迟
4. Linux进程状态:T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态,
不可处理signal, 因为根本没有时间片运行代码
5. Linux进程状态:Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸
进程。不可被kill, 即不响应任务信号, 无法用SIGKILL杀死
进程的基本调度状态有哪些?
①运行。②就绪。③阻塞。
Linux文件系统的组织方式称做Filesystem Hierarchy Standard(文件系统分层标准,简称FHS),即采用层次式的树状目录结构。在此结构的最上层是根目录"/"(斜杠),然后在此根目录下是其他的目录和子目录,如图6.1所示。
linux文件系统分类
:jfs、 ReiserFS、ext、ext2、ext3、iso9660、xfs、 minx、msdos、umsdos、
Vfat、NTFS、Hpfs、Nfs、smb、sysv、proc
linux文件类型:
普通文件 目录文件 字符设备或块设备文件 数据接口文件(sockets): 符号链接文件
1000个苹果放到20个箱子 能不能放下?
能 箱子中依次放
1,2,4,8,16,32,64,128,256,489个苹果 其余十个不放
其实就是数的二进制表示而已
分油问题:3斤和7斤空杯子 一个10斤被子 分成了两个五斤,
先用三斤的连续分三次 1 6 3
再 1 7 2
再 8 2 0
在 5 5
CVTE面试题目
A:
char *a="012345";
printf("%d\n",*((unsigned short *)(a+2)));// 13106=51*256+50 PC小端
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的
低地址中强制转换的意思,这个指针指向的代表是新类型数据,起始地址不变
B;查找第二大数
海能达面试:
万用表等级精度:2.5级,误差率为2.5%
堆:
最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的
值大。
最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的
值小。
二叉排序树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。
二叉平衡树:
首先是二叉排序树
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1
每个点都是二叉平衡树
网络字节序:
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统
等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采
用big endian排序方式。
X86现在流行的PC机是小段格式 arm的大小端可以自己设置默认是小端
linux内核2.4以后内核开发者对链表的结构实现了一个统一的接口
Linux内核链表节点: 内核实现的是双向循环链表,提供了链表操作的基本功能。
LIST_HEAD 实现统一接口
struct list_head
{
struct list *next,*pre;
}
内核的数据结却是将链表的节点嵌入到数据结构中:
struct list_node{
TYPE data;
struct list_head list; //定义一个list_head的节点
};
最重要的宏是list_entry,这个宏的思路是根据链表元素结构中链表头结构
list_head的地址推算出链表元素结构的实际地址:#define list_entry(ptr,
type, member)
Linux中一些的常用数据结构:
第一 链表(双向循环链表)
第二 红黑树:
linux内核模块中对红黑树的应用
如果只是为了理解linux内核进程调度和内存管理中的红黑树应用的话,只要记住下面
即可
A、红黑树是一个二叉搜索树(从任何一个节点开始,左下方的数比本节点数值小,右
下方的数比本节点大)。
B、插入过程中按照key值大小插入到树中适当的位置。
C、搜索、插入和删除效率很高。
第三 队列
struct kfifo *fifo;
kfifo_put(fifo, (char *)stu1, sizeof(struct student));
kfifo_get(fifo, c_tmp, sizeof(struct student));
内核中的队列是以字节形式保存数据的,所以获取数据的时候,需要知道数据的大
小。如果从队列中取得数据时指定的大小不对的话,取得数据会不完整或过大。
内核队列编程需要注意的是:
队列的size在初始化时,始终设定为2的n次方
使用队列之前将队列结构体中的锁(spinlock)释放
美图秀秀笔试:
写一个数组 数组里面是函数指针 (int)(*a[10])(int)
气泡法排序: 用起泡法对10个数排序 从小到大
for(j=0;j<9;j++)
for(i=0;i<9-j;i++)
if(a[i]>a[i+1])
{
t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
define swap(x,y) (x = (x)+(y),y=(x)-(y), x=(x)-(y))
在页式虚拟存储管理中,如果访问的页面不在内存,产生缺页中断,将所缺页从外存
调入,如果内存没有空间需要将内存的一页淘汰,再将所缺页调入,然后计算出相应
的物理地址。
YY语音笔试:
用户程序发出磁盘请求后 用户程序 系统调用程序 设备驱动程序 中断
是C++新增的关键字,用于:1.用于防止类型被继承;2.用于防止虚函数被重写。
64位系统Int还是4字节
++优先级高于* *a++ 先指针++ 再取指针指向的值
求类的大小sizeof(A)=12
class A
{
public:
int a;// 4
static int b;//压根不属于这个类 不占空间
char e;
char c;//4
int d;
void fn() //不占空间
{printf("abvvvvvvb\n");}
};
使用红黑树的STL容器是map hash_map采用哈希表
template <class T> T fun(T x,T y) fun(1.0,2)是错误的 fun<float>
(1,2.0)是正确的
23树:
每个节点都有两个孩子或者三个 或者空
一个2节点有一个元素两个孩子或者没孩子
一个三节点包含一小一大两个元素和三个孩子
所以叶子在同一层次上
class a(b) 拷贝构造
class a=b 拷贝构造
class a,b; a=b 赋值操作符重载
const char *p="hello";
string s=static_cast<string>(p);
string s=const_cast<string>(p);//错误的
char *m=const_cast<char *>(p);
int *m=reinterpret_cast<int *>((char*)p);
引用可以实现多态 不能定义引用的引用
C++不能重载析构函数,只能声明为虚函数,只有构造函数才能重载构造函数和析构函数是两个非常特殊的函数:它们没有返回值.这与返回值为void的
函数显然不同
文件系统主要有三类
1. 位于磁盘的文件系统,在物理磁盘上存储文件,比如NTFS, FAT, ext3, ext4
2. 虚拟文件系统,在内核中生成,没有物理的存储介质
3. 网络文件系统,位于远程主机上的文件系统,通过网络访问
硬连接:ln
Unix/Linux系统允许,多个文件名指向同一个inode号码。
这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所
有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"
硬链接"(hard link)。 反过来,删除一个文件名,就会使得inode节点中的"链接数"减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。
软连接:ln -s
文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A
时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文
件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic
link)。
linux读取文件:
1、根据文件名,通过Directory里的对应关系,找到文件对应的Inode number
2、再根据Inode number读取到文件的Inode table
3、再根据Inode table中的Pointer读取到相应的Blocks
如果发送方速度高于接收方,则接收方可能因为套接字缓冲区满而丢弃后来接收到的
数据报。也就是说,此时数据虽然被接收方接收到了,但是没有被放进接收缓冲区(
因为缓冲区已满,直接丢弃数据),没有被提交给上层应用程序。可以用SO_RCVBUF的setsockopt来修改缓冲区大小:
socket编程,如果client断电了,服务器如何快速知道???
有以下几个技术:
使用定时器(适合有数据流动的情况); 使用socket选项SO_KEEPALIVE(适合没有
数据流动的情况);
C++模板的作用。
将算法与具体对象分离,与类型无关,通用,节省精力
保证函数的可重入性的方法:
在写函数时候尽量使用局部变量(例如寄存器、堆栈中的变量),对于要使用的全
局变量要加以保护(如采取关中断、信号量等方法),这样构成的函数就一定是一个
可重入的函数。
编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等
手段对其加以保护。
问题1,如何编写可重入的函数?
答:在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变
量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保
护全局变量。
问题2,如何将一个不可重入的函数改写成可重入的函数?
答:把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写它。其实
很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。
1) 不要使用全局变量。因为别的代码很可能覆盖这些变量值。
2) 在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是
关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”。
3) 不能调用其它任何不可重入的函数。
4) 谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。
Linux 守护进程出错处理:
由于守护进程完全脱离了终端,因此不能只是写到标准出错上。通常使用的方法是使
用syslog服务,将出错信息输入到”/var/log/message”系统日志文件中去。
Syslog是Linux中的系统日志管理服务,通过守护进程syslog来维护。
处理过程
<1>打开syslog
<2>写入日志
<3>关闭syslog
线程特定数据,也被称为线程私有数据,是一种存储和查找一个特定线程相关数
据的机制。我们称这个数据为线程特定或线程私有的原因,是因为每个线程访问它自
己独立的数据拷贝,而不用担心和其它线程的访问的同步。
4.在一个只有128M内存并且没有交换分区的机器上,说说下面两个程序的运行结果
1,
#define MEMSIZE 1024*1024
int count = 0;
void *p = NULL;
while(1) {
p = (void *)malloc(MEMSIZE);
if (!p) break;
printf("Current allocation %d MB\n", ++count);
}
2,
while(1) {
p = (void *)malloc(MEMSIZE);
if (!p) break;
memset(p, 1, MEMSIZE);
printf("Current allocation %d MB\n", ++count);
}
第一道程序分配内存但没有填充,编译器可能会把内存分配优化掉,程序死循环;第
二道,程序分配内存并进行填充,系统会一直分配内存,直到内存不足,退出循环。
自旋锁和信号量在互斥使用时需要注意哪些?在中断服务程序里面的互斥是使用自旋
锁还是信号量?还是两者都能用?为什么?
答:使用自旋锁的进程不能睡眠,使用信号量的进程可以睡眠。中断服务例程中的互
斥使用的是自旋锁,原因是在中断处理例程中,硬中断是关闭的,这样会丢失可能到
来的中断。
创建进程的调用时 clone vfork fork
linux伙伴算法:
假设要请求一个256 个页框的块(即1MB)。算法先在256 个页框的链表中检查是否
有一个空闲块。如果没有这样的块,算法会查找下一个更大的页块,也就是,在512
个页框的链表中找一个空闲块。如果存在这样的块,内核就把256 的页框分成两等份,一半用作满足请求,另一半插入到256 个页框的链表中。如果在512 个页框的块链表中也没找到空闲块,就继续找更大的块 —— 1024个页框的块。如果这样的块存在
,内核把1024个页框块的256 个页框用作请求,然后从剩余的768 个页框中拿512个
插入到512个页框的链表中,再把最后的256个插入到256个页框的链表中。如果1024
个页框的链表还是空的,算法就放弃并发出错信号。