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)
- 不良风格:
if (flag == TRUE)
if (flag == 1)
if (flag == FALSE)
if (flag == 0)
(2)请写出 float x 与 “零值” 比较的 if 语句。
- 标准答案:
const float EPSINON = 0.0001;
if (x >= -EPSINON)
注意:不可将浮点变量用“==”或“!=” 与数字比较,应该设法转化成 “>=” 或 “<=” 此类形式。
- 错误写法
if (x == 0.0)
if (x != 0.0)
*(3)请写出 char p 与“零值”比较的 if 语句。
- 标准答案
if (p == NULL)
if (p != NULL)
- 错误写法
if (p == 0)
if (p != 0)
if (p)
2. 以下为Linux下的32位C程序,请计算sizeof的值。
(1) char str[] = “hello”; (2) char *p = str; (3) int n = 10;
(4) void Func(char str[100]); (5) void *p = malloc(100);
请计算:
(1) sizeof (str) = 6; (2) sizeof(p) = 4; (3) sizeof(n) = 4;
(4) sizeof (str) = 4; (5) sizeof(p) = 4;
3. long a=0x801010,a+5 = ?
十六进制 | 8 | 0 | 1 | 0 | 1 | 0 |
---|---|---|---|---|---|---|
二进制 | 1000 | 0000 | 0001 | 0000 | 0001 | 0000 |
十进制 | 8388608 | 0 | 4096 | 0 | 16 | 0 |
所以 a 的十进制为:8392720。
a + 5 = 8392725;
4. 用变量 a 给出下面定义:
- 一个有10个指针的数组,该指针是指向一个整型数的;
int *a[10];
- 一个指向有10个 整型数数组的指针;
int (*a)[10];
- 一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
int (*a)(int);
- 一个有10个指针的数组,该指针指向一个函数,该 函数有一个整型参数并返回一个整型数;
int (*a[10])(int);
5. 设有以下定义说明:
typedef union {
long i; // 8
int k[5]; // 20
char c; // 1
} DATE;
struct data {
int cat; // 4
DATE cow; // 20
double dog; // 8
} too;
DATE max; // 20
则语句 printf("%d",sizeof(struct date)+sizeof(max));
的执行结果是:_52_
6. 请问下面的代码有什么问题?
int main(int argc, char *argv[])
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}
没有为 str 分配内存空间,可能会发生异常。
7. 请问下面的代码有什么问题?
int main(int argc, char *argv[])
{
char *s = "AAA";
printf("%s", s);
s[0] = 'B';
printf("%s", s);
}
"AAA" 是字符串常量。s 是指针,指向这个字符串常量,所以应该这样声明 s : cosnt char* s="AAA";然后又因为是常 量,所以对是s[0]的赋值操作是不合法的。
8. int (*s[10])(int) 表示的是什么?
int (*s[10])(int)
是函数指针数组,每个指针指向一个 int func(int param)
的函数。
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(int argc, char *argv[])
{
char *str=NULL;
getmemory(str);
printf(“%s/n”,str);
free(str);
return 0;
}
会导致程序崩溃,因为 getmemory 函数中的 malloc 不能返回动态内存, free(str) 的操作很危险。
11. 下面的代码会出现什么问题?
char szstr[10];
strcpy(szstr,"0123456789");
出现段错误,因为字符串的最后面还有 ‘\0’ 结束符,上面的数组长度只有10,而字符串长度是11,所以数组越界。
12. 数组和链表的区别?
- 数组:数据顺序存储,固定大小
- 链表:数据可以随机存储,大 小可动态改变
13. 下面的代码会出现什么问题,打印结果是什么?
void main(int argc, char *argv[])
{
char aa[10];
printf("%d", strlen(aa));
printf("%d", sizeof(aa));
}
strlen(aa) 打印结果未知,因为数组 aa[10] 是局部变量,没有对它进行初始化,系统会默认赋一些垃圾值给它,所以直接使用 strlen 去计算它的长度是未知的。
sizeof(aa) 的打印结果为10,sizeof 的使用和初始化没有关系,它会直接计算出这个数组的长度。
14. 下面结构体的大小?
sruct A {
char t:4; // 4位
char k:4; // 4位
unsigned short i:8; // 8位 这里要偏移2字节保证4字节对齐
unsigned long m; // 4位
};
所以 sizeof(A) = 8;
15. 下面结构体的大小?
struct name1 {
char str; // 1
short x; // 2
int num; // 4
};
所以 sizeof(name1) = 8;
16. 下面结构体的大小?
struct name2 {
char str; // 1
int num; // 4
short x; // 2
};
所以 sizeof(name2) = 12;
17. 下面的程序有什么错误?
wap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
指针 p 没有赋初值,变成了野指针。
18. c++ 的 struct 和 class 有什么不同?
c++ 中 struct 和 class 的主要区别在于默认的存取权限不同,struct 默认为 public,而 class 默认为 private。
19. (void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针。
(void *)ptr 和 (*(void **))ptr值是相同的。
20. 怎么对地址 0x100000 赋值?
(unsigned int *)0x100000 = 1234;
那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
首先要将 0x100000 强制转换成函数指针,即:
(void (*)())0x100000
然后再调用它:
*((void (*)())0x100000)();
21. int a,b,c; 请写函数实现 c=a+b ,不可以改变数据类型,如将 c 改为long int,如何处理溢出问题
bool add (int a, int b,int *c)
{
*c = a+b;
return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0&&(*c>a || *c>b)));
}
22. 内存思考题,下面代码你能看出有什么问题?
- 示例1:运行 test 函数会出现什么问题?
void getmemory(char *p)
{
p = (char *)malloc(100);
}
void test(void)
{
char *str = NULL;
getmemory(str);
strcpy(str, "hello world");
printf("%s", str);
}
程序崩溃,因为 getmemory 并不能传递动态内存,test 函数中的 str 一直都是 NULL 。所以strcpy(str,”hello world”) 将使程序崩溃。
- 示例2:运行 test 函数会出现什么问题?
void *getmemory(void)
{
char p[] = "hello world";
return p;
}
void test(void)
{
char *str = NULL;
str = getmemory();
printf("%s", str);
}
可能输出是乱码。因为 getmemory 返回的是指向栈内存的指针,该指针的地址不是NULL,但其原先的内容已经被清除,新内容不可知。
- 示例3:运行 test 函数会出现什么问题?
void getmemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void test(void)
{
char *str = NULL;
getmemory(&str, 100);
strcpy(str, "hello");
printf("%s", str);
}
能够输出 hello,但是内存泄漏。
- 示例4:运行 test 函数会出现什么问题?
void test(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL) {
strcpy(str, "world");
printf("%s", str);
}
}
篡改动态内存区的内容,后果难以预料非常危险。因为free(str)之后 str成为野指针,if(str != NULL)语句不起作用。
27. 关键字volatile有什么含意? 并给出三个不同的例子。
一个定义为 volatile 的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面是volatile变量的几个例子:
- 并行设备的硬件寄存器(如:状态寄存器) 。
- 一个中断服务子程序中会访问到的非自动变量 (Non-automatic variables) 。
- 多线程应用中被几个任务共享的变量 。
28. 编写下面要求的代码。
嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为 0x67a9 的整型变量的值为 0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
29. 头文件中的 ifndef/define/endif 是做什么的?
防止该头文件被重复引用。
30. #include <filename.h> 和 #include “filename.h” 有什么区别?
- 对于 #include <filename.h> 来说编译器会从标准库路径开始搜索 filename.h 。
- 对于 #include “filename.h” 来说编译器从用户的工作路径开始搜索 filename.h 。
31. const 有什么用途?
- 可以定义 const 常量
- const 可以修饰函数的参数、返回值,甚至函数的定义体。
- 被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
32. static有什么用途?
- 限制变量的作用域(static全局变量)。
- 设置变量的存储域(static局部变量)。
- 修饰函数只对本文件可见。
33. 堆栈溢出一般是由什么原因导致的?
- 没有回收垃圾资源。
34. 如何引用一个已经定义过的全局变量?
可以用引用头文件的方式,也可以用 extern 关键字,如果用引用头文件方式来引用某 个在头文件中声明的全局变理,假定那个变量写错了,那么在编译期间会报错,如果用 extern 方式引用时,假定犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
35. 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
可以,在不同的 C 文件中以 static 形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个 C 文件中对此变量赋初值,此时连接不会出错。
36. 队列和栈有什么区别?
队列先进先出,栈先进后出。
37. heap 与 stack 的差别。
- heap是堆,stack是栈。
- stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
- stack空间有限,heap是很大的自由存储区。
- C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。
- 程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行。
38. 用宏定义写出swap(x,y),即交换两数。
#define swap(x, y) (x)=(x)+(y);(y)=(x)–(y);(x)=(x)–(y);
39. 写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
#define Min(X, Y) ((X)>(Y)?(Y):(X)) //结尾没有;
40. 带参宏与带参函数的区别?
- 带参宏的执行效率要高于带参函数。因为带参宏的代码是在预处理阶段直接替换进程序代码中的,所以不需要在运行时调用函数和返回,所以带参宏的执行效率要高于带参函数。
- 带参宏不检查数据类型。带参宏在预处理阶段进行替换,而不是在运行时进行调用,所以带参宏不会检查参数的数据类型。
- 使用带参宏时传递了错误的参数类型,在编译时可能不会报错,但是在运行时会出现意想不到的错误。
- 带参函数会在编译时检查参数的数据类型,因此在编译时就能发现错误。
41. 关键字volatile有什么含意?
提示编译器对象的值可能在编译器未监测到的情况下改变。
42. 下面这个函数既然不会被其它函数调用,为什么要返回1?
int main(int argc, char *argv[])
{
int x=3;
printf("%d",x);
return 1;
}
mian 中,c 标准认为 0 表示成功,非 0 表示错误。具体的值是某中具体出错信息。
43. 已知一个数组table,用一个宏定义,求出数据的元素个数。
#define NTBL(table) (sizeof(table)/sizeof(table[0]))
44. A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
- static 修饰的全局变量,表明这个变量仅在本模块中有 意义,不会影响其他模块。
- 他们都放在静态数据区,但是编译器对他们的命名是不同的。
- 如果要使变量在其他模块也有意义的话,需要使用extern关键字。
45. static全局变量与普通的全局变量有什么区别?
- static全局变量只初使化一次,防止在其他文件单元中被引用。
46. static局部变量和普通局部变量有什么区别?
- static局部变量只被初始化一次,下一次依据上一次结果值;
47. static函数与普通函数有什么区别?
- static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。 static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件。
48. 程序的局部变量存在于____中,全局变量存在于____中,动态申请数据存在于___中。
- 程序的局部变量存在于栈(stack)中,全局变量存在于静态数据区 中,动态申请数据存在于堆(heap)中。
49. 什么是预编译,何时需要预编译?
- 总是使用在不经常改动的大型代码体。
- 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
50. 用两个栈实现一个队列的功能?要求给出算法和思路!
设2个栈为A,B, 一开始均为空。
入队:将新元素 push 入栈A;
出队:
-
判断栈B是否为空;
-
如果不为空,则将栈A中所有元素依次pop出并push到栈B;
-
将栈B的栈顶元素pop出;
51. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
- C 用宏定义,C++ 用inline
52. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
53. typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。
- 例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
**以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么? **
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。
- 思考下面的例子:
dPS p1, p2; // struct s * p1, p2;
tPS p3, p4;
上面的代码定义p1为一个指向结构的指针,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
54. 在 C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”?
C++ 语言支持函数重载,C 语言不支持函数重载。函数被 C++编译后在库中的名字与 C 语言的不同。
假设某个函数的原型为:void foo(int x, int y); 该函数被 C 编译器编译后在库中的名字为_foo,而 C++编译器则会产生像_foo_int_int 之类的名字。
C++ 提供了 C 连接交换指定符号 extern“C”来解决名字匹配问题。
55. 请简述以下两个 for 循环的优缺点。
- 示例1:
for (i=0; i<n; i++) {
if (condition)
DoSomething();
else
DoOthering();
}
优点:程序简洁。
缺点:多执行了 N-1 次逻辑判断,并且打断了循环的 “流水线” 作业,使得编译器不能对循环进行优化处理,降低了效率。
- 示例2:
if (condition) {
for (i=0; i<n; i++)
DoSomething();
}
else {
for (i=0; i<n; i++)
DoOthering();
}
优点:循环效率高。
缺点:程序不简洁。
56. 语句for( ;1 ;)有什么问题?它是什么意思?
- 死循环,和while(1)相同。
57. do……while和while……do有什么区别?
- 前一个循环一遍再判断,后一个判断以后再循环。
58. 请写出下列代码的输出内容
#include <stdio.h>
int main(int argc, char *argv[])
{
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;
}
b,c,d:10,12,120
59. 下面代码 p1+5 跟 p2+5 等于多少?
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
- 0x801005、0x810020
60、请写出下列代码的输出内容
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf(“%d,%d”,*(a+1),*(ptr-1));
}
2,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;
需要将循环语句内外换一下才能对数组进行赋值。
62. 以下是求一个数的平方的程序,请找出错误:
#define SQUARE(a)((a)*(a))
int a=5;
int b;
b=SQUARE(a++);
宏在预编译时会以替换的形式展开,仅仅会替换。涉及到宏的地方,不要用++ --,标准中对此没有规定,因此最终结果将会依赖于不同的编译器。
执行程序的答案可能是25、也有可能是36。
63. 下面这段代码执行有什么问题?
#define Max_CB 500
void LmiQueryCSmd(Struct MSgCB * pmsg)
{
unsigned char ucCmdNum;
......
for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++)
{
......;
}
}
程序会进入死循环 ,unsigned char 是无符号字符型它的范围是 0~255。
64. 嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
while(1);
for(;;);
do ... while(1);
65. 下面程序输出结果是?
int sum(int a)
{
auto int c = 0;
static int b = 3;
c += 1;
b += 2;
return(a+b+c);
}
void main(void)
{
int i;
int a = 2;
for (i = 0;i < 5;i ++) {
Printf(“%d”,sum(a));
}
}
8,10,12,14,16