1、判断以下程序输出结果
main()
{
char *p1=“name”;
char *p2;
p2=(char*)malloc(20);
memset (p2, 0, 20);
while(*p2++ = *p1++);
printf(“%s\n”,p2);
}
Answer:empty string.
2、Change 宏定义 do{}while(0)
#include <stdio.h>
#define swap(a,b) do{a=a+b;b=a-b;a=a-b;}while(0)
int swap2(int *a,int *b);
int main()
{ int x =5, y = 10;
swap(x,y);
printf("%d,%d\n",x, y);
swap2(&x,&y);
printf("%d,%d\n", x,y);
}
int swap2(int *a,int *b)
{ int temp;
temp = *a;
*a = *b;
*b = temp;
return 0;
}
Answer:10,5 5,10
3 宏定义 条件运算符 ?:
Answer:
#define min(a, b) (((a)<=(b)) ? (a) : (b))
4. 用变量a给出下面的定义
a) 一个整型数 int a;
b) 一个指向整型数的指针 int *a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数 int **a;
d) 一个有10个整型数的数组 int a[10];
e) 一个有10个指针的数组,该指针是指向一个整型数的 int *a[10];
f) 一个指向有10个整型数数组的指针 int (*a)[10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 int (*a)(int);
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 int(*a[10])(int)
5. 关键字static的作用是什么?
在C语言中,关键字static有三个明显的作用:
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
6.关键字const:
const 意味着声明的变量为只读变量,其值不可改变。
const int a; a是一个常整型数
int const a; a是一个常整型数
const int *a; a是一个指向常整型数的指针
int * const a; a是一个指向整型数的常指针
int const * a const; a是一个指向常整型数的常指针
前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(整型数是不可修改的,但指针可以)
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数 是不可修改的,同时指针也是不可修改的)。
7.关键字volalile:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,被定义为volatile的变量,优化器每次用到这个变量时都会重新读取这个值,而不会用保存在寄存器中的值,防止变量被优化。例子:
1)并行设备的硬件寄存器
2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3)多线程应用中被几个任务共享的变量
8.访问一绝对地址把一个整型数强制转换为一指针是合法的:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
9.堆和栈的区别:
栈是由系统自动分配的一块连续的内存空间,申请速率快,但是不受程序员控制,申请后只要栈的剩余空间大于申请空间,系统就为内存提供空间,否则将报异常提示栈溢出。堆是由程序员申请的不连续的内存空间,申请速率慢,但受程序员控制,申请后系统从记录空闲空间的链表中查找第一块大于申请空间的堆节点,然后把该节点从空闲链表中删除,并将该节点空间分配给程序,空间的首地址记录本次分配的大小,并把剩余空间重新放入空闲链表中。
1.申请方式
栈(stack): 由系统自动分配。
堆(heap): 需要程序员自己申请,并指明大小,在c中用malloc函数。
2.申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:申请后系统从记录空闲空间的链表中查找第一块大于申请空间的堆节点,然后把该节点从空闲链表中删除,并将该节点空间分配给程序,空间的首地址记录本次分配的大小,并把剩余空间重新放入空闲链表中。
3.申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。
4.申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自 由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
10.malloc和calloc的区别:
1、传递参数不同,malloc函数有1个参数,及申请空间大小;calloc有2个参数,分别为元素的个数和每个元素的大小,这两个参数的乘积就是申请空间的大小。
2、malloc不能初始化申请空间,而calloc可以。
11.论述含参数的宏与函数的优缺点。
函数是内置的,执行效率高,速度快;宏可以自己定制,比较灵活,但执行速度相对较慢。
12.比较 union 和 struct 的不同;
union中的各个域的空间是重叠的,struct中的各个域的空间是不重叠的。
13.字符数组与字符指针的区别:
字符指针存放在文字常量区,指向地址可变;字符串数组所代表的数组首地址不可变。
14.进程线程的区别:
1.进程是系统分配资源的最小单位,线程是系统执行的最小单元。
2.线程是进程的一个实体,一个进程里可有多个线程,进程独自占有系统资源,进程中的多个线程共享这个进程的所有资源。
3.线程可以并发执行,进程不可以并发执行。
15.链表逆序:
Typedef struct node{
……
Struct node *next;
}NODE;
NODE *reverse(NODE *head)
{
NODE *p1 = NULL, p2 = NULL, p3 = NULL;
p1 = head;
p2 = head->next;
While(p2 != NULL)
{
p3 = p2->next;
P2->next = p1;
P1 = p2;
P2 = p3;
}
head->next = NULL;
head = p1;
return head;
}
void del_all(NODE *head)
{
NODE *pb;
while(head != NULL)
{
pb = head->neat;
free(head);
head = pb;
}
}
16.编译的几个步骤
编译的完整过程:C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf等)
1. 编译预处理
读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
2. 编译阶段
编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
3. 汇编过程
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程.
4. 链接程序
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。