高级语言入门_第1页
高级语言入门_第2页
高级语言入门_第3页
高级语言入门_第4页
高级语言入门_第5页
已阅读5页,还剩159页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

传智播客C语言入门教程(7)讲师:尹成QQ:77025077博客/yincheng01微博/yincheng8848网址C语言C++语言传智播客高薪就业传智播客C语言入门教程(7)大纲1.编译及预处理链表讲解栈,队列,链表综合学习C语言实战C语言面试传智播客C/C++学院课程介绍如果一个源程序由多个诸如A.c,B.h等的源文件组成,使用的编译链接器是如何根据这些文件生成可执行文件的?编译链接的机理到底是什么,这是本章要学习的内容。对C语言来说,除了掌握必要的语法机制外,学好预处理命令也是写出高质量代码的前提。宏预处理预处理是指在进行编译之前所作的处理,由预处理程序负责完成用一个标识符来表示一个字符串,称为

“宏”,被定义为

“宏”的标识符称为

“宏名”。宏替换\在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”;编辑可能就是通常所说的“写代码”,用集成开发工具也好,用记事本也好,按C语言的语法规则组织一系列的源文件,主要有两种形式,一种是.c文件,另一种是.h文件,也称头文件。前面接触到的“#include”和“#define”都属于编译预处理,C语言允许在程序中用预处理指令写一些命令行。预处理器在编译器之前根据指令更改程序文本。编译器看到的是预处理器修改过的代码文本,C语言的编译预处理功能主要包括宏定义、文件包含和条件编译3种。预处理器对宏进行替换,并将所包含的头文件整体插入源文件中,为后面要进行的编译做好准备。编译器处理的对象是由单个c文件和其中递归包含的头文件组成的编译单元,一般来说,头文件是不直接参加编译的。编译器会将每个编译单元翻译成同名的二进制代码文件,在DOS和Windows环境下,二进制代码文件的后缀名为.obj,在Unix环境下,其后缀名为.o,此时,二进制代码文件是零散的,还不是可执行二进制文件。错误检查大多是在编译阶段进行的,编译器主要进行语法分析,词法分析,产生目标代码并进行代码优化等处理。为全局变量和静态变量等分配内存,并检查函数是否已定义,如没有定义,是否有函数声明。函数声明通知编译器:该函数在本文件晚些时候定义,或者是在其他文件中定义。链接器将编译得到的零散的二进制代码文件组合成二进制可执行文件,主要完成下述两个工作,一是解析其他文件中函数引用或其他引用,二是解析库函数。举例来说,某个程序由两个c文件组成,分别为A.c、B.c,两个c文件和其中递归包含的头文件组成的两个编译单元,经过预处理和编译生成二进制代码文件A.obj和B.obj,假设A.c中调用了函数C,可函数C定义在B.c中,A.obj中实际上仅仅包括着对C函数的引用,其二进制定义代码需要从B.obj中提取,插入到A.obj的调用处,这个过程称为函数解析(resolve),由链接器完成。不仅仅是函数,变量(诸如有外部链接性的全局变量)也牵扯到解析的问题。当B.c没有定义函数C时,编译时不会产生错误,但链接时却会提示,有未解析的对象,据此可分析出问题出在编译阶段还是链接阶段。兴致勃勃地写完程序,编译链接,一大堆的错误提示,不要沮丧,再优秀的程序员也会犯错,有人说,程序编写的过程大部分的时间都是用在错误调试上。有时为了排除一个小问题,可能会几天几夜地跟踪代码,正因为如此,有人把问题找到并解决的刹那称为“痛苦的幸

福”。继续说明程序错误前,有个观点要说明:没有完美的程

序,不存在没有缺陷的程序,如果一个程序运行很完美,那是因为它的缺陷到现在还没有被发现。同样,软件测

试是为了发现程序中可能存在的问题,而不是证明程序

没有错误。错误可分两大类,一是程序书写形式在某些方面不合C语言要求,称为语法错误,这种错误将会由编译器指明,是种比较容易修改的错误,二是程序书写本身没错,编译链接能够完成,但输出结果与预期不符,或着执行着便崩溃掉,称为逻辑错误。细分下去,语法错误又可分为编译错误和链接错

误,很明显,编译错误就是在程序编译阶段出的

错误,而链接错误就是在程序链接阶段出的问题。如果文件中出现编译错误,编译器将给出错误信息,并指明错误所在的行,提示用户修改代码,编译错误主要有两类:(1)语法问题,缺少符号,如缺分号,缺括号等,符号拼写不正确,一般来说,编译器都会指明错误所在行,但由于代码是彼此联系的,有时编译器给出的信息未必正确。一般来说,源程序中出错位置要么就是编译器提示位置,要么在提示位置之前,甚至是在前面很远的地方。另一个问题是有时一个实际错误会让编译器给出很多出错提示,所以,面对成百上千个错误提示时,不要害怕,没准修改一处代码,所有的问题都解决了。(2)上下文关系有误,程序设计中有很多彼此关联的东西,比如变量要先创建再使用,有时编译器会发现某个变量尚未定义,便会提示出

错。这种情况有时是因为变量名拼写有误,有时是因为确实忘了定义。除了错误外,编译器还会对程序中一些不合理的用法进行警告(warning),尽管警告不耽误程序编译链接,但对警告信息不能掉以轻心,警告常常预示着隐藏很深的错误,特别是逻辑错误,应当仔细排查。当一个编译单元中调用了库函数或定义在其他编译单元中的函数时,在链接阶段就需要从库文件或其他目标文件中抽取该函数的二进制代码,以便进行组合等一系列工作,找不到函数定义时,链接器无法找到该函数对应的代码,便会提示出错,指出名字未解析。一般来说,链接器给出的错误提示信息是关乎函数的链接。即使程序顺利通过了编译链接,也不是说万事大吉,可以收工了,要检查生成的可执行程序,看其是否实现了所需的功能。实际上,运行阶段出现的逻辑错误更难排查,更让人头疼,编译错误和链

接错误好歹有提示信息,但面对逻辑错误,就像浑水摸鱼。可能出现的逻辑错误有以下情况:与操作系统有关的操作,是否进行了非法操作,如非法内存访问等。是否出现了死循环,表现为长时间无反应,假死,注意,长时间无反应并不一定都是死循环,有的程序确实需要很长时间,这种情况要仔细分析。程序执行期间发生了一些异常,比如除数为0等,操作无法继续进行。程序能正确执行,但结果不对,此时应检查代码的编写是否合乎问题规范。排除错误,有两层含义,找到出错的代码,修改该代码。排错也

有两种形式,一是静态排错,编译器和链接器发现的错误基本都

属于这一类,通过观察源程序便能确定问题所在并改正它。另一

种是动态排错,逻辑错误的发现和纠正都比较困难,要综合考虑

代码、使用的数据和输出结果的关联,仔细思考,尝试更换数据,观察结果的改变,依此分析错误可能存在的地方。如果还是不行,就要使用动态检查机制,最基本的方法是“分而治之”,检查程序执行的中间状态,最常用的方法是在可能出错的地方插入一些输出语句,让程序输出一些中间变量的值,确定可能出错的区域。此外,还可利用编译环境提供的DEBUG工具,对程序进行跟踪、监视和设断点等,定位并排错。预处理命令的引入是为了优化程序设计环境,提高编程效率,合

理使用预处理命令能使编写的程序易于阅读、修改、移植和调试,也有利于程序的模块化设计。预处理命令必须独占一行,并以#开头,末尾不加分号,以示与普通C语句的区别。原则上,预处理行可以写在程序的任何位置,但推荐(或是惯常写法)写在程序文件的头部。编译器在对文件进行实质性的编译之前,先处理这些预处理行,这也是“预”字的含义。C语言的编译预处理功能主要包括宏定义、文件包含和条件编译3种。对宏已经不再陌生,在字符常量一节中,已经介绍过#define的用法,宏即是用#define语句定义的。宏定义是用宏名来表示一个字符串,在编译预处理时,对程序中所有出现的宏名,

都用宏定义中的字符串来替换,称为“宏代换”或“宏展开”。宏展开只是种简单的代换,字符串中可以包含任何字符,可以是常数,也可以是表达式,预处理器进行宏展开时并不进行语法检查。/*使用printf要包含的头文件*//*宏定义允许嵌套*/#define

OUTPUT

printf("Hello,C\n");/*主函数*/不带参数宏的一般定义形式为:#define

宏名宏体宏名的命名规则与变量相同,一般习惯用大写字母,以便与变量区分,当然,这并不是说不允许使用小写字母作为宏名。来看一个不带参数宏的示例,从中学习一些宏的用法:#include

<stdio.h>#include

<stdlib.h>#define

SIDE

5#define

SQUARE

SIDE*SIDE#define

PI

3.14159265void

main(void){intx=SQUARE;printf("x

is

%d\n",x);if(PI<4)OUTPUTprintf("PI

is

%f",PI);getcharar();/*等待,按任意键继续*/}#define定义的常量称为符号常量,而const常量常称静态常量,相比#define,const有很多优势,在实际使用时,推荐采用

const定义常量。对#define定义的符号常量,预处理器只是进行简单的字符串替换,并不对其进行类型检查,而且会与程序中定义的同名变量冲突,如:#define

num

10;void

disp(){int

num;Printf(“%d”,num);}编译时,预处理器会将disp函数中的语句“int

num;”替换成

“int10”,若使用“const

int

num=10;”便不会出现这种问题。1、预处理程序对宏定义不作语法检查。2.宏定义不是普通C

语句,在行末不必加分号,如加上分号则连分号也一起置换例#define

N

3Omain(

){int

i;for(i=1;i<=N;i++)printf("%d\n",i);}宏名在源程序中若用引号括起来,则预处理程序不对其作置换例#define

PRICE

88main(

){printf("PRICE

IS

%d",PRICE);}运行结果如下:

PRICE

IS

88而不是88

IS88,即双引号中的PRICE

没有用88代替同一个宏名不能重复定义如#define

PRICE

88和#define

PRICE

100不能同时出现在同一段程序中。宏定义中的字符串不能替换用户标志符中与宏名相同的部分PRICE

88#definemain(

){int

BOOK_PTICE=10;}程序中的BOOK_PTICE中的PRICE不会被替换为BOOK_88。宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。#defineM10#defineN2#defineXM+100#defineYM*Nmain(){printf("M=%d\nN=%d\nX=%d\nY=%d\n",M,N,X,Y);}运行结果是:M=10N=2X=110Y=20在第三条宏定义#define

X

M+100语句中,用到了前面已经定义过的宏M宏定义一般写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。#define

N

100main(){……}#undef

Nmax(){……}N只在main函数中有效,在max中无效C语言有一类宏可以带有参数,在宏定义中的参数称为形式参数,在宏展开中的参数称为实际参数。带参宏展开的一般形式为:宏名(实参表);带参数的宏在编译连接后,不仅要展开宏,而且要用实参去代换形参,在宏定义中的形参是标识符,而宏展开中的实参可以是任意表达式。带参宏定义的一般形式为:例:#define 宏名(形参表) 字符串ADD(x)

x*10#define/*宏定义*/……a=ADD

(3);/*宏展开*/在宏展开时,用实参3去代替形参x,经预处理宏展开后的语句为:a

=3*10;#defineCUBE(x)((x)*

(x)*

(x))main(

){double

y;float

z=10;int

i;int

j=2;y=

CUBE

(z);i=

CUBE

(j);printf("y=%8.1f\ni=%d\n",y,i);}运行结果是:

y=1000.0i=8执行语句y=CUBE(z);时自动将z的值代替((x)*

(x)*

(x))中的x,

执行语句i=CUBE

(j);时自动将j的值代替((x)*

(x)*(x))中的x,并且将结果返回给CUBE,再分别赋值给y、i类似函数的带参数宏定义

#include"stdio.h"{int

t;t=a;a=b;b=t;}#defineexchange(a,b)voidmain(){int

x=10;int

y=20;printf("x=%d;

y=%d\n",x,y);exchange(x,y);printf("after

exchange:x=%d;y=%d\n",x,y);}上述程序运行结果如下:

x=10;y=20afterexchange:x=20;y=10文件包含是C语言预处理的另一个重要功能,用“#include”来实现,将一个源文件的全部内容包含到另一个源文件中,成为它的一个部分,文件包含的一般格式为:#include<文件名>或者#include

“文件名”两种形式的区别在于:使用尖括号表示在系统头文件目录中查找(由用户在设置编程环境时设置),而不在源文件目录中查找。使用双引号则表示首先在当前的源文件目录中查找,找不到再到系统头文件目录中查找。#include

“文件名”格式下,用户可以显式指明文件的位置,如:#include

“D:\A\B\C.h”#include

“..\X.h”#include

“.\X.h”#include

“\X.h”/*上级目录下的X.h文件*//*当前级目录下的X.h文件*//*当顶级目录下的X.h文件*/1、一条include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。不能这样写include语句:#include

“m1.h,m2.h”

或#include

“m1.h”,”m2.h”而必须写成:#include

“m1.h”

#include

“m2.h”2、文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。3、文件包含语句中被包含的文件通常是以.h结尾的头文件,这种头文件中的内容多为变量的定义、类型定义、宏定义、函数的定义或说明,但被包含的文件也可以是以.c为扩展名的C语言源文件。#endif#ifndef

标识符程序段1#else程序段2#endif通过某些条件,控制源程序中的某段源代码是否参加编译,这就是条件编译的功能,一般来说,所有源文件中的代码都应参加编译,但有时候希望某部分代码不参加编译,应用条件编译可达到这以目的。条件编译的基本形式为:#if

判断表达式语句段1#else语句段2与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被

#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。这与第一种形式的功能正相反。讨论了C语言程序编译及预处理的相关内容,C程序的编译分编辑、预处理、编译和链接几个步骤,预处理指令

是由预处理器负责执行的,主要有头文件包含、宏定义、条件编译等,经过预处理后,编译器才开始工作,将每

个编译单元编译成二进制代码文件,但此时分散的二进

制代码文件中的变量和函数没有分配到具体内存地址,

因而不能执行,需要链接器将这些二进制代码文件、用到的库文件中相关代码,系统相关的信息组合起来,形成二进制可执行文件。掌握程序编译链接的过程能帮助理解错误的根源,提高调试的效率,是写出高质量代码的必要条件。1234链表是一种常见的重要的数据结构它是动态地进行存储分配的一种结构head124912491356A1356B1475C1021D\0头指针各结点地址不连续1475

1021各结点含有两个部分表尾struct

Student{ int

num;float

score;struct

Student

*next;}a,b,c;1010189.510103901010785a结点b结点a.next=&b;b.next=&c;numscorenext建立简单的静态链表建立一个如图所示的简单链表,它由3个学生数据的结点组成,要求输出各结点中的数据。1010189.510103901010785numscorenext建立简单的静态链表1010189.51010390headnumscorenext1010785NULLhead=&a;a.next=&b;b.next=&c;c.next=NULL;所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。写一函数建立一个有3名学生数据的单向动态链表。链表的建立一般是指先建立一个空链表,而后一个个地将元素插在队尾。删除几乎可以看成是结点插入的逆操作,将到换一个顺序即可:如果删除的是第1个数据结点,即从到,则应使

head指针指向E1,同时释放掉Einsert申请的动态内存。如果删除的是中间结点,即从到,则只需让E2->next指向Einsert->next,同时,释放掉

Einsert占据的动态内存。如果删除的尾结点,即从到,只需让E1->next为NULL,同时释放掉Einsert占据的动态内存。所谓链表的逆置,是指“头变尾,尾变头”,将原来的“ABCD……”变成

“……DCBA”,先从单链表模型来看,如:/*删除结点*//*释放内存*//*释放第1个结点所占内存*/在链表使用完毕后,需将其销毁,回收所分配的内存。由于是整体销毁,实现起来比结点的删除简单,可以采取如下策略:每次删除第1个结点后面的结点,最后再删除头结点,这样即可实现整个链表的销毁。仅仅删除第1个结点并不意味着整个链表被删除掉了,链表是一个结点一个结点建立起来的,所以,销毁它也必须一个结点一个结点地删除才行。编写链表销毁的函数如下:void

freeAll(STU*

head){STU*

p=NULL,*q=NULL;p=head;while(p->next!=NULL){q=p->next;p->next=q->next;free(q);}free(head);}数组链表各个不同实现链表逆转实现链表排序以及删除所有节点构建一个链表的数据结构栈和队列。栈和队列的操作受到了一定程度的限制对栈而言,只能在栈顶一端进行元素的插入和删除.队列只允许在一段插入,在另外一端删除元素。数据结构是合理组织数据的手段,掌握数据结构,能使代码组织清晰,程序质量高,易读易维护。栈是种“先入后出”的结构,打个比方,栈相当于放餐具的带底木桶,而数据相当于一个个的盘子,刷完的盘子一个个摞起来放在桶里,用盘子时就一个个从桶中取出。很容易理解,最先刷好的盘子会放在桶底,此时,只有上面的盘子用光了才会将其拿出来,这就是所谓的先入后出FILO(First

InLast

Out),等价的说法是后入先出。一个栈有以下要素:栈底(表示栈的开始位置,木桶的底部),栈顶(当前数据已经排放在什么位置了,当前盘子摞了多高了),不含元素的栈称为空栈。形象的示意如:根据元素储存方式的不同,可以将栈分为顺序栈和链式栈两类:(1)顺序栈利用一组连续的内存单元依次存放自栈底到栈顶的数据,同时,用一个指针top只是栈顶的位置,在C语言中,这可用数组来实现,一般是先开辟一块区域,在编程中可根据需要再对此区域进行调整。(2)链式栈链式栈的结构与链表类似,如所示,其中,top为栈顶指针,始终指向栈顶元素,栈顶元素的指针指向下一个元素,依此类推,直到栈底,栈底元素的指针区域为空如果top为空,表示该栈是个空栈。对栈元素的操作有一定限制,不允许随意访问栈中间的元素,只允许访问栈顶元素,对栈的操作有以下几种:判断栈是否为空,判断栈是否已满(只针对顺序栈),将一个元素压入栈,从栈中弹出一个元素,销毁一个栈(或称清空一个栈)。判断栈是否为空相对来说比较简单,只要判断下top指针是否为NULL即可,下面给出栈的使用范例,如:用栈实现进制转换用栈实现逆序用栈实现进制转换项目实践算法信息处理游戏安全问题所在问题分析问题分解设计逻辑与封装逐步实现12345入口出口面向过程设计规则设计理念封装可复用耦合度,是指模块之间相互依赖性大小的度量,耦合度越小,

模块的相对独立性越大。内聚度,是指模块内各成份之间相互

依赖性大小的度量,内聚度越大,模块各成份之间联系越紧密,其功能越强。AmericaEuropeAsia巴西美国非洲俄罗斯案例实现调戏百度阿里腾讯360微软谷歌迅雷案例实现编写植物大战僵尸外挂案例实现编写双星物语外挂,加血加钱加雷案例实现远程控制游戏挂3D游戏引擎信息安全信息系统案例IDE

编译并执行C语言C++语言案例实现物联网传感器分类以及数量管理案例实现传智播客教主黎活明大战企业面试官案例实现C语言实现数据加密解密案例实现C语言实现自我复制案例实现C语言实现自我删除案例实现C语言文件切割与合并案例耍流氓借助detours拦截系统API检验你前面学习的效果好坏,就看你是否能够通过世界五百强严酷的C语言考核,不过五百强很有挑战,你先搞定基础的面试题100题。面试

笔试

机试检验你是否通关1、请填写

bool

,

float,

指针变量 与“零值”比较的

if

语句。提示:这里“零值”可以是0,

0.0

,

FALSE或者“空指针”

。例如

int

变量

n

与“零值”比较的

if

语句为:if

(n

==

0)if(

n!=

0)以此类推。与“零值”比较的(1)请写出

bool

flagif

语句:【标准答案】if(flag)if

(

!flag

)(2)请写出

float

x

与“零值”比较的

if

语句:【标准答案】

const

float

EPSINON

=0.00001; if

((x

>=-EPSINON)

&&

(x

<=

EPSINON)不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。(3)请写出

char

*p

与“零值”比较的

if语句【标准答案】

if

(p

==

NULL) if

(p

!=NULL)2、以下为Linux下的32

位C程序,请计算

sizeof的值。charcharstr[]

=

“Hello”;*p

=str

;int n

=

10;请计算sizeof

(str

)=sizeof(p)=sizeof(n)=【标准答案】(1)6、(2)4、(3)4(4)void

Func

(

char

str[100]){……

;}请计算sizeof(

str)=(5)void

*p

=

malloc(

100

);请计算sizeof(p)=【标准答案】(4)4、(5)43、long

a=0x801010;a+5=?【标准答案】0x801010用二进制表示为:“1000

0000

0001

0000

0001

0000”,十进制的值为8392720,再加上5就是8392725。4、写一个函数找出一个整数数组中,第二大的数。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(structdate)+sizeof(max));的执行结果是:

【标准答案】DATE是一个union,变量公用空间.里面最大的变量类型是int[5],占用20个字节.所以它的大小是20data是一个struct,

每个变量分开占用空间.依次为int4+

DATE20+double8=32.所以结果是20+32=52.6、请问以下代码有什么问题:

int

main(){char

a;char

*str=&a;strcpy(str,"hello");printf(str);return

0;}【标准答案】没有为str分配内存空间,将会发生异常问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。7、请问以下代码有什么问题:

char*

s="AAA";printf("%s",s);s[0]='B';printf("%s",s);有什么错?【标准答案】"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。cosnt

char*

s="AAA";然后又因为是常量,所以对是s[0]的赋值操作是不合法的。8、写出下面的结果char

str1[]

=

"abc";char

str2[]

=

"abc";const

char

str3[]

=

"abc";const

char

str4[]

=

"abc";const

char

*str5

=

"abc";const

char

*str6

=

"abc";char

*str7

=

"abc";char

*str8

=

"abc";cout

<<

(

str1

==

str2

)

<<

endl;

cout

<<

(

str3

==

str4)

<<

endl;

cout

<<

(

str5

==

str6

)

<<

endl;

cout

<<

(str7

==

str8

)

<<

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

c++中的struct可以。10、写出输出结果Int

main(){int

a[5]={1,2,3,4,5};int

*ptr=(int

*)(&a+1);printf("%d,%d",*(a+1),*(ptr-1));}11、char

szstr[10];strcpy(szstr,"");产生什么结果?为什么?【标准答案】长度不一样,出现段错误。12、int

a=248;

b=4;int

constc=21;constint*d=&a;int

*const

e=&b;int

const

*fconst=&a;请问下列表达式哪些会被编译器禁止?为什么?13、void

main(){char

aa[10];printf(“%d”,strlen(aa));}会出现什么问题?打印结果是是多少?【标准答案】sizeof()和初不初始化,没有关系,strlen()和初始化有关,打印结果值未知。14、给定结构struct

A{chart:4;chark:4;unsigned

short

i:8;unsigned

long

m;};问sizeof(A)=?【标准答案】815、struct

name1{charstr;short

x;int

num;};求sizeof(name1)?【标准答案】816、struct

name2{ charstr;int

num;short

x;};求sizeof(name2)?【标准答案】12

17、程序哪里有错误

wap(int*

p1,int*

p2){int*p;*p

=

*p1;*p1=*p2;*p2

=*p;}【标准答案】p为野指针18、什么是预编译,何时需要预编译?

预编译又称为预处理,是做些代码文本的替换工作。处理

#开头的指令,比如拷贝#include

包含的文件代码,

#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。c

编译系统在对程序进行通常的编译之前,先进行预处理。c提供的预处理功能主要有以下三种:1)宏定义2)文件包含3)条件编译19、(void*)ptr和(*(void**))ptr的结果是否相同?其中ptr为同一个指针。【标准答案】(void

*)ptr

和(*(void**))ptr值是相同的20、要对绝对地址0x100000赋值,我们可以用

(unsigned

int*)0x100000=1234;那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?【标准答案】*((void

(*)())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)));}23、关于内存的思考题(2)你能看出有什么问题?25、关于内存的思考题(3)你能看出有什么问题?26、关于内存的思考题(4)你能看出有什么问题?27.main函数既然不会被其它函数调用,为什么要返回1int

main(){int

x=3;printf("%d",x);return

1;}28、请写出输出结果int

sum(int

a){auto

intc=0;static

int

b=3;c+=1;b+=2;return(a+b+c);}void

main(){intI;inta=2;for(I=0;I<5;I++){printf("%d,",

sum(a));}}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、完成输出下列字符**.*.*..*..*..*...*...*...*...*....*....*....*....*....*.....*.....*.....*.....*.....*.....*......*......*......*......*......*......*......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、带参宏与带参函数的区别(至少说出5点)?【标准答案】带参宏 带参函数处理时间参数类型程序长度占用存储空间运行时间编译时无变长否不占运行时间运行时需定义不变是调用和返回时占41、请写出数组的冒泡排序法,选择排序法,插入排序法。42

、请写出链表的插入排序法,冒泡排序法。43、已知一个数组table,用一个宏定义,求出数据的元素个数。【标准答案】#define

NTBL(table)(sizeof(table)/sizeof(table[0]))44、A.c和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?【标准答案】static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。他们都放在静态数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern关键字。45、单连表的建立,把'a'--'z'26个字母插入到连表中,并且倒叙,还要打印46、求组合数:求n

个数(1....n)中k个数的组合....如:combination(5,3)要求输出:543,542,541,532,531,521,432,431,421,321,47、求全排列:求n个数(1....n)中k个数的排列....如:P(2,2)1221如:P(3,2)12

21 13

3123

3248、程序的局部变量存在于中,全局变量存在于

中,动态申请数据存在于 中。【标准答案】程序的局部变量存在于栈(stack)中,全局变量存在于静态数据区中,动态申请数据存在于堆(heap)中。49、什么是预编译,何时需要预编译:【标准答案】1、总是使用不经常改动的大型代码体。

2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况

下,可以将所有包含文件预编译为一个预编译头。50、用两个栈实现一个队列的功能?要求给出算法和思路!【参考答案】设2个栈为A,B,一开始均为空.入队:将新元素push入栈A;出队:判断栈B是否为空;如果不为空,则将栈A中所有元素依次

pop出并push到栈B;将栈B的栈顶元素pop出;51、对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?【标准答案】c用宏定义,c++用inline52、1.用预处理指令#define

声明一个常数,用以表明1年中有多少秒(忽略闰年问题)【参考答案】#define

SECONDS_PER_YEAR(60

*

60*

24

*365)UL53、有一分数序列:1/2,1/4,1/6,1/8„„,用函数递归调用的方法,求此数列前20

项的和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

循环的优缺点。56、两个字符串,s,t;把t字符串插入到s字符串中,s

字符串有足够的空间存放t字符串57、请编写一个

C

函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值。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,12059、unsignedchar*p1; unsignedlong

*p2;p1=(unsigned

char

*)0x801000;p2=(unsigned

long*)0x810000;请问p1+5=;p2+5=

;【标准答案】0x801005、0x81002060、main(){inta[5]={1,2,3,4,5};int

*ptr=(int

*)(&a+1);printf(“%d,%d”,*(a+1),*(ptr-1));}请问输出:【标准答案】2,561、请问下面程序有什么错误?inta[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;intb;b=SQUARE(a++);【标准答案】宏在预编译时会以替换的形式展开,仅仅会替换。涉及到宏的地方,不要用++--,标准中对此没有规定,因此最终结果将会依赖于不同的编译器。执行程序的答案可能是25、也有可能是36。63、#define

Max_CB

500void

LmiQueryCSmd(Struct

MSgCB

*

pmsg){unsigned

char

ucCmdNum;......for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++){......;}}这段代码执行有什么问题?【标准答案】死循环unsigned

char//无符号字符型表示范围0~255char//有符号字符型表示范围-128~12764、请写入一个宏,传入变量的时候,输出变量名。65、程序输出结果是?66、求输出67、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("Third

output:%dn",x);}输出?【标准答案】12、13、1368、有双向循环链表结点定义为:struct

node{

int

data;struct

node

*front,*next;};有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data

值相同的结点删除69、请写出下列代码的输出内容#i

nclude<stdio.h>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,12070、找出程序的错误。71、一语句实现x是否为2的若干次幂的判断。【参考答案】voidmain(){inta;scanf(“%d”,&a);printf(“%c”,(a)&(a-1)?’n’:’y’);// 若是打印y,n}72、编写一个C函数,该函数在一个字符串中找到可能的最长的子字符串,且该字符串是由同一字符组成的。73、下面的代码输出是什么,为什么?

void

foo(void){unsigned

int

a

=

6;int

b

=

-20;(a+b

>

6)?

puts(">

6")

:

puts("<=

6");}【参考答案】这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。74、评价下面的代码片断:

unsignedintzero=0;unsigned

int

compzero

=0xFFFF;/*1‘s

complement

of

zero

*/【参考答案】对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:unsigned

int

compzero

=

~0;这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。75、下面的代码片段的输出是什么,为什么?char

*ptr;if

((ptr

=

(char

*)malloc(0))

==NULL)puts("Got

a

nullpointer");elseputs("Got

a

validpointer");76、编写strcpy

函数已知

strcpy

函数的原型是

char

*strcpy(char

*strDest,const

char

*strSrc);其中strDest

是目的字符串,strSrc是源字符串。

(1)不调用C++/C

的字符串库函数,请编写函数strcpy

。(2)strcpy

能把strSrc

的内容复制到strDest,为什么还要

char

*

类型的返回值?77、编程实现:把十进制数(long型)分别以二进制输出,不能使用printf

系列库函数。78、请编写一个C函数,该函数给出一个字节中被置1

的位的个数。int

TestAsOne0(char

log)unsigned{int

i;int

num=0,

val;i<8;

i++)=

log

>>i; //移位unsignedfor(i=0;{valval&=

0x01;//与1相与if(val)num++;}return

num;}79、请编写一个C函数,该函数将给定的一个字符串转换成整数。【参考答案】int

Invert(char

*str){int

num=0;while(*str!='\0'){int

digital=*str-48;num=num*10+digital;str=str+1;}return

num;}80、请编写一个C

函数,该函数将给定的一个整数转换成字符串。void

IntToCharChange(int

num,

char*

pval){char

strval[100];int

i,

j;intintval0val0

=

0;val1

=

0;=

num;for(i=0;{i<100;i++)val1

=val0

=val0val0%/10;10;//取余//取整+

48;

//数字—字符strval[i]if(val0{=

val0

+

48;=

val1<

10)i++;strval[i]break;}}for(j=0;j++)

//倒置= strval[i-j];pval[j]j<=i;pval[j]=

'\0';81、用递归算法判断数组a[N]是否为一个递增数组。。82、请编写一个C递归函数,该函数将一个字符串逆序。83、请编写一个C函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值。intsearch(char*cpSource,intn,charch)//起始地址,搜索长度,目标字符{int

i;for(i=0;

i<n

&&

*(cpSource+i)

!=

ch;

++i);return

i;}84、请编写一个C

函数,该函数在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成的。int

ChildString(char*p)

//自己写{char

*q=p;int

stringlen=0,i=0,j=1,len=0,maxlen=1;while(*q!=’\0’)

//不能用strlen,求得长度stringlen{Stringlen++;q++;}while(

i<

Stringlen

){if(*(p+i)==*(p+j)&&j<

Stringlen){//统计子串长度len++;i++;j++;}else{if(len>maxlen) //统计最大子串长度{maxlen=len+1;len=0;}elselen=0;i++;j++;}85、华为面试题:怎么判断链表中是否有环?【参考答案】答:用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步; 当p2

指针追上

p1的时候,就表明链表当中有环路了。int testLinkRing(Link

*head){Link

*t1=head,*t2=head;while(

t1->next

&&

t2->next){t1

=

t1->next;if

(NULL==(t2=t2->next->next))return

0; //无环if

(t1

==

t2)return

1;}return

0;}86、有一浮点型数组A,用C语言写一函数实现对浮点数组A进行降序排序,并输出结果,要求要以数组A作为函数的入口.(建议用冒泡排序法)void

BubbleSort(double

arr[],

int

n){int

i,j;int

exchange

=

1;

//交换标志for(i=1;i<n;i++){ //最多做n-1趟排序exchange=0;

//本趟排序开始前,交换标志应为假for(j=n-1;j>=i;j--) //对当前无序区R[i..n]自下向上扫描if(arr[j+1]

>

arr[j]){//交换记录arr[0]=arr[j+1];

//R[0]不是哨兵,仅做暂存单元

arr[j+1]=arr[j];arr[j]=arr[0];exchange=1;

//发生了交换,故将交换标志置为真}if(!exchange) //本趟排序未发生交换,提前终止算法return;} //endfor(外循环)}87、实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。//删除操作Status

ListDelete_DuL(DuLinkList

&L,int

i,ElemType&e){if(!(p=GetElemP_DuL(L,i)))

return

ERROR;e=p->data;p->prior->next=p->next;p->next->prior=p->pror;free(p);return

OK;}//插入操作Status

ListInsert_DuL(DuLinkList

&L,int

i,ElemType

&e){if(!(p=GetElemP_DuL(L,i)))return

ERROR;if(!(s=(DuLinkList)malloc(sizeof(DuLNode))))return

ERROR;s->data=e;s->prior=p;p->

next

->

prior

=s;p->next=s;s->next=p->next->next;return

OK;}88、读文件file1.txt

的内容(例如):123456输出到file2.txt:56341289、输出和为一个给定整数的所有组合90、输入一行字符,统计其中有多少个单词。#include

<stdio.h>main(){char

string[81];int

i,num=0,word=0;char

c;gets(string);for(i=0

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论