C语言经典面试题学习

1. 请填写bool , float, 指针变量 与“零值”比较的if 语句。
提示:这里“零值”可以是0, 0.0 , FALSE 或者“空指针”
。例如int 变量n 与“零值”比较的if 语句为:
if ( n == 0 )
if ( n != 0 )
以此类推。
(1)请写出bool flag 与“零值”比较的if 语句:
【标准答案】 if ( flag ) if ( !flag )
个人解析:bool flag = FALSE;
if(flag) 等于if(FALSE)
if(!flag)等于if(TRUE)

(2)请写出float x 与“零值”比较的if 语句:
【标准答案】 const float EPSINON = 0.00001;

【注意】 不可将浮点变量用“”或“!=”与任何数字比较。
千万要留意,无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“
”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。
假设浮点变量的名字为x,应当将
if (x == 0.0) // 隐含错误的比较
转化为
if ((x>=-EPSINON) && (x<=EPSINON))
其中EPSINON是允许的误差(即精度)。

(3)请写出char *p 与“零值”比较的if 语句
【标准答案】 if (p == NULL) if (p != NULL)

2. 以下为Linux下的32 位C 程序,请计算sizeof 的值。
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
(1)sizeof (str ) = (2)sizeof ( p ) =
(3)sizeof ( n ) =
(4)void Func ( char str[100])
{
…… ;
}
请计算sizeof( str ) =
(5)void * p = malloc( 100 );
请计算sizeof ( p ) =
【标准答案】 (1)6 (2)4 (3)4 (4)4 (5)4
个人解析:(1)“ ”双引号会在字符串结尾加上‘\0’,所以Hello为5字节+‘\0’1字节=6字节
(2)sizeof(指针),返回的是指针的大小,而不是指针所指向的内存空间的大小,指针本身是一个无符号整型数,地址常为4字节
(3)数值类型int:4字节,char:1字节,double:8字节
(4)sizeof(数组)=定义的数组大小,但此时的str是形参
(5)指针返回为指针的大小,同(2)

4、用变量a 给出下面的定义
e) 一个有10个指针的数组,该指针是指向一个整型数的;
f) 一个指向有10个整型数数组的指针;
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数;
【标准答案】
e) int *p[10];
f) int (*p)[10];
g)int (*p)(int)
h)int((*p)[10])(int)
个人解析:自左向右开始读式子

5、设有以下说明和定义:
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
个人解析:union是公用空间,最大为int k[5]所以sizeof(DATA)的大小为20
所以sizeof(too)=20+12=32

6、请问以下代码有什么问题:
int main()
{
char a;
char *str=&a;
strcpy(str,“hello”);
printf(str);
return 0;
}
【标准答案】 指针str指向的是字符变量a的地址空间,而“hello”是字符串,无法将字符串复制到字符变量指针所指的空间中

7、请问以下代码有什么问题:
char *s=“AAA”;
printf(“%s”,s);
s[0]=‘B’;
printf(“%s”,s);
有什么错?
【标准答案】 因为指针s指向的是一个字符串常量,所以无法通过数组下标对字符串常量进行修改
个人修改代码:
char s[4]=“AAA”;
char *p=s;
printf(“%s\n”,s);//运行结果:AAA
p[0]=‘B’;
printf(“%s”,p);//运行结果:BAA

8、int (*s[10])(int) 表示的是什么啊
【标准答案】 表示一个指向函数的十个元素的数组指针,函数参数为int类型,返回值为int类型

9、c和c++ 中的struct有什么不同?
【标准答案】 c和c++ 中struct的主要区别是c中的struct不可以含有成员函数,而c++ 中的struct可以。

10、void getmemory(char *p)
{
p=(char *) malloc(100);
strcpy(p,“hello world”);
}
int main( )
{
char *str=NULL;
getmemory(str);
printf(“%s/n”,str);
free(str);
return 0;
} 会出现什么问题?
【标准答案】 程序崩溃,因为str传入的为副本,在调用函数时仍旧为NULL,申请空间的时在子函数中的p指针,所以p指针的动态空间没有收回,free了一个str。

11、char szstr[10];
strcpy(szstr,“0123456789”);
产生什么结果?为什么

【标准答案】 长度不一样,出现段错误。
个人解析:字符串有11字节,但数组只有10字节

12.数组和链表的区别?
【标准答案】 数组是顺序存储,固定大小,链表是随机存储大小可以动态改变。

13.void main()
{
char aa[10];
printf(“%d”,strlen(aa));
}
会出现什么问题?打印结果是是多少?

【标准答案】 sizeof()使用时不出话没有关系,但是strlen()需要初始化之后再使用,打印结果未知。

14.给定结构
struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
}; 问sizeof(A) = ?

【标准答案】 char(1)+short(2)+long(4)=7,字节对齐后,最终结果为8
补充知识:
一、16位编译器

char :1个字节

char*(即指针变量): 2个字节

short int : 2个字节

int: 2个字节

unsigned int : 2个字节

float: 4个字节

double: 8个字节

long: 4个字节

long long: 8个字节

unsigned long: 4个字

二、32位编译器

char :1个字节

char*(即指针变量): 4个字节

short int : 2个字节

int: 4个字节

unsigned int : 4个字节

float: 4个字节

double: 8个字节

long: 4个字节

long long: 8个字节

unsigned long: 4个字节

三、64位编译器

char :1个字节

char*(即指针变量): 8个字节

short int : 2个字节

int: 4个字节

unsigned int : 4个字节

float: 4个字节

double: 8个字节

long: 8个字节 (定义是long至少不小于int)

long long: 8个字节 (long long至少不小于long)

unsigned long: 8个字节

位域

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
struct 位域结构名
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度
struct bs
{
int a:8;
int b:2;
int c:6;
}data;
说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位

15.struct name1
{
char str;
short x;
int num;
} ;求sizeof(name1)?

【标准答案】 char(1+空)+short(2)+int(4)=8,字节对齐.
个人解析:关于struct结构体字节对齐问题,我找了一篇博客,其中重要理解部分截图如下:
在这里插入图片描述
16.struct name2
{
char str;
int num;
short x;
}; 求sizeof(name2)?

【标准答案】 char(1+空+空+空)+int(4)+short(2+空+空)=4+4+4 =12

**17.程序哪里有错误
wap( int *p1,int *p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
p2 = p;
}

【标准答案】 申请p的时候没有初始化,所以p为野指针。

19.(void * )ptr 和((void))ptr 的结果是否相同?其中ptr为同一个指针。**
【标准答案】 (void )ptr 和((void**))ptr 值是相同的

20.要对绝对地址0x100000赋值,我们可以用
(unsigned int
)0x100000 = 1234;
那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
*
【标准答案】 ((void( ∗ \ast )(void))0x100000)()
个人解析:
void ( ∗ \ast )(void)是一个指向函数的指针,且这个函数无返回值,无参数。
(void ( ∗ \ast )(void))类似(int*),做强制类型转换
0x100000强制转化为一个函数指针,即:(void(*)(void))0x100000
最后通过调用函数来跳转

27.关键字volatile有什么含意? 并给出三个不同的例子。
【标准答案】C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。
遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt;
下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量

28.嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
【标准答案】
int * ptr;
ptr= (int *)0x67a9;
*ptr = 0xaa66;

29.头文件中的ifndef/define/endif 干什么用?
【标准答案】 防止该头文件被重复引用

30.#include <filename.h> 和 #include “filename.h” 有什么区别?
【标准答案】
#include<filename.h>编译器从标准库路径搜索头文件,而#include"filename.h"编译器从用户的工作路径来搜索头文件。

31.const 有什么用途?(请至少说明两种)
【标准答案】
(1)const可以修饰常量
(2)congst可以修饰函数的参数、返回值、函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的引用变动,提高程序的健壮性。

32.static有什么用途?(请至少说明两种)
【标准答案】
(1)限制变量的作用域(static定义全局变量)
(2)限制变量的存储域(static定义局部变量)

33.堆栈溢出一般是由什么原因导致的?
【标准答案】
(1)函数调用的层次太深。函数进行递归调用时,系统要在栈中不断保存函数调用时的现场和产生的变量。调用层数太深会导致堆栈溢出。
(2)动态申请的空间使用后没有进行释放,C语言没有自动垃圾回收机制。

34.如何引用一个已经定义过的全局变量?
【标准答案】

  1. 用extern关键字方式
  2. 用引用头文件的形式

35.全局变量可不可以定义在可被多个.C 文件包含的头文件中?为什么?
【标准答案】

可以,在不同的C 文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。

36.队列和栈有什么区别?
【标准答案】 队列先进先出,栈后进先出

37.Heap与stack的差别。
【标准答案】
Heap是堆,Stack是栈。Stack的空间由操作系统自动分配/释放,但Heap的空间可以进行手动分配,C语言中malloc动态分配的内存空间就是分配在堆上,C++中对应的是new操作。

38.用宏定义写出swap(x,y),即交换两数。
【标准答案】

#define SWAP(x,y) (x)=(x)+(y);(y) = (x)-(y);(x) = (x)-(y);

39.写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
【标准答案】

#defien MIN(x,y) ((x)>(y) ? (x):(y));

40.带参宏与带参宏函数的区别(至少说出5点)?
【标准答案】

1.函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换
2.函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
3.对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
4.调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
5.使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长
6.宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)

42.int main()
{
int x=3;
printf(“%d”,x);
return 1;
}
问函数既然不会被其它函数调用,为什么要返回1?

【标准答案】 mian中,c标准认为0表示成功,非0表示错误

43.已知一个数组table ,用一个宏定义,求出数据的元素个数。
【标准答案】
#defien NTBL(table) (sizeof(table)/sizeof(table[0]))

44.A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?
这两个static变量会保存到哪里(栈还是堆或者其他的)?

【标准答案】
static的全局变量,表明这个变量仅在本模块中有意义,不会影响到其他模块。他们都放在静态数据区,编译器对他们的命名是不同的。

45.static全局变量与普通的全局变量有什么区别?
【标准答案】
这两者的区别在于(普通)非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而(static)静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。

46.static局部变量和普通局部变量有什么区别?
【标准答案】
普通局部变量只有执行到变量定义的语句的时候才会分配空间,static局部变量在编译阶段,变量空间就已经分配。普通局部变量离开作用域自动释放其空间,无法使用此变量,static局部变量只有在整个程序结束的时候才将其自动释放

47.static函数与普通函数有什么区别?
【标准答案】
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

48.程序的局部变量存在于()中,全局变量存在于 ()中,动态申请数据存在于()中。
【标准答案】
程序的局部变量存在于栈(stack) 中,全局变量存在于静态数据区中,动态申请数据存在于堆(heap)中

49.什么是预编译,何时需要预编译?
【标准答案】
(1)总是使用不经常改动的大型代码体
(2)程序由多个模块组成,所有模块都使用同一组标准的包含文件和相同的编译选项。可以将所有包含文件预编译为一个预编译头

50.用两个栈实现一个队列的功能?要求给出算法和思路!
【标准答案】
设两个栈为A、B,一开始均为空
入队:新元素入栈A
出队:判断B栈是否为空,若为空,则将栈A的内容全部出栈后入栈B,将B的栈顶元素出栈。

51.对于一个频繁使用的短小函数,在C 语言中应用什么实现,在C++ 中应用什么实现?
【标准答案】
C语言中使用宏定义,C++中使用inline

52.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
【标准答案】
#define SECONS(6024365)UL
UL为无符号长整型

53.Typedef 在C 语言中频繁用以声明一个已经存在的数据类型的同义字。
也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s

typedef struct s
tPS;
以上两种情况的意图都是要定义dPS 和tPS 作为一个指向结构s指针。
哪种方法更好呢?(如果有的话)为什么?**
【标准答案】
方法二,虽然typedef和define都可以起到起别名的作用,但define定义的宏,本身定义的不在编译过程中进行,而是在预处理过程中就已经完成了,所以更加不容易发现define定义下的错误。
个人解析:
本题定义 dPS a,b;
tPS a,b;
替换为原来的样子:方法1 struct s *a,b; a是一个结构体指针,但b是一个结构体
方法2 struct s *a,struct s *b; a和b均为结构体指针

54.在 C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
【标准答案】
extern C的主要作用是为了正确实现C++代码调用其他C语言代码。加上后这部分代码编译器就会按照C语言的标准来执行而不是C++的标准。且C++允许函数重载,在编译过程会带上函数的参数类型,但C语言不允许,所以编译的过程有所不同。

56.语句for( ; 1 😉 有什么问题?它是什么意思?
【标准答案】
死循环,和while(1)相同

57.do……while和while……do有什么区别?
【标准答案】
前一个循环一遍再判断,后一个判断以后再循环。

58.请写出下列代码的输出内容
#include <stdio.h>
int 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

**59.unsigned char *p1;
unsigned long *p2;
p1=(unsigned char )0x801000;
p2=(unsigned long )0x810000;
请问p1+5= ;
p2+5= ;

【标准答案】
p1+5 = 0x801005
p2+5 = 0x810014
个人解析:
p1指向字符型,一次移动一个字符型,1个字节;p1+5后移5个字节,16进制表示为5;
p2指向长整型,一次移动一个长整型,4个字节,p2+5后移20字节,16进制表示为14

60.main()
{
int a[5]={1,2,3,4,5};
int * ptr=(int
)(&a+1);
printf(“%d,%d”,(a+1),(ptr-1));
}
请问输出:
*
【标准答案】 2,5
a代表数组首地址,即* a=1,* (a+1)=2
个人解析:&a代表数组指针,其类型为int (*)[5],所以&a+1可以理解为在数组指针的基础上偏移为5,然后强制转换为int类型的指针赋给ptr,所以是下个数组的首地址,ptr-1即为上个数组的最后一位,所以是a[4]=5

61.请问下面程序有什么错误?
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;

【标准答案】 对于k的判断多了一个=,会导致溢出

62.以下是求一个数的平方的程序,请找出错误:
#define SQUARE(a)((a)*(a))
int a=5;
int b;
b=SQUARE(a++);

【标准答案】
替换后b=(a++)*(a++)=(5) ∗ \ast (6)

63.#define Max_CB 500
void LmiQueryCSmd(StructMSgCB * pmsg)
{
unsigned char ucCmdNum;

for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++)
{
…;
}
} 这段代码执行有什么问题?

【标准答案】
死循环,因为unsigned char 的取值范围在0~255之间,所以ucCmdNum永远小于Max_CB

64.嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
【标准答案】
while(1);或者for ( ;1;) ;

67.
int x;
int modifyvalue()
{
return(x+=10);
}
int changevalue(int x)
{
return(x+=1);
}
void main()
{
int x =10;
x++;
changevalue(x);
x++;
modifyvalue();
printf(“First output:%dn”,x);
x++;
changevalue(x);
printf(“Second output:%dn”,x);
modifyvalue();
printf(“Thirdoutput:%dn”,x);
}输出?

【标准答案】 12,13,13
个人解析:调用的函数都是形参没有对主函数中的x做出改变

68.不能做switch()的参数类型是:
【标准答案】 switch 的参数不能为实型(浮点型)

71.一语句实现x是否为2 的若干次幂的判断。
【标准答案】
void main()
{
int a;
scanf(“%d”,&a);
printf(“%c”,(a)&(a-1)?’n’:’y’); // 若是打印y,否则n
}
个人解析:(a)&(a-1)进行按位与运算,结果为1则输出‘n’,即不是2的若干次幂,结果为0则输出‘y’,是2的若干次幂

72.中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C 支持中断。具代表事实是,产生了一个新的关键字__interrupt 。下面的代码就使用了__interrupt 关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}

【标准答案】
(1)中断不能有入参和返回值
(2)有许多处理器/编译器中,浮点数一般都是不可重入的。需要让额外的寄存器入栈,有些不允许在ISR中做浮点数运算
(3)printf()经常有重入和性能上的问题。

73.下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b> 6)? puts(“> 6”) : puts(“<= 6”);
}

【标准答案】 >6
个人解析:当有符号和无符号运算时,统一转换为无符号,而在有符号的情况下是将最高位置1来表示负数,所以负数转为无符号时将会是一个很大的数

74.评价下面的代码片断:
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;

【标准答案】 unsigned int compzero = 0xFFFF; 只写了2个字节,16位的才符合 。
32位的可以写:
unsigned int compzero = 0xFFFFFFFF; 但unsigned int compzero = ~0;更安全,不管有多少位,直接取反,把所有的0都变成1了

**75.下面的代码片段的输出是什么,为什么?
char ptr;
if ((ptr = (char )malloc(0)) == NULL)
puts(“Gota null pointer”);
else
puts(“Gota valid pointer”);

【标准答案】 Gota valid pointer
因为malloc申请的空间为0,所以成功申请,此时的ptr!=NULL,所以运行else语句下的句子

**76.编写strcpy 函数
已知strcpy 函数的原型是 char *strcpy(char strDest, const char strSrc);其中strDest是目的字符串,strSrc 是源字符串。
【标准答案】

char * strcpy( char *strDest, const char *strSrc )
{
 	assert( (strDest != NULL) && (strSrc != NULL) );//判断两个指针非空
 	char *address = strDest;
 	//执行复制功能
 	while( (*strDest++ = * strSrc++) != ‘\0);
  return address;//引用返回地址,方便链式操作!!
}

77.写出二分查找的代码
【标准答案】

int binary_search(int *arr,int key,int n){
	int low = 0;
	int high = n-1;
	int mid;
	while(low<=high){
		mid = (low + high)/2;
		if(key < arr[mid]){
			low = mid + 1;
		}
		else if(key < arr[mid]){
			high = mid - 1;
		}
		else
			return mid;
	}
	return -1;
}

78.请编写一个C函数,该函数给出一个字节中被置1 的位的个数
【标准答案】

int sum(unsigned char byte){
	int n = 0;
	for(int i = 0;i < 8;i++){
		if(byte&1<<i)//和1相与操作后再左移相当于/2
		n++;
	}
	return n;
}

79.请编写一个C 函数,该函数将给定的一个字符串转换成整数。
【标准答案】

int str_to_num(char *str){
	int num =  0;
	assert(str != NULL);//str不为空
	while((*str)!='\0')
	{
		num = num*10;
		num = num + ((*str)- 48);
		str++
	}
	return num;
}

80.请编写一个C 函数,该函数将给定的一个整数转换成字符串。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值