C 语言笔试题题目
一、 简答题
1. 程序的局部变量存在于(栈区)中,全局变量存在于(数据区)中,动态申请数据存在
于(堆区)中。
2. 设有以下说明和定义:
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____
data 是一个 union, 变量公用空间. 里面最大的变量类型是 int[5], 占用 20 个字节. 所以它
的大小是 20。
data 是一个 struct, 每个变量分开占用空间. 依次为 int4 + DATE20 + double8 = 32.所以结
果是 20 + 32 = 52
3. 32 位系统下,请问如下语句的值
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问 p1+5= 0x801005
p2+5= 0x810020 0x810014
int i=10, j=10, k=3; k*=i+j; k 最后的值是? ---60
4.
此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低
5. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少? ---30
#define -----> 替换
6. 下面程序的输出是_____,为什么?
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
{
puts("Got a null pointer");
}
else
{
puts("Got a valid pointer");
}
Got a valid pointer
7. 以下程序运行后的输出结果是___b___ 。
main()
{
char m;
m='B'+32; printf("%c\n",m);
}
8. 已有定义如下:
struct node
{
int data;
struct node *next;
} *p;
以下语句调用 malloc 函数,使指针 p 指向一个具有 struct node 类型的动态存储空间。
请填空 p = (struct node *)malloc(_________);
sizeof(struct node)
9. 在绝对地址 0xXXXXXXXX 上写入字符’a’的语句是___________。
unsigned char *p = (unsigned char *)0xF00000FF;
p = ‘a’;
10. 用预处理指令#define 声明一个常数,用以表明 1 年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
1)#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年
中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3) 意识到这个表达式将使一个 16 位机的整型数溢出-因此要用到长整型符号 L,
告诉编译器这个常数是的长整型数。
4)如果你在你的表达式中用到 UL(表示无符号长整型),那么你有了一个好的起
点。记住,第一印象很重要
11. 写一个"标准"宏 MIN ,这个宏输入两个参数并返回较小的一个。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
1)标识#define 在宏中应用的基本知识。这是很重要的。因为在嵌入(inline)操作符
变为标准 C 的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来
说,为了能达到要求的性能,嵌入代码经常是必须的方法。
2)三重条件操作符的知识。这个操作符存在 C 语言中的原因是它使得编译器能产
生比 if-then-else 更优化的代码,了解这个用法是很重要的。
3)懂得在宏中小心地把参数用括号括起来,因为#define 仅仅做替换,如果我们写
#define MUL(a,b) a/b 的话,那么我写 MUL(a+1,b-1)替换之后的表达式就为
a+1/b-1,这个结果显然是违背我们定义的目的的。
4)我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么
事?
least = MIN(*p++, b);
12. 嵌入式系统中经常要用到无限循环,你怎么样用 C 编写死循环呢?
首选方案是
while(1){}
一些程序员更喜欢如下方案:
for(;;){}
这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试
者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他
们的基本答案是:"我被教着这样做,但从没有想到过为什么。"这会给我留下一个坏印
象。
第三个方案是用 goto
Loop:
...
goto Loop;
应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)
或者他是一个想进入新领域的 BASIC/FORTRAN 程序员。
13. 用变量 a 给出下面的定义
a) 一个整型数(An integer)
int a;
b) 一个指向整型数的指针( A pointer to an integer)
int *a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to
an intege)
int **a;
d) 一个有 10 个整型数的数组( An array of 10 integers)
int a[10]
e) 一个有 10 个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to
integers);
int *a[10]
f) 一个指向有 10 个整型数数组的指针( A pointer to an array of 10 integers)
int (*a)[10]
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a
function that takes an integer as an argument and returns an integer)
int *a(int)
h) 一个有 10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一
个整型数( An array of ten pointers to functions that take an integer argument and
return an integer )
int (*a[10])(int)
14. 关键字 static 的作用是什么?
1) 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访
问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就
是,这个函数被限制在声明它的模块的本地范围内使用。
1、static 修饰局部变量: 改变局部变量的存储位置(栈区-->数据区),从而改变局
部变量的生命周期;(且,被 static 修饰的局部变量只能被初始化一次)。
2、static 修饰全局变量:限制全局变量在本文件中使用,其他文件不能访问(相当
于隐藏,且只能初始化一次
3、static 修饰函数: static 函数在内存中只有一份,限制函数在本文件中使用,而其
他文件不能访问;(相当于隐藏)
static int a[10]; (static 修饰的数组不初始化时,系统默认初始化为 0)
static 全局变量与普通的全局变量有什么区别:static 全局变量只初使化一次,防止在其
他文件单元中被引用;
static 局部变量和普通局部变量有什么区别:static 局部变量只被初始化一次,下一次依
据上一次结果值;
static 函数与普通函数有什么区别:static 函数在内存中只有一份,普通函数在每个
被调用中维持一份拷贝。
15. 关键字 const 的含义及作用。
const 声明一个只读变量,可用于修饰指针,变量,形参等等 修饰数据类型
const int a; <==> int const a;
修饰变量 常整形数 (不能通过变量名修改 a 的值,但可以通过指针来修改)
const int *a (int const *a); 一个指向常整型数的指针,指向的整型数是不可修改的,但指
针可以
int * const a; 一个指向整型数的常指针,指针指向的整型数是可以修改的,但指针是不
可修改的
int const * a const; 一个指向常整型数的常指针(也就是说,指针指向的整型数是不
可修改的,同时指针也是不可修改的)
本质:const 在谁后面谁就不可修改,const 在最前面则将其后移一位即可,二者等效
const 关键字作用:
(1)欲阻止一个变量被改变,可以使用 const 关键字。在定义该 const 变量时,通
常需要对它进行初始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 const,
或二者同时指定为 const;
(3)在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数内
部不能改变其值;
(4)对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不能修改
类的成员变量;
1) 关键字 const 的作用是为给读你代码的人传达非常有用的信息,实际上,声明一
个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人
留下的垃圾,你就会很快学会感谢这点多余的信息。
2) 通过给优化器一些附加的信息,使用关键字 const 也许能产生更紧凑的代码。
3) 合理地使用关键字 const 可以使编译器很自然地保护那些不希望被改变的参数,
防止其被无意的代码修改。简而言之,这样可以减少 bug 的出现。
16. 关键字 volatile 有什么含意?并给出三个不同的例子
保证 CPU 每一次都去内存中读取数据,防止编译器优化;
一个定义为 volatile 的变量是说这变量可能会被意想不到地改变,这样,编译器就
不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心
地重新从内存中读取这个变量的值,而不是使用保存在寄存器里的备份。下面是 volatile
变量的几个例子:
(内存写入寄存器一般开始写一次,但是 valatile 修饰之后,每次都会重新读取)
1) 并行设备的硬件寄存器(如:状态寄存器)
2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3)多线程应用中被几个任务共享的变量
17. 一个参数既可以是 const 还可以是 volatile 吗?解释为什么。
是的。一个例子是 只读的状态寄存器。它是 volatile 因为它可能被意想不到地改变。它
是 const 因为程序不应该试图去修改它
18. 一个指针可以是 volatile 吗?解释为什么。
是的。尽管这并不很常见。
一个例子是 当一个中断服务子程序修改一个指向 buffer 的指针时。
19. 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
int a,b;
return a * b;
}
这段代码的目的是用来返指针*ptr 指向值的平方,但是,由于*ptr 指向一个 volatile
型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
a = *ptr;
b = *ptr;
}
由于*ptr 的值可能被意想不到地该变,因此 a 和 b 可能是不同的。结果,这段代码可
能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
a = *ptr;
}
int a;
return a * a;
20. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量 a,写两段代码,
第一个设置 a 的 bit 3,第二个清除 a 的 bit 3。在以上两个操作中,要保持其它位不变。
最佳的解决方案如下:
#define BIT3 (0x1 << 3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
21. 在某工程中,要求设置一绝对地址为 0x67a9 的整型变量的值为 0xaa66。编译器是一个
纯粹的 ANSI 编译器。写代码去完成这一任务。
建议你在面试时使用第一种方案。
Int *ptr;
Ptr = (int *)0x67a9;
*ptr = 0xaa66;
*(int * const)(0x67a9) = 0xaa66;
22. 局部变量能否和全局变量重名?
能,局部会屏蔽全局。要用全局变量,需要使用"::"。
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而
不会用到全局变量。如果需要用全局变量,则需要使用指针才能访问
对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环
体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
23. 如何引用一个已经定义过的全局变量?
extern
可以用引用头文件的方式,也可以用 extern 关键字,如果用引用头文件方式来引用某
个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如
果你用 extern 方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在
连接期间报错
24. 全局变量可不可以定义在可被多个.C 文件包含的头文件中?为什么?
可以,在不同的 C 文件中以 static 形式来声明同名全局变量。可以在不同的 C 文件中声
明同名的全局变量,前提是其中只能有一个 C 文件中对此变量赋初值,此时连接不会出
错
25. 语句 for( ;1 ;)有什么问题?它是什么意思?
等同于 while(1) 死循环
26. do……while 和 while……do 有什么区别?
do….while 先循环 再判断
while…….do 先判断 再循环
27. 下列哪种方法更好,为什么?
define dPS struct s *
typedef struct s * tPS;
typedef 更好。因为 typedef 是给类型取别名, 而 define 仅仅是替换。。思考下面的
例子:
dPS p1,p2;
tPS p3,p4;
第一个扩展为 struct s * p1, p2;
上面的代码定义 p1 为一个指向结构的指针,p2 为一个实际的结构体,这也许不是你
想要的。第二个例子正确地定义了 p3 和 p4 两个指针。
28. 下面的结构是合法的吗,如果是它做些什么?
int a = 5, b = 7, c;
c = a+++b;
根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处
理成: c = a++ + b; 因此, 这段代码持行后 a = 6, b = 7, c = 12。
29. 队列和栈有什么区别?
栈(即堆栈):先进后出
队列: 先进先出
30. 全局变量和局部变量是否有区别?如果有,是什么区别?
有区别:
全局变量储存在静态数据库(数据区),局部变量在堆栈(栈区)。
全局变量的作用域在定义之下的任何位置 而局部变量的作用域在函数模块内
全局变量的生命周期从编译开始到程序结束 而局部变量的声明周期从定义开始到函数
结束
31. 堆栈溢出一般是由什么原因导致的?
没有回收垃圾资源
32. 冒泡排序算法的时间复杂度是什么?
时间复杂度是 O(n^2)
33. 分别写出 BOOL,int,float,指针类型的变量 a 与“零”的比较语句。
BOOL : if ( !a ) or if(a)
int : if ( a == 0)
float : if(a > -0.000001 && a < 0.000001)
const EXPRESSION EXP = 0.000001
if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)
34. 不能做 switch()的参数类型是:
switch()参数不能为实型
35. 某 32 位系统下,请计算 sizeof 的值.
char str[] = “http://www.ibegroup.com/”