几个C语言题与答案
1.C语言中,修饰符volatile的含义是什么?举例说明其使用场合。
答.volatile提醒编译起它后面所定义的变量随时都有可能发生改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直
接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变化由别
的程序更新了的话,将会出现不一致现象。
一般来说,volatile用在如下几个地方:
(1)中断服务程序中修改的供其他程序检测的变量需要加volatile;
(2)多任务环境下各任务间共享的标志因该加volatile;
(3)存储器映射的硬件寄存器通常也要加volatile,因为每次对它的读写都可能有不同意义。
2.请问TCP/IP协议分为哪几层?FTP协议属于哪一层?
答.
(1)应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP,file transfer protocol)、网络远程访问协
议(Telnet)等。
(2)传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP,user datagram protocol
)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
(3)互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议
(IP)。
(4)网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
补充:ISO的七层模型:应用层,表示层,会话层,传输层,网络层,物理链路层,物理层
TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,
比 TCP 负载消耗少。
tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
udp: 不提供稳定的服务,包头小,开销小
3.什么是预编译 何时需要预编译?
答.
预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,
条件编译等。就是为编译做预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译起进行的操作
,可以放在程序中的任何位置。预处理功能主要有三种:1)宏定义 2)文件包含 3)条件编译
4.c和c++中的struct有什么不同?
c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的
存取权限不同,struct默认为public,而class默认为private。
5.main函数的返回值:mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息
6.要对绝对地址0x100000赋值,我们可以用(unsigned int*)0x100000 = 1234;那么要是想让程序跳转到绝对地址是0x100000去执行,应
该怎么做?
*((void (*)( ))0x100000 ) ( );
首先要将0x100000强制转换成函数指针,即:
(void (*)())0x100000
然后再调用它:
*((void (*)())0x100000)();
用typedef可以看得更直观些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
7.线程与进程的区别和联系? 线程是否具有相同的堆栈?
进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。
每个线程有自己的堆栈。
8.分析下面的程序:
void GetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
int main()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
free(str);
if(str!=NULL)
{
strcpy(str,"world");
}
printf("\n str is %s",str); 软件开发网 www.mscto.com
getchar();
}
问输出结果是什么?
输出str is world。
free 只是释放的str指向的内存空间,它本身的值还是存在的.所以free之后,有一个好的习惯就是将str=NULL.
此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,
尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。
这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。
当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息
(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此
你是可以继续访问这块地址的。
9.用预处理指令#define 声明一个常数,用以表明1 年中有多少秒
意识到这个表达式将使一个16 位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
10.嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9 的整型变量的值为
0xaa66。编译器是一个纯粹的ANSI 编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式
随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
11.若寄存器的地址为ox53000000,如何定义一个宏访问它的值?
#define rWTCON (*(volatile unsigned *)0x53000000)
12.下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
这个问题测试你是否懂得C 语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是
输出是 ">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20 变成了一个非常大的
正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。
13.define和typedef
(1)关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。
Define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
(2)Typedef用来定义类型的别名
(3)#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。而typedef有自己的作用域。
14.浮点型变量并不精确,所以不可将float 变量用“==”或“!=”与数字比较,应该设法转化成“>=”
或“<=”形式。如果写成if (x == 0.0),则判为错。if ((x >= - EPSINON) && (x <= EPSINON)
15.assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>
void assert( int expression );
16.程序:
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
char p[] = "hello world";
return p;
的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,
其根源在于不理解变量的生存期
17.求二进制数中1的个数
快速法:
int BitCount2(unsigned int n)
{
unsigned int c =0 ;
for (c =0; n; ++c)
{
n &= (n -1) ; // 清除最低位的1
}
return c ;
}
查表法:
int BitCount3(unsigned int n)
{
// 建表
unsigned char BitsSetTable256[256] = {0} ;
// 初始化表
for (int i =0; i <256; i++)
{
BitsSetTable256[i] = (i &1) + BitsSetTable256[i /2];
}
unsigned int c =0 ;
// 查表
unsigned char* p = (unsigned char*) &n ;
c = BitsSetTable256[p[0]] +
BitsSetTable256[p[1]] +
BitsSetTable256[p[2]] +
BitsSetTable256[p[3]];
return c ;
}