C/C++ 常见面试题目 (一)

C/C++ 常见面试题目

常见的题目,不一定用过,但一定要知道。

1. C语言中C程序运行时的内存分配机制

之前写的参考谭浩强的C语言书,写的没有那么准确,重新修改。
程序的内存分配:
(1)代码段code segment/data segment:
(2)数据段data segment:数据段又分为BSS和.data;
(3)堆head:
(4)栈stack:
如图所示:
这里写图片描述

代码段:一般也成为正文段,包含可执行的指令,代码段一般在堆和栈的存储空间下面,防止堆或栈溢出而覆盖写代码段。通常代码段是可共享的,内存中只存在一个副本,但可以被频繁执行。代码段是只读的,防止其他程序修改指令。常量保存在代码段,所有对常量的赋值,都会报segment fault。

数据段:分为两部分,BSS(block started by symbol),包含所有没有在源程序中初始化或者初始化为0的全局变量和静态变量。
.data段,包含所有被程序员初始化的全局变量和静态变量,.data段又可分为初始化的只读区域和初始化的可读可写的区域。

堆:堆开始于BSS段的结尾,由低地址向高地址增长,堆是由malloc、remalloc、free操作来管理。

栈:栈和堆相邻,栈的增长方向与堆相反。栈,存放程序定义的局部变量(不包括static声明的变量),函数被调用时,其参数、局部变量入栈,调用结束,依次出栈,函数返回值入栈。

从图中可以看出:·text段和.data段是在可执行文件中的,由系统从可执行文件中加载,而BSS段不是在可执行文件中的,由系统初始化。

int main(){
    char a=0, b=0;
    int *p = (int*)&b;
    *p = 258;
    printf("%d %d", a, b);
    return 0;
}

输出值:1 2
a, b属于局部变量,存储在栈空间中,先分配a的地址,再分配b的地址。因为栈是从上往下生长的,所以b的地址比a低一个字节。 然后对b的地址进行赋值258(int是4字节,二进制表示是0x00 00 01 02)。最后1字节0x02赋值给了b,接下来1字节0x01赋值给了a。
(小端模式)
参考:
[1] http://www.geeksforgeeks.org/memory-layout-of-c-program/
[2] http://www.wikiwand.com/en/Data_segment
[3]http://keendawn.blog.163.com/blog/static/888807432010314111152109/
[4] http://harttle.com/2015/07/22/memory-segment.html

2. C语言中全局静态变量和局部静态变量

接问题1,在C语言中,每个变量和函数有两个属性:数据类型和数据存储类型。定义变量,关心的是作用域和生存周期。
定义:
全局静态变量:实际上就是全局变量,一个程序中的全局变量全部存储在静态存储区中;
局部静态变量:指的是在某个函数中用关键字static定义的变量,这种变量的作用范围只在定义它的函数起作用,但是它存储在静态存储区。我们知道,在函数执行结束后,局部变量的内存空间会返回操作系统。但如果定义为静态局部变量,函数执行结束后静态局部变量不会被释放,仍然保存它的值。如果再次 调用这个函数时,我们就可以直接使用这个保存下来的值。
总结:
局部变量和静态局部变量:二者作用域相同,都只在定义的函数体,局部静态变量分配在静态存储区,函数执行结束后内存空间不被释放,局部变量分配在动态存储区,函数执行结束后内存空间被释放;
局部静态变量和全局静态变量:二者的存储区相同都在静态存储区,区别在于作用域,局部静态变量作用域仅限于定义的函数体,全局静态变量作用域在定义全局变量的整个文件中。
注意:
对静态变量的初始化是在编译阶段完成的。
存储方式分为两大类:静态存储和动态存储,具体包含4种,自动的(auto)、静态的(static)、寄存器的(register)、外边的(extern)。
如果想允许其它源文件访问本文件中的全局变量,在其它源文件中通 过使用关键字extern来定义全局变量。

3. C++中程序运行的内存分配机制

C++和C类似,稍微有些不同,用户的内存空间分为5个部分:
(1)栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效;

(2)堆(Heap):这里与C不同的是,该堆是由new申请的内存,由delete或delete[]负责释放;

(3)自由存储区(Free Storage):由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收;(常见内存分配算法有:首次适应算法、循环首次适应算法、最佳适应算法和最差适应算法等)

(4)全局区/静态区(Global Static Area): 全局变量和静态变量存放区,程序一经编译好,该区域便存在。在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了初始化变量和未初始化变量了。由于全局变量一直占据内存空间且不易维护,推荐少用。程序结束时释放。

(5)常量存储区: 这是一块比较特殊的存储区,专门存储不能修改的常量(如果采用非正常手段更改当然也是可以的了)。
参考:
[1] http://www.cnblogs.com/computerg/archive/2012/02/01/2334898.html

4. C语言中static关键字的具体作用

static变量:改变变量的生存周期,见问题1;
static函数:有说是隐藏作用,是限定static函数只能被当前文件内的函数调用,其他文件中可以定义同名函数。

5. C++ static数据成员和成员函数

为什么要有static数据成员?
在C++面向对象编程过程当中,对象与对象之间的数据不是共享,在设计类的时候,有时候需要一些对象之间共享的数据,除了把所要共享的数据设置为全局数据或者函数之外,还可以利用C++的静态机制。
C++ static数据成员:
静态数据成员实际上是类域中的全局变量。
静态数据成员是所有对象共享的,其所占的内存空间不会因为某个对象的产生而分配,也不会因为对象的销毁而消失。跟类中其他的非静态数据成员一样,被定义为private时,不能被外界访问。但是可以被类内任意访问权限的函数访问。
静态数据成员在类内定义,在类外初始化。
静态数据成员的初始化:非静态成员可以在构造函数当中初始化,但是static不能在构造函数当中初始化,它的初始化,只能存在于全局区域,并且要指明是什么类的静态成员,可以用作用域符号“::”来指明。
类名::静态数据成员

C++ static成员函数:
静态成员函数当中不能访问任何权限的非静态数据成员,换句话说它只能访问static。在类外部调用静态成员函数的时候,不是简单的
对象.静态成员函数,这是普通成员函数的做法,类名::静态成员函数。参考[3]讲得好。
参考:
[1] https://msdn.microsoft.com/zh-cn/library/b1b5y48f(v=vs.120).aspx
[2] http://www.cnblogs.com/daoluanxiaozi/archive/2011/12/03/2274636.html
[3] http://blog.sina.com.cn/s/blog_5f0d72800100swkz.html

6. C++ static const

参考[1]对比的好:
const定义的常量在函数执行之后其空间会被释放,而static定义的静态常量在函数执行后不会被释放其空间。
static 表示的是静态的。类的静态成员函数,成员变量是和类相关的,不是和类的具体对象相关,即使没有具体的对象,也能调用类的静态成员函数,成员变量。一般的静态函数几乎就是一个全局函数,只不过它的作用域限于包含它的文件中。

在c++中,static静态成员变量不能在类内部初始化。
在c++中,const常量成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数。

const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。
const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static const。
参考:
[1] http://blog.sina.com.cn/s/blog_60be7ec80100gzhm.html

7. 构造函数

7.1 构造函数的作用

构造函数主要用来在创建对象时完成对对象的数据成员一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。一般来说, 构造函数有以下三个方面的作用:
■ 给创建的对象建立一个标识符;
■ 为对象数据成员开辟内存空间;
■ 完成对象数据成员的初始化。

7.2 默认构造函数

当用户没有显式的去定义构造函数时, 编译器会为类生成一个默认的构造函数, 称为 “默认构造函数”, 默认构造函数不能完成对象数据成员的初始化, 只能给对象创建一标识符, 并为对象中的数据成员开辟一定的内存空间。

7.3 构造函数的特点

无论是用户自定义的构造函数还是默认构造函数都主要有以下特点:
①. 构造函数与类同名;
②. 构造函数没有返回类型,没有返回值;
③. 构造函数可以被重载;
④. 构造函数在程序创建对象时由系统自动调用,不允许在程序中显示调用。
参考:
[1] http://www.cnblogs.com/mr-wid/archive/2013/02/19/2917911.html
[2] http://ticktick.blog.51cto.com/823160/194307

8. 析构函数

与构造函数相反, 析构函数是在对象生存期结束时被自动调用完成对象的清理工作,例如释放在构造函数中使用 new 或 malloc 分配的内存空间。析构函数具有以下特点:
①. 析构函数函数名与类名相同, 紧贴在名称前面用波浪号 ~ 与构造函数进行区分, 例如: ~Point();
②. 构造函数没有返回类型, 也不能指定参数, 因此析构函数只能有一个, 不能被重载;
③. 析构函数不可以被重载;
④. 当对象被撤销时析构函数被自动调用, 与构造函数不同的是, 析构函数可以被显式的调用, 以释放对象中动态申请的内存。
注意:
当用户没有显式定义析构函数时, 编译器同样会为对象生成一个默认的析构函数, 但默认生成的析构函数只能释放类的普通数据成员所占用的空间, 无法释放通过 new 或 malloc 进行申请的空间, 因此有时我们需要自己显式的定义析构函数对这些申请的空间进行释放, 避免造成内存泄露。
另外:
构造函数和析构函数的调用顺序,如果有多个对象同事结束生存期,C++将按照与调用构造函数相反的次序调用析构函数。

Q1:构造函数能否重载,析构函数能否重载,为什么?
A1:构造函数可以,析构函数不可以。
Q2:析构函数为什么一般情况下要声明为虚函数?
A2:虚函数是实现多态的基础,当我们通过基类的指针析构子类对象时,如果不定义成虚函数,那只调用基类的析构函数,子类的析构函数将不会被调用。如果定义为虚函数,则可以调用子类析构函数。

9. sizeof

sizeof是C/C++中的一个操作符,简单的说其作用就是返回一个对象 或者 类型所占的内存字节数。
如:当对数组名做sizeof操作,返回的是整个数组中元素占用的总字节数,如果将数组名做为实参传递给函数,在函数内做sizeof操作,数组名退化成一指针,sizeof返回的保存指针变量占用的字节数。

c面试题 4. static有什么用途?(请至少说明两种) 1.限制变量的作用域 2.设置变量的存储域 7. 引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 2) 不存在指向空值的引用,但是存在指向空值的指针。 8. 描述实时系统的基本特性 在特定时间内完成特定的任务,实时性与可靠性 9. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈 10. 什么是平衡二叉树? 左右子树都是平衡二叉树且左右子树的深度差值的绝对值不大于1 11. 堆栈溢出一般是由什么原因导致的? 没有回收垃圾资源 12. 什么函数不能声明为虚函数? constructor 13. 冒泡排序算法的时间复杂度是什么? O(n^2) 14. 写出float x 与“零值”比较的if语句。 if(x>0.000001&&x<-0.000001) 16. Internet采用哪种网络协议?该协议的主要层次结构? tcp/ip 应用层/传输层/网络层/数据链路层/物理层 17. Internet物理地址和IP地址转换采用什么协议? ARP (Address Resolution Protocol)(地址解析協議) 18.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。 2.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。 循环链表,用取余操作做 3.不能做switch()的参数类型是: switch的参数不能为实型。 華為 1、局部变量能否和全局变量重名? 答:能,局部会屏蔽全局。要用全局变量,需要使用"::" 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内 2、如何引用一个已经定义过的全局变量? 答:extern 可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错 3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么? 答:可以,在不同的C文件中以static形式来声明同名全局变量。 可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错 4、语句for( ;1 ;)有什么问题?它是什么意思? 答:和while(1)相同。 5、do……while和while……do有什么区别? 答:前一个循环一遍再判断,后一个判断以后再循环 6、请写出下列代码的输出内容 #include<stdio.h> main() { int a,b,c,d; a=10; b=a++; c=++a; d=10*a++; printf("b,c,d:%d,%d,%d",b,c,d); return 0; } 答:10,12,120 1、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别? 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。 从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。 static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件 static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用; static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值; static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝 2、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区)中,动态申请数据存在于(堆)中。 3、设有以下说明和定义: typedef union {long i; int k[5]; char c;} DATE; struct data { int cat; DATE cow; double dog;} too; DATE max; 则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:___52____ 答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20 data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32. 所以结果是 20 + 32 = 52. 当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20 4、队列和栈有什么区别? 队列先进先出,栈后进先出 5、写出下列代码的输出内容 #include<stdio.h> int inc(int a) { return(++a); } int multi(int*a,int*b,int*c) { return(*c=*a**b); } typedef int(FUNC1)(int in); typedef int(FUNC2) (int*,int*,int*); void show(FUNC2 fun,int arg1, int*arg2) { INCp=&inc; int temp =p(arg1); fun(&temp,&arg1, arg2); printf("%d"n",*arg2); } main() { int a; show(multi,10,&a); return 0; } 答:110 7、请找出下面代码中的所以错误 说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba” 1、#include"string.h" 2、main() 3、{ 4、 char*src="hello,world"; 5、 char* dest=NULL; 6、 int len=strlen(src); 7、 dest=(char*)malloc(len); 8、 char* d=dest; 9、 char* s=src[len]; 10、 while(len--!=0) 11、 d++=s--; 12、 printf("%s",dest); 13、 return 0; 14、} 答: 方法1: int main(){ char* src = "hello,world"; int len = strlen(src); char* dest = (char*)malloc(len+1);//要为"0分配一个空间 char* d = dest; char* s = &src[len-1];//指向最后一个字符 while( len-- != 0 ) *d++=*s--; *d = 0;//尾部要加"0 printf("%s"n",dest); free(dest);// 使用完,应当释放空间,以免造成内存汇泄露 return 0; } 方法2: #include <stdio.h> #include <string.h> main() { char str[]="hello,world"; int len=strlen(str); char t; for(int i=0; i<len/2; i++) { t=str[i]; str[i]=str[len-i-1]; str[len-i-1]=t; } printf("%s",str); return 0; } 1.-1,2,7,28,,126请问28和126中间那个数是什么?为什么? 第一题的答案应该是4^3-1=63 规律是n^3-1(当n为偶数0,2,4) n^3+1(当n为奇数1,3,5) 答案:63 2.用两个栈实现一个队列的功能?要求给出算法和思路! 设2个栈为A,B, 一开始均为空. 入队: 将新元素push入栈A; 出队: (1)判断栈B是否为空; (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出; 这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。3.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么? 函数名: atol 功能: 把字符串转换成长整型数 用法: long atol(const char *nptr); 程序例: #include <stdlib.h> #include <stdio.h> int main(void) { long l; char *str = "98765432"; l = atol(lstr); printf("string = %s integer = %ld"n", str, l); return(0); } 2.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现? c用宏定义,c++用inline 3.直接链接两个信令点的一组链路称作什么? PPP点到点连接 4.接入网用的是什么接口? 5.voip都用了那些协议? 6.软件测试都有那些种类? 黑盒:针对系统功能的测试白合:测试函数功能,各函数接口 7.确定模块的功能和模块的接口是在软件设计的那个队段完成的? 概要设计阶段 8.enum string { x1, x2, x3=10, x4, x5, }x; 问x= 0x801005,0x8010f4 ; 9.unsigned char *p1; unsigned long *p2; p1=(unsigned char *)0x801000; p2=(unsigned long *)0x810000; 请问p1+5= ; p2+5= ; 三.选择题: 1.Ethternet链接到Internet用到以下那个协议? A.HDLC;B.ARP;C.UDP;D.TCP;E.ID 2.属于网络层协议的是: A.TCP;B.IP;C.ICMP;D.X.25 3.Windows消息调度机制是: A.指令队列;B.指令堆栈;C.消息队列;D.消息堆栈; 4.unsigned short hash(unsigned short key) { return (key>>)%256 } 请问hash(16),hash(256)的值分别是: A.1.16;B.8.32;C.4.16;D.1.32 四.找错题: 1.请问下面程序有什么错误? int a[60][250][1000],i,j,k; for(k=0;k<=1000;k++) for(j=0;j<250;j++) for(i=0;i<60;i++) a[i][j][k]=0; 把循环语句内外换一下 2.#define Max_CB 500 void LmiQueryCSmd(Struct MSgCB * pmsg) { unsigned char ucCmdNum; ...... for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++) { ......; } 死循环 3.以下是求一个数的平方的程序,请找出错误: #define SQUARE(a)((a)*(a)) int a=5; int b; b=SQUARE(a++); 4.typedef unsigned char BYTE int examply_fun(BYTE gt_len; BYTE *gt_code) { BYTE *gt_buf; gt_buf=(BYTE *)MALLOC(Max_GT_Length); ...... if(gt_len>Max_GT_Length) { return GT_Length_ERROR; } ....... } 五.问答题: 1.IP Phone的原理是什么? IPV6 2.TCP/IP通信建立的过程怎样,端口有什么作用? 三次握手,确定是哪个应用程序使用该协议 3.1号信令和7号信令有什么区别,我国某前广泛使用的是那一种? 4.列举5种以上的电话新业务?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值