求职指南网 > 面试试题 >

c语言面试常见问题及答案

时间: 淑娟 面试试题

招聘方会发出一个c语言面试邀请,通过笔试来选筛首批面试合格人员,然后进行二轮面试。今天小编整理了c语言面试常见问题及答案供大家参考,一起来看看吧!

c语言面试常见问题及答案

c语言面试常见问题

分析下面的程序,指出程序中的错误:

本题解析

没有正确为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然编译的时候没有报错,但是在运行过程中,因为越界访问了未被分配的内存,而导致段错误。

相关知识点

在处理与指针相关的问题时,首先需要搞明白的就是内存,因为指针操作的就是内存。

第一个,就是内存的分区。这也是经常会被考察的一个考点。

写出内存分为几大区域

对于这个问题,有几种不同的说法,有的说内存分为五大分区,有的说分为四大分区,我们先来看五大分区的说法:

认为内存分为五大分区的人,通常会这样划分:

1、BSS段( bss segment )

通常是指用来存放程序中未初始化的'全局变量和静态变量 (这里注意一个问题:一般的书上都会说全局变量和静态变量是会自动初始化的,那么哪来的未初始化的变量呢?变量的初始化可以分为显示初始化和隐式初始化,全局变量和静态变量如果程序员自己不初始化的话的确也会被初始化,那就是不管什么类型都初始化为0,这种没有显示初始化的就 是我们这里所说的未初始化。既然都是0那么就没必要把每个0都存储起来,从而节省磁盘空间,这是BSS的主要作用)的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。 BSS节不包含任何数据,只是简单的维护开始和结束的地址,即总大小。以便内存区能在运行时分配并被有效地清零。BSS节在应用程序的二进制映象文件中并不存在,即不占用 磁盘空间 而只在运行的时候占用内存空间 ,所以如果全局变量和静态变量未初始化那么其可执行文件要小很多。

2、数据段(data segment)

通常是指用来存放程序中已经初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配,可以分为只读数据段和读写数据段。字符串常量等,但一般都是放在只读数据段中。

3、代码段(code segment/text segment)

通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等,但一般都是放在只读数据段中 。

4、堆(heap)

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或 缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张); 当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

5、栈 (stack)

栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}” 中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外, 在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值 也会被存放回栈中。由于栈的先进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

而四大分区的说法,则这么认为:

1、堆区:

由程序员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间。使用malloc或者new进行堆的申请,堆的总大小为机器的虚拟内存的大小。

说明:new操作符本质上是使用了malloc进行内存的申请,new和malloc的区别如下:

(1)malloc是C语言中的函数,而new是C++中的操作符。

(2)malloc申请之后返回的类型是void__,而new返回的指针带有类型。

(3)malloc只负责内存的分配而不会调用类的构造函数,而new不仅会分配内存,而且会自动调用类的构造函数。

2、栈区:

由系统进行内存的管理。主要存放函数的参数以及局部变量。在函数完成执行,系统自行释放栈区内存,不需要用户管理。整个程序的栈区的大小可以在编译器中由用户自行设定,VS中默认的栈区大小为1M,可通过VS手动更改栈的大小。64bits的Linux默认栈大小为10MB,可通过ulimit -s临时修改。

3、静态存储区:

静态存储区内的变量在程序编译阶段已经分配好内存空间并初始化。这块内存在程序的整个运行期间都存在,它主要存放静态变量、全局变量和常量。

注意:

(1)这里不区分初始化和未初始化的数据区,是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。

(2)静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。

(3)字符串常量存储在静态存储区的常量区,字符串常量的名称即为它本身,属于常变量。

(4)数据区的具体划分,有利于我们对于变量类型的理解。不同类型的变量存放的区域不同。后面将以实例代码说明这四种数据区中具体对应的变量。

4、代码区:

存放程序体的二进制代码。比如我们写的函数,都是在代码区的。

通过上面的不同说法,我们也可以看出,这两种说法本身没有优劣之分,具体的内存划分也跟编译器有很大的关系,因此这两种说法都是可以接受的,搞明白内存的分区之后,指针的使用才能够更加的灵活。

C语言知识点

冒泡排序

平均复杂度是O(N^2)

最好情况是O(1) 本身就是排好序的

最坏就是倒序O(N^2)

空间复杂度是O(1)

冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序工作。

class Sort{ public: void MaoPao_Sort(vector&arr){ //1.判断溢出条件 if(arr.size() <2) return; int length =arr.size(); for(int i =0;i < length;i++){ for(int j=0; j < length -i -1 ;j++){ if(arr[j] >arr[j+1]){ int temp = arr[j]; arr[j]= arr[j+1]; arr[j+1]=temp; } } } } };

插入排序

插入排序思想的由来,其实就是按照在一个有序的数组中插入一个元素的思想,找到合适的位置进行插入并迁移后面的元素

首先,我们将数组中的数据分为两个区间,已排序区间和未排序区间。初始已排序区间只有一个元素,就是数组的第一个元素。插入算法的核心思想是取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。重复这个过程,直到未排序区间中元素为空,算法结束。

class Sort{ public: void Insert_Sort(vector&arr){ //1.判断溢出条件 if(arr.size() < 2) return; int length =arr.size(); int j =0;//初始的已排序区间的下标 for(int i =1;i < length ;i++){ //从未排序的区间里面取元素 int temp =arr[i]; j =i-1; //不断更新已排序区间 while(j >= 0 && temp <a[j]){ p="" };

选择排序

选择排序算法的实现思路有点类似插入排序,也分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾

class Sort{ public: void Select_Sort(vector&arr ,int length){ for(int i =0;i < length -1;i++){ int min_number =arr[i]; int flag = i; for(int j =i;jarr[j]){ min_number = arr[j]; flag =j; } } //交换数字 arr[flag] =arr[i]; arr[i]=min_number; } } };

归并排序

归并排序是由下而上,采用分治的思想,把数据先拆分在合并,并把合并后的数据存入临时数组中,保证原先的数据位置不发生变化,是一种稳定的排序但不是原地排序,时间复杂度是O(nlogn),空间复杂度是O(N)

class Sort{ public: //归并排序 void MergeSort(vector& arr){ if(arr.size() < 2){ return ; } //拆分函数 Merge_Process(arr,0,arr.size())-1); } //先拆分,这是拆分函数 void Merge_Process(vector&arr,int start,int end){ //递归拆分,首先需要递归的终止条件 if(end -start == 0) return; int mid =((end -start)/2) +start; Merge_Process(arr,start,mid); Merge_Process(arr,mid+1,end); //在合并 Merge(arr,start,mid,end); } //合并函数 void Merge(vector&arr,int start,int mid, int end){ vectortemp(end-start+1,0);//初始化一个临时数组 int tempIndex =0; //辅助空间索引 int leftIndex =start; int rightIndex =mid+1; while(leftIndex <= mid && rightIndex <= end){ if(leftIndex<rightindex){ p="" };<="" }="" arr[start+i]="temp[i];" temp.size();i++){="" i="0;i<" for(int="" temp[tempindex++]="arr[leftIndex++];"

快速排序

快速排序是先分区,在处理子问题,通过找到区间后取得任意一个分区点,小的放分区点左边,大的放分区点右边,时间复杂度是O(nlong),空间复杂度是O(1),是原地排序但不是稳定排序

快排优化的话,有:三数取中法,和随机法,都是为了防止要排序的数组中有重复元素,这块我演示的是随机法

class Sort{ public: void quickSort(vector&arr,int begin, int low){ if(begin<end){ i="begin;" arr[j]="" while(i<j&&="" = base){ j--; } num[i]=num[j]; while(i<j p="" };<="" }=""

面试常见问题总结

1.首先,开场白是自我介绍。

也许面试官在你之前已经问了n多位同学的自我介绍了,所以此时你的自我介绍别陷入老套,比如从叫什么名字(简历上本来就有),来自什么学校什么的,这会一开始让面试官失去兴趣,记得当初面试华为时,已是快中午十二点了,面试官早上已经面试了一个上午,此时正急着等着吃饭呢(表面上是不会表现出来的啦),我当时很傻很天真地按我原先已经准备好的自我介绍从头说。可想而知,面试官对你没什么好的印象。其实,比较恰当的做法是,看准形势,尽量能有与众不同的自我介绍,比如可以在自己名字上做文章,用一两句话让人一下子就记住你了。

2.谈谈自己性格的`优缺点。

这个问题必须事先准备好几个优缺点,并根据岗位有针对性的说一两个,还要附加几个典型的例子,加以说明。

3.有关于自身的职业规划。

最好能结合自身的特点、职位等内容,说得与他人不太一样,别总是说先做技术,再做管理什么的。

4.你有什么问题要问的。

之前都是老是被面试官问,现在突然要你向他(她)提问问题,还有点不适应,如果没有事先做准备,一下子会被问焖了。

28114