找工作笔试面试经验总结(C语言基础部分)

2017年9月14号,辞去了在伟易达的工作,怎么说,待了两年了,提辞职不太好说出口,但人各有志,我还是希望能去外面接触更多的东西,也希望能够多认识一些人,丰富我的社交经验。

纵观好几个公司的笔试面试经验,都考得比较简单,笔试和面试不会是那种特别难的题目,基本上都是基础知识,所以我一再告诉我的师弟师妹,出来工作,除了一些比较牛逼的公司出的题比较异类以外,其余的绝大多数公司,考的题目都是比较基础的,所以,基础是非常重要的。下面我就根据我笔试的回忆,考的最多依然是C语言基础,写出以下考到的题目:

(1) ++a 和 a++的区别?哪个效率要高一些?

答:++”运算符被称为自增运算符。如果“++”运算符出现在变量的前面(++a(变量)),那么在表达式使用变量之前,变量的值将增加1。如果“++”运算符出现在变量之后((变量)a++),那么先对表达式求值,然后变量的值才增加1。

效率问题,可以参考这个博客:http://blog.csdn.net/gao1440156051/article/details/51570490

如以下程序:

#include <stdio.h>
int main(void)
{
	int a = 2 ; 
	int b = 3 ;
	int c ; 
	c = ++a - b++ ; 
	printf("a=%d b=%d c=%d\n",a,b,c);
	return 0 ;
}
运行结果:

a=3,b=4,c=0

很明显,根据上面的理论可以得知,a是前加a,所以a是先加1后赋值,所以a = 2+1 = 3 ;

b是后加,所以b的值在c=++a - b++;这个表达式的时候,它的值不变,依然为3,但由于在后面使用printf进行打印的时候,由于b++的先赋值后加,所以b最终的结果为4。由于表达式c=++a - b++,b的值仅仅只是先赋值,所以b的值此时为3,a先加后赋值,所以a为3,可推出c=0。

(2)=和==的区别

#include <stdio.h>
int main(void)
{
	int a = 1 ; 
	int b = 0 ;
	if(a=1)
		b = 3 ; 
	if(a=2)
		b = 5 ; 
	printf("b:%d\n",b);
}
运行结果为5。

为什么?因为=号是赋值操作,if(条件表达式)语句中,条件表达式只要为真,就会执行语句块里的程序,所以a=1为真,b=3,当a=2的时候,也为真,所以最终b=5。

#include <stdio.h>
int main(void)
{
	int a = 1 ; 
	int b = 0 ;
	if(a==1)
		b = 3 ; 
	if(a==2)
		b = 5 ; 
	printf("b:%d\n",b);
}
运行结果为3。

为什么?因为==是关系运算符,此时相当于比较a和一个数是否相等,如果相等,则会执行语句块的内容,因此,a等于1,条件成立,所以最终结果b=3。

(3)值传递和地址传递

#include <stdio.h>
int add(int x,int j)
{
	x+= j*10 ;
}
int main(void)
{
	int i ;
	int num = 100 ; 
	for(i = 0 ; i < 5 ; i++)
	{
		add(num,i);
		printf("i=%d,num:%d\n",i,num);
	}
	return 0 ;
}
运行结果:

i = 0 , num = 100 ; 

i = 1 , num = 100 ; 

i = 2 , num = 100 ; 

i = 3 , num = 100 ; 

i = 4 , num = 100 ; 

为什么?

调用add函数的时候,执行语句:num += i*10 ; 其实只是对该函数的形参进行操作,并没有对i和num进行操作,所以num的值没有进行任何更改,故打印的结果都是原始值100。

#include <stdio.h>
int add(int *x,int j)
{
	*x+= j*10 ;
}
int main(void)
{
	int i ;
	int num = 100 ; 
	for(i = 0 ; i < 5 ; i++)
	{
		add(&num,i);
		printf("i=%d,num:%d\n",i,num);
	}
	return 0 ;
}
输出结果:

i = 0 , num = 100 ; 

i = 1 , num = 110 ; 

i = 2 , num = 130 ; 

i = 3 , num = 160 ; 

i = 4 , num = 200 ; 

为什么?

此时,函数add的第一个参数传递的是num地址,这就是C语言间接引用的技巧,也就是地址传递了。这时候到了add函数里面,此时x的地址就是num的地址,x的操作等同于操作num,所以最后num的输出结果肯定是不同的。

(4)共用体大小端相关问题

#include <stdio.h>
int main(void)
{
	union{
		int num ; 
		unsigned char n[4] ;
	}q;
	int i ;
	q.num = 10 ;
	for(i = 0 ; i < 4 ;i++)
		printf("%x ",q.n[i]);
	return 0 ;
}
运行结果:

a 0 0 0

共用体,简单的理解也就是共用一段内存,也就是说此时共用体中的num和数组n的起始地址都是一样的,我们可以用:printf("num:%p\nn:%p\n",&q.num,&q.n);打出来看看。

当然,运行结果在大小端的影响下,可能不同。

大端存储:指的是数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。

小端存储:指的是数据的低字节保存在内存的高地址中,而数据的高字节保存在内存的高地址中。在32位机中,

如果为小端模式,值为:a 0 0 0

如果为大端模式,值为:a0000000 0 0 0 0

以上的运行结果,可以说明,该32位机器的输出结果a 0 0 0是小端模式。

(5)用C语言实现冒泡排序:

参考以前的博客:http://blog.csdn.net/morixinguan/article/details/50647028
(6)用C语言实现单链表的删除和插入函数:

参考以前的博客:http://blog.csdn.net/morixinguan/article/details/77756216

(7)不调用库函数,实现strcpy函数的功能:

#include <stdio.h>
#include <assert.h>
char *strcpy(char *dest , const char *src)
{
	//1.检查参数是否合法 
	assert(dest != NULL && src != NULL);
	//2.定义新的变量来接收,不要直接去操作原来的数据 
	char *_dest = dest ; 
	const char *_src = src ;
	//3.进行赋值操作,判断是否到'\0' 
	while((*_dest ++ = *_src++) != '\0');
	//4.返回dest的地址 
	return _dest ;
}
int main(void)
{
	char *p = "hello world!";
	char buf[20] = {0};
	strcpy(buf,p);
	printf("%s\n",buf);
	return 0 ;
}
(8)setjmp和longjmp

请分析一下程序的输出结果:

#include <setjmp.h>
#include <stdio.h>
static jmp_buf buf;
main()    
{
    volatile  int b;
    b =3;
    
    if(setjmp(buf)!=0)
    {
        printf("%d ", b); 
        exit(0);
    }
    b=5;
    longjmp(buf , 1);
} 
参考博客解答:http://blog.csdn.net/wangkeyen/article/details/50658998

(9)全局变量,局部变量各有什么特点?

全局变量储存在全局区,局部变量在栈区。全局变量作用于当前的位置到文件的结尾,局部变量仅仅只作用于当前栈所在的区域,一旦栈被释放,局部变量存储的数据即是无意义的。比如:一个函数结束后,该函数内所有的自动变量所占用的内存空间都被释放,释放的含义是:通知系统,这些内存已经是*的了,可以被其他代码改写了。没有被改写前,这些内存中还是原来的值,至于什么时候改写,那谁也不知道。所以返回它们的地址是没有任何意义的。

参考百度:https://zhidao.baidu.com/question/982178744566405419.html

(10)volatile的作用是什么?

修饰符告诉编译程序不要对该变量所参与的操作进行某些优化。

1.内存映射硬件

2.共享内存

(11)static的作用是什么?

在函数外部说明为static 的变量的作用域为从定义点到该文件尾部;在函数内部说明为static 的变量的作用域为从定义点到该局部程序块尾部。static还有其它的特性:

1.static 修饰的局部变量的数值是上一次函数调用结束之后的数值

2.static 还可以修饰全局变量或者函数。静态局部变量在定义的时候没有初始化,系统会给定 0 为默认的初始值

3.基于static关键字的作用,定义一个static变量,结合switch语句,很容易实现状态机。

(12)用C语言实现判断大小端的方法的程序

#include <stdio.h>
#include <stdlib.h>
//用指针的方式检测机器的大小端模式
int small_port()
{
	int a = 1 ;
	char b = *((char *)(&a)) ;
	return b ;
}
int main(void)
{
	int i = small_port();
	if(1 == i)
		printf("小端模式\n");
	else
		printf("大端模式\n");
	return 0 ;
}

(13)变量数据范围的考查

在32位操作系统PC机上,运行以下程序:

#include <stdio.h>
int main(void)
{
	char a = 0x80 ;
	int b = a ;
	if(b < 0) b = 0;
	else b = 0x80;
	printf("b:%d \n",b);
	return 0 ;
}
运行结果:

b:0

为什么?char类型的变量的数据范围为-128 ~ +127,占用一个字节,char a = 0x80 , 0x80是正数128,显然已经越界,那么越界输出a则不是一个正数,而是一个负数。

关于C语言的数据范围的取值可以参考这个博客或者看C语言基础相关的书籍:

http://blog.csdn.net/abaloon/article/details/8173552

(14)三目运算符 

#include <stdio.h>
int main(void)
{
	char a = 100 ; 
	char c = a > 0 ? 'y' : 'n' ;
	printf("c:%c\n",c);
	return 0 ;
}
运行结果:

c: y

以上的题目都是比较简单的,没什么难度,都是考的比较基础的知识点。




上一篇:C语言的结构体和C++结构体的区别


下一篇:操作系统1