华为面试常用考题汇总
一、const用法
const是一个C语言的关键字,它限定一个变量不允许被改变。
范例:
int const nValue; // nValue是const
char const * pContent;// *pContent是const, pContent可变
(char *) const pContent;//pContent是const,*pContent可变
char* const pContent;// pContent是const,*pContent可变
char const* const pContent;// pContent和*pContent都是const
二、sizeof用法
sizeof是C语言的一种单目操作符,它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类
型名。操作数的存储大小由操作数的类型决定。
1、用于数据类型
sizeof使用形式:sizeof(type)数据类型必须用括号括住。如sizeof
(int)。
2、用于变量
sizeof使用形式:sizeof(var_name)或sizeof var_name
3、sizeof的结果
3.1、int、unsigned int 、short int、unsigned short、long int、unsigned long、float,double、long double类型的sizeof分别为2、2、2、2、4、4、
4、8、10。
3.2、当操作数是指针时,sizeof的值为4 3.3、当操作数具有数组类型时,其结果是数组的总字节数。 3.4、联合类型操作数的sizeof是其最大字节成员的字节数。
在内。
4、sizeof和强制字节对齐程序范例
#incldue<stdio.h> #include<string.h> using namespace std; 3.5、结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补
struct { short a1; short a2; short a3; }A; struct { long a1; short a2; }B; int main()
{
char* ss1 = "0123456789"; char ss2[] ="0123456789"; char ss3[100] = "0123456789";
int ss4[100]; char q1[] = "abc"; char q2[] = "a\n"; char *q3 = "a\n";
char *str1 = (char*)malloc(100); void *str2 = (void*)malloc(100);
cout <<sizeof(ss1)<<" "; cout <<sizeof(ss2)<<" "; cout <<sizeof(ss3)<<" "; cout <<sizeof(ss4)<<" "; cout <<sizeof(q1)<<" "; cout <<sizeof(q2)<<" "; cout <<sizeof(q3)<<" "; cout <<sizeof(A)<<" "; cout <<sizeof(B)<<" "; cout <<sizeof(str1)<<" "; cout <<sizeof(str2)<<" ";
return 0; }
结果:4,11,100,400,4,3,4,6,8,4,4
三、static用法
1、修饰变量,static变量无论是定义在函数内或外,该变量都位于数据段中;定义于函数体外的static变量的访问域仅仅是它所在文件中定义的函数,其它文
件无法通过extern对其申明后访问。
2、修饰函数,static函数只能在声明它的文件当中可见,不能被其它文件使
用。
3、类中变量使用static修饰表示变量时类变量,类中函数用static修饰表示
函数只能访问类中的static变量,不接受this指针,称为类函数。
四、namespace用法
namespace是为了防止名字污染在标准 C++ 中引入的。它可以将其中定义的名字隐藏起来,不同的名字空间中可以有相同的名字而互不干扰,使用时用域
操作符(::)来引用。
namespace 名字
{ 定义的数据; } 定义的函数; 程序范例: #include <iostream> using namespace std;
namespace a
{ } { } {
} int sakura; namespace b int sakura; namespace int sakura;//相当于静态的全局变量,即作用域为该文件
int main()
{ b::sakura = 1; a::sakura = 2; sakura = 3;// 调用没有命名的名称空间 相当于静态的全局变量 cout << b::sakura << endl; cout << a::sakura << endl; cout << sakura << endl;
return 0;
五、传递内存错误范例
#include<stdio.h>
{ } { void GetMemory(char *p,int num) p = (char*) malloc(sizeof(char) *num); int main() char *str = NULL; GetMemory(str,100); strcpy(str,"hello");
return 0; } }
解析:本例GetMemory中为p开辟了新的内存,但是没有返回,str还是NULL,执行strcpy()函数时将出错,并且为P开辟的内容没有释放将造成内存泄露。
六、C++基本容器比较
1、vector:向量容器,使用线性存储结构,可以像数组一样随机(下标)访问元素,还可以在尾部插入元素(用push_back()函数)。特点:访问元素速度
快,但插入、删除操作速度慢;
2、list: 双向链表容器,数据元素是通过链表指针串连成逻辑意义上的线性表,但在物理内存中数据可以是不连续的。特点:对链表的任一位置的元素进行插入、删除和查找操作都是极快速的,但由于通过指针串连而成(这里的指针
也占用了内存空间),不能通过下标访问元素,因此list容器访问元素的速度比
vector慢;
3、deque: 双端队列容器,跟vector一样和采用线性表存储结构,但与vector唯一不同的是,deque采用分块的线性存储结构来存储数据,每块的大小一般为512字节,称为一个deque块,所有的deque块使用一个Map块进行管理,每个Map数据项记录各个deque块的首地址。特点:可以在deque块的头部和尾部插入和删除元素而不需移动其他元素,所以插入和删除操作速度比vector快。一般来说,当考虑到容器元素的内存分配策略和操作的性能时,deque相对于vector
更有优势。
总结:一般来说,当访问元素次数比较多时,用vector比较好;当插入、删除、查找元素的次数比较多时,用list比较好;当访问线性表的头部和尾部、插
入、删除次数较多时,用deque比较好;
七、指针和引用区别
1、非空区别。可以有空指针,没有指向空值的应用。
2、可修该区别。指针与引用的一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化是被指定的对象,以后不能
改变,但是指定的对象其内容可以改变。
3、应用区别。存在不指向任何对象的可能,在不同的时刻指向不同的对象时使用指针。总是指向一个对象并且一旦指向一个对象后就不会改变指向的情况
下应该使用应用。
八、函数重载
定义:所谓函数重载是指同一个函数名可以对应着多个函数的实现。 函数重载类型包括:1、参数类型不同的函数重载。如:add(5,10)和
add(5.0,10.0)
2、参数个不同的函数重载。如:add(int a,int b,int c)和
add(int a,int b)
九、进程和线程
1.定义:
进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他
的线程共享进程所拥有的全部资源.
2、线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如
程序计数器、一组寄存器和栈)。
3、linux下创建进程和线程:创建进程调用函数pid_t fork();创建线程调用函
数pthread_create()。
4、进程间通信:最常见的进程间通信包括:信号,信号量,消息队列,共
享内存。
十、模板
定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即
把类型定义为参数, 从而实现了真正的代码可重用性。
模版分类:1.函数模版
2.另外一个是类模版。 函数模板的一般形式如下: Template <classT>返回类型 函数名(形参表)
{//函数定义体 }
说明:template是一个声明模板的关键字,表示声明一个模板关键字class不能省略,如果类型形参多余一个 ,每个形参前都要加class <类型 形参表>可
以包含基本数据类型可以包含类类型.
程序范例:
#include <iostream> using std::cout; using std::endl;
//声明一个函数模版,用来比较输入的两个相同数据类型的参数的大小,class也可
以被typename代替,//T可以被任何字母或者数字代替。
template <class T> T min(T x,T y) { return(x<y)?x:y;} { int n1=2,n2=10; double d1=1.5,d2=5.6; void main( ) cout<< "较小整数:"<<min(n1,n2)<<endl;
cout<< "较小实数:"<<min(d1,d2)<<endl;
system("PAUSE"); }
程序分析:main()函数中定义了两个整型变量n1 , n2 两个双精度类型变量d1 , d2然后调用min( n1, n2); 即实例化函数模板T min(T x, T y)其中T为int型,求
出n1,n2中的最小值.同理调用min(d1,d2)时,求出d1,d2中的最小值.
类模板的一般形式如下:
Template < classT >class类名{
//类定义...... };
说明:其中,template是声明各模板的关键字,表示声明一个模板,模板参数
可以是一个,也可以是多个。
程序范例:
// ClassTemplate.h
#ifndef ClassTemplate_HH
#define ClassTemplate_HH
template<typename T1,typename T2>
class myClass{
private:
T1 I;
T2 J;
public:
myClass(T1 a, T2 b);//Constructor
void show();
};
//这是构造函数 //注意这些格式 template <typename T1,typename T2> //这是void show(); myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){} template <typename T1,typename T2>
void myClass<T1,T2>::show() { cout<<"I="<<I<<", J="<<J<<endl;
} #endif // Test.cpp #include <iostream> #include "ClassTemplate.h" using std::cout; using std::endl; void main() { myClass<int,int> class1(3,5); class1.show(); class2.show(); class3.show(); system("PAUSE");
十一、tcp/ip协议基本知识
1、名词解释 } myClass<int,char> class2(3,'a'); myClass<double,int> class3(2.9,10);
IP:网间协议(Internet Protocol) 负责主机间数据的路由和网络上数据的存储。同时为ICMP,TCP,UDP提供分组发送服务。用户进程通常不需要涉及这
一层。
ARP:地址解析协议(Address Resolution Protocol)此协议将网络地址映射到
硬件地址。
RARP: 反向地址解析协议(Reverse Address Resolution Protocol)此协议将硬
件地址映射到网络地址
ICMP: 网间报文控制协议(Internet Control Message Protocol)此协议处理信
关和主机的差错和传送控制。
TCP: 传送控制协议(Transmission Control Protocol)这是一种提供给用户进程的可靠的全双工字节流面向连接的协议。它要为用户进程提供虚电路服务,并
为数据可靠传输建立检查。(注:大多数网络用户程序使用TCP)
UDP: 用户数据报协议(User Datagram Protocol)这是提供给用户进程的无连
接协议,用于传送数据而不执行正确性检查。
FTP: 文件传输协议(File Transfer Protocol)允许用户以文件操作的方式(文
件的增、删、改、查、传送等)与另一主机相互通信。
SMTP: 简单邮件传送协议(Simple Mail Transfer Protocol)SMTP协议为系统
之间传送电子邮件。
TELNET:终端协议(Telnet Terminal Procotol)允许用户以虚终端方式访问远
程主机
HTTP: 超文本传输协议(Hypertext Transfer Procotol)
TFTP: 简单文件传输协议(Trivial File Transfer Protocol)
2、TCP/IP特点
TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。因此用户一般不涉及。编程时,编程界面有两种形式:一、是由内核心直接提供的系统调用;二、使用以库函数方式提供的各种函数。前者为核内实现,后者为核外实现。用户服务要通过核外
的应用程序才能实现,所以要使用套接字(socket)来实现。
2.1、套接字
套接字是网络的基本构件。它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。套接字存在通信区域(通信区域又称地址簇)中。套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。WINDOWS 中的套接字只支持一个域——网际域。
套接字具有类型。
WINDOWS SOCKET 1.1 版本支持两种套接字:流套接字(SOCK_STREAM)
和数据报套接字(SOCK_DGRAM)
2.2、WINDOWS SOCKETS 实现
一个WINDOWS SOCKETS 实现是指实现了WINDOWS SOCKETS规范所
描述的全部功能的一套软件。一般通过DLL文件来实现
2.3、阻塞处理例程
阻塞处理例程(blocking hook,阻塞钩子)是WINDOWS SOCKETS实现为了支
持阻塞套接字函数调用而提供的一种机制。
2.4、多址广播(multicast,多点传送或组播)
是一种一对多的传输方式,传输发起者通过一次传输就将信息传送到一组接
收者,与单点传送(unicast)和广播(Broadcast)相对应。
3、客户机/服务器模式
在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1、非对等作用;2、通信完
全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务:(过程如下)
1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户
请求。
2、等待客户请求到达该端口。
3、接收到重复服务请求,处理该请求并发送应答信号。
4、返回第二步,等待另一客户请求
5、关闭服务器。
客户端:
1、打开一通信通道,并连接到服务器所在主机的特定端口。
2、向服务器发送服务请求报文,等待并接收应答;继续提出请求……
3、请求结束后关闭通信通道并终止。
基本套接字
为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会
给出更详细的使用说明。
1、创建套接字——socket()
功能:使用前创建一个新的套接字
格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);
参数:af: 通信发生的区域
type: 要建立的套接字类型
procotol: 使用的特定协议
2、指定本地地址——bind()
功能:将套接字地址与所创建的套接字号联系起来。
格式:int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR *
name,int namelen);
参数:s: 是由socket()调用返回的并且未作连接的套接字描述符(套接
字号)。
其它:没有错误,bind()返回0,否则SOCKET_ERROR
地址结构说明:
struct sockaddr_in { short sin_family;//AF_INET u_short sin_port;//16位端口号,网络字节顺序
char sin_zero[8];//保留
} struct in_addr sin_addr;//32位IP地址,网络字节顺序
3、建立套接字连接——connect()和accept()
功能:共同完成连接工作
格式:int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR *
name,int namelen);
SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int
FAR * addrlen);
参数:同上
4、监听连接——listen()
功能:用于面向连接服务器,表明它愿意接收连接。
格式:int PASCAL FAR listen(SOCKET s, int backlog);
5、数据传输——send()与recv()
功能:数据的发送与接收
格式:int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int
flags);
int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);
参数:buf:指向存有传输数据的缓冲区的指针。
6、多路复用——select()
功能:用来检测一个或多个套接字状态。
格式:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR *
writefds,
fd_set FAR * exceptfds,const struct timeval FAR * timeout);
参数:readfds:指向要做读检测的指针
writefds:指向要做写检测的指针
exceptfds:指向要检测是否出错的指针
timeout:最大等待时间
7、关闭套接字——closesocket()
功能:关闭套接字s
格式:BOOL PASCAL FAR closesocket(SOCKET s);
面向连接的套件字的函数调用过程 服务器方: 1.socket()建立流式套接字,返回套接字号s 2.bind(),套接字与本地地址相连接 4.accept(),接收连接,等待客户端的连接 3.listen(),通知TCP服务器准备好接收连接 5.建立连接,accept()返回,得到新的套接字,如ns
6.recv()/send(),在套接字ns上读写数据,直到完成交换 7.closesocket(),关闭套接字ns
客户端: 8.closesocket(),关闭最初套接字s,服务结束 1.socket()建立流式套接字,返回套接字号s 2.connect(),将套接字s与远地主机连接 4.closesocket(),关闭套接字s,结束TCP对话
无连接协议的套接字的函数调用过程
服务器方: 1.socket()建立流式套接字,返回套接字号s 2.bind(),套接字与本地地址相连接 3.recv()/send(),在套接字上读写数据,直到完成数据交换
3.recv()/send(),在套接字ns上读写数据,直到完成交换 4.closesocket(),关闭最初套接字s,服务结束
客户端: 1.socket()建立流式套接字,返回套接字号s 2.bind(),套接字与本地地址相连接 4.closesocket(),关闭套接字s
十二、二叉树 3.recv()/send(),在套接字上读写数据,直到完成数据交换
1、二叉树:是个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。当集合为空
时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。
2、性质
2.1、一棵非空二叉树的第i层上最多有2i-1个结点(i≥1)。
2.2、一棵深度为k的二叉树中,最多具有2k-1个结点。
2.3、具有n个结点的完全二叉树的深度k为[log2n]+1。
3、遍历方式
3.1、前根遍:先遍历根节点,再遍历左节点,最后遍历右节点
3.2、中根遍历:先遍历左节点,再遍历根节点,最后遍历右节点
3.3、后根遍历:先遍历左节点,再遍历右节点,最后遍历根节点
4、二叉树查找范例:从二叉树中查找值为x的结点,若存在则返回元素存储
位置,否则返回空值
struct BTreeNode
{
char data;
struct BTreeNode *left; struct BTreeNode *right;
}; {
char *findBTree(struct BTreeNode *bt, char x)
if(bt == NULL)
{
return NULL;
} else { { }
else {
if(bt->data == x)
return &(bt->data);
/* 分别向左右子树递归查找 */
if(p = findBTree(bt->left, x))
十三、冒泡排序函数
1、原理:依次比较相邻的两个数,将小数放在前面,大数放在后面。
2、程序范例
}
{ return p; } { return p; }
if(p = findBTree(bt->right, x))
}
void bubble_sort(int a[],int n)
}
{ int i,j,temp; for(j =0;j < i;j++) { {
if(a[j] > a[j+1])
temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } }
for(i = n-1;i >0;i --)
十四、单链表的创建,插入,删除范例
#include<iostream> #include<stdio.h> using namespace std; typedef struct student
{ int data; }node; {
struct student* next; node *creat() node *head,*p1,*p2;
p1 = head; int x,flag = 1; while(flag)
{
head = node* malloc(sizeof(node));
printf("please input a num\n");
scanf("%d\n",&x);
if(x != 0)
{
p2 = (node*) malloc(sizeof(node));
p2 ->data = x; p1 ->next = p2;
p1 = p2; } else flag = 0; }
head = head ->next; p1 ->next = NULL; return head;
} {
node* del(node *head,int num)
node *p1,*p2; p1 = head;
{ p2 = p1; } {
{ free(p1); } else }
while(num != p1 ->data)
p1 = p1 ->next;
if(num == p1 ->data)
if(p1 == head) head = p1 -> next;
p2 ->next = p1 ->next;
else
printf("could not found %d\n",num);
return head;
}
node* insert(node* head,int num)
int main()
{
node *head,stud;
{
node *p0,*p1,*p2;
p1 = head;
p0 = (node*) malloc(sizeof(node));
p0 ->data = num;
{ p2 = p1; } { {
while(p0 ->data > p1 ->data && p1 ->next != NULL)
p1 = p1 ->next;
if(p0 ->data <= p1 ->data)
if(head == p1) p0 ->next = p1; head = p0;
} else {
p2 ->next = p0; p0 ->next = p1; } else { }
p1 ->next = p0; p0 ->next = NULL;
}
return head;
}
int n,del_num,insert_num;
head = creat();
printf("\nplease input the del_num:");
scanf("%d\n",del_num); head = del(head,del_num); scanf("%d\n",insert_num);
创建双链表
typedef struct student
{ int data; return 0; }
printf("\nplease input the insert_num:");
head = insert(head,insert_num);
struct student *next; struct student *pre;
}dnode;
{
dnode *creat() dnonde *head,*p,*s; int x,cycle = 1;
p = head; while(cycle)
{
head = (dnode*)malloc(sizeof(dnode));
printf("\nplease input the data:");
scanf("%d,&x");
if(x !=0)
{
s= (dnode*)malloc(sizeof(dnode));
s ->data =x; p ->next = s; s ->pre = p; p = s; }
else cycle = 0; } head = head ->next; head ->pre =NULL;
return head;
十五、gdb调试 }
1、gdb基本调试命令简介
1.1、编译选项-g,编译时须加入-g才能使用gdb对可执行文件进行调试调
试。
1.2、查看文件:l(list)。 1.4、查看断点信息:info b。 1.3、设置断点:b,如b6代表在程序第6行设置断点。 1.5、执行命令:r(run),如r 6,代表从程序第6行开始执行。 1.6、查看变量的值:p,如p i,表示查看变量i的值。
n不会进入该函数。 1.7、单步执行命令:n或者s,区别在于:若有函数调用时,s会进入该函数,
1.8、恢复程序运行:c,在使用C命令会把未执行的程序全执行完。
1.9、删除断点:delete。
十六、Makefile文件
1、Makefile的规则
target : prerequisites
command
target也就是一个目标文件,可以是Object File,也可以是执行文件。
prerequisites就是,要生成那个target所需要的文件。 command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内
容。
2、Makefile简单实例
如果一个工程有3个头文件,和8个C文件则makefile文件如下:
edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o gcc -o edit main.o kbd.o command.o display.o \
件,冒号后是生成该执行文件所需的目标文件。
main.o : main.c defs.h
gcc -c main.c gcc -c kbd.c gcc -c command.c gcc -c display.c gcc -c insert.c gcc -c search.c
gcc -c files.c
gcc -c utils.c
clean : insert.o search.o files.o utils.o //edit是要生成的可执行文kbd.o : kbd.c defs.h command.h command.o : command.c defs.h command.h display.o : display.c defs.h buffer.h insert.o : insert.c defs.h buffer.h search.o : search.c defs.h buffer.h files.o : files.c defs.h buffer.h command.h utils.o : utils.c defs.h
rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 解析:1、反斜杠(\)是换行符的意思。把这个内容保存在文件为“Makefile”
件edit。 或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文
2、如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。 3、目标文件(target)包含:执行文件edit和中间目标文件(*.o) 4、依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h
文件。
3、Gcc参数表
参数 含义
-c 只编译不连接,生成目标文件".o"
-g
-S -E 只编译不汇编,生成汇编代码 只进行预编译,不做其他处理 试) 在可执行程序中包含标准调试信息(可执行文件可用GDB调
-w 吧输出文件输出到file里 连接名为library的库文件 关闭所有告警 -o file -library
-Wall Gcc提供的所有有用的报警信息 允许打印出