C语言基础知识总结大全(干货)

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,下面为大家带来C语言基础知识梳理总结,C语言零基础入门绝对不是天方夜谭!

算法结构:

一、顺序结构、选择结构、循环结构;二、循环结构又分为while型、until型、for循环结构;程序流程图;

结构化程序设计方法:

(1)自顶向下;(2)逐步细化;(3)模块化设计;(4)结构化编码。

数据类型:

常量:常量包括字面常量、直接常量和符号常量;

变量:C语言规定标志符只能由字母、数字和下划线三种字符组成,且第一个字符必须是字母或者下划线;必须压迫先定义后使用;每一个变量被定义以确定类型后,在编译时就能为其分配相应的存储单元;

整数类型:整数常量有十进制、八进制和十六进制;“%d”

整形变量:数据在内存中存放形式是以二进制形式存放;有int型、short int型和long int型,无符号整型变量的范围是-32768—32767,有符号型为0~65535.通常把long定义为32位,把short定义为16位,int可以是32位也可以为16位,这都主要取决于机器字长。

实型常量的表示方法:(1)十进制,0.0;(2)指数形式,123e3

实型变量:实数型数据在内存中的存放形式,一般在内存中占4个字节,分成整数部分和小数部分存放。实型变量分为float型、double型long double型。实型数据会存在舍入误差。

实型常量的类型:C编译系统将实型常量作为双精度来处理。

字符型数组:(一)字符常量:转义字符(\\n——换行,\\t——tab,\\r——回车,\\f——换页,\\b——退格,\\ddd——1到3位8进制的数代表的字符)(二)字符变量:字符数据存储形式实际是以ASCII码存储。“%c”字符串常量:双撇号括起来的一系列字符序列。

C的运算符有以下几种:

1、算术运算符(+ – * / %)结合方向自左向右2、关系运算符(> < ==\”\”>= <= !=\”\”>3、逻辑运算符(! && ||)4、位运算符(<>> ~ | ^ &)5、赋值运算符(=及符号扩展赋值运算符)6、条件运算符(? : )7、逗号运算符( , )8、指针运算符(* &)9、求字节运算符(sizeof)10、强制类型转换运算符((类型))11、分量运算符( . ->)12、下标运算符([])13、其他

控制语句:

完成一定的控制功能。1、if()~else~2、for()~3、while()~4、do~while()5、continue6、break7、switch8、goto9、return

字符数据的输入输出:

1、putchar()输入字符变量2、getchar()只能接受一个字符

格式输入输出:

1、printf(%d—整型,%c—字符型,%ld,%md,%o,%u,%s,%-m.nf,%e,%g)2、scanf(格式控制,地址列表)

数组

一维数组的定义:类型说明符 数组名【常量表达式】;先定义后引用;一维数组初始化时可以只对一部分元素初始化,在对全部数组元素初始化的时候可以部规定长度;但是若被定义的数组长度与提供的初始值不一样时,则数组长度不能省略。

二维数组的定义:类型说明符 数组名【常量表达式】【常量表达式】C语言中存放二维数组是先存放第一行的元素,紧接着是第二行,其实也是以一维的方式存放。如果初始化时能指定所有元素的初始值,第一维大小可以省略,但是第二维不能省略。

字符数组:定义和初始化跟数组差不多,只是需要加单引号。字符和字符串结束标志,C语言规定,以\’\\0’代表。

字符串处理函数:1、puts()将一个字符串输出到终端2、gets()从终端输入一个字符串到字符数组,并且得到一个函数值。3、strcat()链接两个字符数组中的字符串。4、strcpy()字符串复制函数。5、strcmp()比较字符串作用。6、strlen()测试字符串长度的函数不包括“\\0”7、strlwr()将字符串中的大写字母转换为小写字母。8、strupr()将字符串中的小写字母转换为大写字母。

函数

(1)一个源程序由多个函数组成。(2)C程序的执行从main()函数开始;(3)所有函数都是平行的;(4)函数分类;可以分为标准和自定义,还可以分为有参函数和无参函数。

函数定义的一般形式:

(1)类型标志符 函数名(){声明部分语句}(2)类型标志符 函数名(形式参数列表){声明部分语句}

关于形参和实参的说明:

(1) 在定义函数中指定的形参,在未出现函数调用时,他们并不占用内存中的存储单元,只有发生调用时,才会分配内存。(2) 实参可以是常量、变量或者表达式;有时传递的时地址;(3) 在被定义中,形参必须指定类型;(4) 实参与形参的类型应相同或赋值兼容;(5) C语言规定,实参变量对形参变量的数据传递是“值传递”,即单向传递,只有实参传递给形参,而不能由形参传递给实参。

函数的返回值:

希望通过函数调用使主调函数得到一个确定的值。(1)函数的返回值是通过函数中的return语句获取的。(2)函数值的类型;(3)如果函数值的类型和return语句中表达式的值不一样,则以函数类型为准。(4)如果调用函数中没有return语句,并不带回一个确定的用户需要的值,函数不是不带回值,而只是不带回有用的值,带回一个不确定的值。(5)如不需要带回任何值,用void。

函数的调用:

调用方式1、函数语句;2、函数表达式;3、函数参数。

被调用的函数的声明:

一个函数调用另一个函数所具备的条件:

1、首先被调用的函数必须是已经存在的函数;2、如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。3、如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。4、如果被调用的函数定义出现在主调函数之前可以不必声明。5、如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明。

局部变量和全局变量:

(一)局部变量在一个函数内部定义的变量是内部变量,它只是在本函数范围内的有效,主函数也不能使用其它函数中定义的变量;不同函数中可以使用相同的名字的变量,他们代表不同的对象,互不干扰;形式参数也是局部变量;在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合句也可以称为“分程序”或“程序块”;

(二)全局变量,在函数之外定义的变量称为外部变量,全局变量可以增加函数间数据联系的渠道,一般不再必要时不要使用,他在程序的全部执行过程中占用存储单元,是函数的通用性,使用全局变量会使程序的清晰性降低。还要注意若果同一源文件中,外部变量和局部变量同名,则在局部变量作用范围内,外部变量被“屏蔽”,不起任何作用。

变量的存储类别:

(变量值存储时间)动态存储方式,在程序运行期间进行分动态的分配存储空间的方式,静态存储方式是指在程序运行期间分配固定的存储空间的方式;存储空间分为程序区、静态存储区和动态存储区;全局变量全部放在静态存储区中,程序开始时分配空间,完毕时释放;动态存储区中存放以下数据:

1、函数形式参数;

2、自动变量;

3、函数调用时的现场保护和返回地址;在C语言中每个变量和函数都有两个属性,是数据类型和数据存储类型,存储类别是数据在内存中存储的方式。

存储方式分为静态和动态存储类,具体包含有四种:自动的(auto),静态的(static),寄存器的(register),外部的(extern),如果不加以声明,就自认为是auto型就会自动分配存储空间属于动态存储方式。

Static声明局部变量是在函数调用结束后不消失而保留原值,即占用存储单元不释放,在下一次调用该函数时,该变量已有值,就是上次函数调用结束时的值。其中需要说明的是在定义局部变量不赋初值的话,则静态局部变量编译时自动赋值为0或者空字符,虽然静态局部变量在函数调用结束后仍然存在,但是其他函数不能引用它的。静态局部变量主要用在当初始化后,变量只是被引用而不改变其值。

Register变量是C语言中允许将局部变量的值放在CPU中的寄存器中需要时直接从寄存器中取出来参加运算,不必再到内存中提取,但是计算机系统中寄存器数量有限,不能任意定义任意多的存储器,局部静态变量不能定义为寄存器变量。

Extern声明外部变量,用以扩展外部变量的作用域。在一个文件中,如果定义之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量做外部变量声明。在多文件中,也可以采用extern声明的办法进行外部变量声明。有时希望某些局部变量只限于被本文件引用,而不能被其他文件引用,这时就可以采用在定义外部变量时外加一个static,这在程序模块化设计中加强了通用性。

Static来声明一个变量的作用有二个,一个是在声明对局部变量时。则为该变量分配的空间在整个程序执行期间始终存在;一个是在对全局变量声明中,该变量的作用域仅限于本文件模块操作。

注意:这些方法同样适用于函数的声明。

这才是你想要的C语言学习路线

作为一门古老的编程语言,大家熟知它不仅是因为拥有48年的发展历程,更主要还是因为当下大部分程序员走入编程世界第一个学习的语言就是C语言。

而近年来高速发展的物联网和智能设备,又把C语言推向了风口浪尖,让它一举成为TOBLE 2019年度编程语言榜首。

熟悉C语言的程序员们更喜欢称C为“造轮子”的语言,因为它什么都能做。游戏公司后台开发、通信公司后台开发、服务端底层应用优化、后台系统驱动和内核……在程序员眼里,这个48岁的C语言几乎是无所不能的。

当然,很多人会觉得C语言入门难,不能像其他编程语言一样快速获得成就感。但仍然有很多技术大咖建议大家有必要学一下C语言。因为优秀的程序员并不是精通某一种编程语言,而是能精确把握编程思想。

这恰好是学C语言的一大好处——可以深入了解计算机底层运行机制。

现在常见的高级语言的底层几乎都是C语言实现的,所以,无论是学什么高级原理,要想掌握其内部原理,借助C语言就可以轻松了解。

01

学习C语言的建议

除了C语言本身之外,程序员必学的内容还有数据结构和算法、数据库原理、计算机网络、操作系统、设计模式,这些都是从事开发必须掌握的基础技能。

在初学C语言时,很多新人会觉得太难了,可能会遇到有些问题理解不透,有的是表达方式与以往数学学习中不同(如运算符等)。这个时候万万不能不气馁,不明白的地方多问多想,鼓足勇气进行学习,待学完后面的章节知识,前面的问题也就迎刃而解。

学习编程语言就是一个坚持看、敲、写的过程。

给自己定一个学习目标

很多人刚开始学习热情十分浓厚,但三分钟热度过后就失去了兴致。当学习有了目标就有了方向,努力往那个方向专研总会学有所成。

认准路线

就按计划学习C语言的学习路线是从基础语法再到高阶算法,不能一口吃成胖子,所以当大家选择了一本可以系统学习的书就认真学完。

多思考,多读源码

在自己无法自主编写代码的时候,可以模仿别人写的代码,学习其中的思想,一步步形成自己的东西,慢慢你就会发现你也可以了。

自己改写程序

通过前面的学习,应该已经掌握一些基本的编程技巧。一定要有自己的想法,然后让自己的想法通过程序来实现。编程语言的学习过程就是坚持的过程,只要掌握了一种编程语言,再去学习其他的语言就很轻松了。

了解C11新特性

2007 年,C语言标准委员会又重新开始修订C语言,到了 2011 年正式发布了 ISO/IEC 9899: 2011,简称为 C11 标准。

C11标准新引入的特征尽管没 C99 相对 C90 引入的那么多,但是这些也都十分有用,比如:字节对齐说明符、泛型机制(generic selection)、对多线程的支持、静态断言、原子操作以及对 Unicode 的支持。

此次,委员会提出了一些新的指导原则。出于对当前编程安全的担忧,不那么强调“信任程序员” 目标了。而且,供应商并未像对 C90 那样很好地接受和支持 C99。这使得 C99 的一些特性成为 C11 的可选项。因为委员会认为,不应要求服务小型机市场的供应商支持其目标环境中用不到的特性。

另外需要强调的是,修订标准的原因不是因为原标准不能用,而是需要跟进新的技术。例如,新标准添加了可选 项支持当前使用多处理器的计算机。

02

怎么学习C语言

那该如何学C语言呢?希望我整理的 C语言的学习路线,能对你有帮助!

首先是C语言的基础语法:变量、字符串、条件、循环、数组、函数、结构体等,然后就是指针、内存管理等C语言中至关重要的两大标准。

因此,学习C语言推荐大家可以从《C Primer Plus》开始入门,系统地了解C语言的基础语法和简单应用。

对C语言有一定认知之后,就可以通过《C和指针》和《C专家编程》以及《C陷阱与缺陷》等高阶图书学习C语言中最重要的指针等内容了。

几乎所有C语言程序员的都会去看斯蒂芬·普拉塔的《C Primer Plus》。这本畅销38年了图书对于 C 语言初学者来说,就像引路人一样意义非凡。

从1984年至今,《C Primer Plus》已经升级到了第6版,作者初心不变——致力于编写一本指导性强、条理清晰而且有用的C语言教程。所以,书中大量完整的、可运行的程序及详细的注释有助于理解代码和概念。

作者不仅阐述了语法中正确的形式,同时也指出错误的代码出现的问题,更是全面讲述了 C 语言编程的相关概念和知识,并且涵盖了 C 编程语言最近的变动发展、以及 C11 标准。

如果你是学习C的同学,可以选择《C Primer Plus第6版 中文版》入门。

C语言入门

C Primer Plus(第6版)中文版

作者: 【美】Stephen Prata(史蒂芬 普拉达)

译者: 姜佑

几乎所有C语言程序员的都会去看斯蒂芬·普拉塔的《C Primer Plus》。这本畅销38年了图书对于 C 语言初学者来说,就像引路人一样意义非凡。

从1984年至今,《C Primer Plus》已经升级到了第6版,作者初心不变——致力于编写一本指导性强、条理清晰而且有用的C语言教程。所以,书中大量完整的、可运行的程序及详细的注释有助于理解代码和概念。

与市面上其他的教程书籍相比,《C Primer Plus(第 6 版)中文版》最大的特点就是读起来不会有枯涩烦躁之感。

因为斯蒂芬·普拉塔十分在意读者在阅读过程中的阅读体验,所以书中新出现的每一个术语,符号,都给出贴近读者目前知识储备的和理解能力的解释。

而且,这本书在编排上也十分与众不同,在每个知识点后面都会附带一个“程序清单”,也就是程序实例,这是理解编程知识点的绝好方法,供初学者自己手动实操,提升编程水平。

更有趣的是,作者不仅阐述了语法中正确的形式,同时也指出错误的代码出现的问题,更是全面讲述了 C 语言编程的相关概念和知识,并且涵盖了 C 编程语言最近的变动发展、以及 C11 标准。

这就是为什么异步君会把先推荐这本书,对初学者来说,系统学习 C 语言是非常有必要的,这本书就是最适合的。

C Primer Plus(第6版)中文版习题解答

作者: 【美】Stephen Prata(史蒂芬 普拉达)

在过去 40 多年里,C 语言已成为最重要、最流行的编程语言之一,学习 C 语言的人很多,但能运用自如的却远远不到一半。

为了每个程序员都能将所学的知识落实到实际项目,《C Primer Plus(第 6 版)中文版 习题解答》面世了,它是Stephen Prata根据《C Primer Plus(第 6 版)中文版》而撰写的,由北京师范大学名师详细剖析所有题目,全面提升 C 编程能力的优选编程练习册。

针对于提高 C 语言的编程技能、理解计算机原理。看书很重要,但训练更重要,看书和做题应该同时进行的才能快速提升编程水平,从而在实际项目中运用自如。

它在《C Primer Plus(第 6 版)中文版》的每章内容做了简单总结和梳理的基础上,对所有复习题和编程练习做了详细的解答。

人性化的是,书中的每一章节首先提供了思维导图,方便读者快速查询常用的知识点,然后简明扼要地概括和提炼了每章的难点和重点知识,它既可作为学习笔记,也可以作为知识点速查手册。

C语言进阶

C和指针

作者: 【美】Kenneth A.Reek

译者: 徐波

“不会用指针就不会 C 语言”,这是程序员间互相流传的信条,他们认为正是指针使得 C 语言如此之强大,所以想要掌握 C 语言的精髓,首先要精通指针!

那么要如何学好指针呢?推荐大家《C 和指针》这本书,作者是美国Rochester工业学院计算机系教授Kenneth A . Reek,他有着20年的C编程教学经验,他的Pointers on C更是获得ACCU的高度评价。

CSDN论坛大牛曾这样点评这本书:“是在职人员开发必不可少的参考书,经典中的经典“。

除此之外,作者在书中将各种指针用法都写出来了,甚至连一些堪称奇葩的指针用法也没有放过,以简洁准确的文字、配合贴切的图示来进行讲解,让广大读者对指针和数组有了更加深刻的认识,特别是多维数组、指针的指针、指向数组的指针和指针的数组的区这些平日里让人头疼的知识点。

而且,《C 和指针》还提供了与 C 语言编程相关的全面资源,通过对指针的基础知识和高级特性的探讨,覆盖了数据、语句、操作符和表达式、指针、函数、数组、字符串、结构和联合等几乎所有重要的 C 编程话题,并且给出了很多编程技巧和提示,加上每章后面有针对性很强的练习,帮助程序员把指针的强大功能融入到自己的程序中去。

ACCU主席Francis Glassborow曾说:“我竭尽全力地推荐这本我所见过的C编程入门图书。作者深知读者所需,并为他们打下良好基础。如果你已经开始学习C语言但始终不得要领,不妨试一试这本书。”

这本书非常适合 C 语言初学者和初级 C 程序员阅读,作为程序员,启蒙书很重要,但读完启蒙书后,强烈建议将这本书作为你第二本必读书。

C陷阱与缺陷

作者: 【美】Andrew Koenig

译者: 高巍

不管你是普通程序员还是 C 编程高手,在进行 C 编程过程中,都会从词法、语法、语义、链接、库、预处理器、可移植性等层次和方面遇到问题——编程过程中的陷阱和障碍。

那么要如何规避这些陷阱和障碍呢?

建议一定要读Andrew Koenig教授的《C 陷阱与缺陷》, 他是AT&T公司Shannon实验室大规模编程研究部门中的成员,同时也是C++标准委员会的项目编辑,编程经验超过30年,其中有15年在使用C++,他还出版了超过150 篇和C++有关的论文,并且在世界范围内就这个主题进行过多次演讲,是世界级的C编程大师。

《C 陷阱与缺陷》主题是你平时往往不会注意 C 中的各类细节:注释的嵌套性,怎么判断编译器是否允许嵌套注释、运算符优先级,结合顺序,编译器贪婪、assert 的实现方法,避免 if、少敲一个分号导致各种血案、注意函数、if 等的作用域、注意字符集,防止移植性问题、变长参数,stdargs 等等,及一些非常底层,会涉及到大端法、小端法和数据的位模式的问题。

ACCU主席Francis Glassborow曾说:

Andrew Koenig以自己在Bell实验室时发表的论文为基础,结合自己的工作经验扩展成这本对C程序员具有珍贵价值的经典著作。写作本书的出发点不是要批判C语言,而是要帮助C程序员绕过编程过程中的陷阱和障碍。本书所揭示的知识,至少能够帮助你减少C代码和初级C++代码中90%的Bug。”

书中所有内容是作者结合自己的工作经验而撰写的,并给出了若干具有实用价值的建议,本书的主旨就是要帮助 C 程序员绕过编程过程中的各种陷阱和障碍。

本书适合有一定经验的 C 程序员阅读学习,即便你是 C 编程高手,本书也应该成为你的案头必备书籍。

C专家编程

作者: 【美】Perter Van Der Linde

译者: 徐波

最优秀的 C 程序员所使用的编码技巧,你知道几个?

如何深入学习 C 语言知识是每个 C 程序员都遇到的难题,市面上的书籍大多数枯燥乏味,而Peter van der Linden 认为:任何人都可以享受编程,编程应该是一项精妙绝伦、充满生机、富有挑战的活动,而讲述编程的书籍也应时时迸射出激情的火花。

Peter van der Linden是一名技术专家和技术作家。他曾在Sun公司和苹果公司工作多年,并曾任摩托罗拉公司首席Android技术布道师、Immersion公司首席Android开发布道师,自2014年至今在万事达卡公司任高级开发布道师。他还出版了一系列有关C语言、Java语言及Linux操作系统的经典技术图书。

其中《C专家编程》展示了专业的C程序员所使用的编码技巧,并专门开辟了一章对C++的基础知识进行了介绍。书中对C的历史、语言特性、声明、数组、指针、链接、运行时、内存以及如何进一步学习C++等问题从实例出发,进行了细致的讲解和深入的分析,Peter认为这对C程序员具有非常高的实用价值。

同时,它也是一本教学性质的书籍,但它希望重新把快乐融入编程之中,书里所提到的绝大多数教程、提示和技巧都是无法在其他书上找到的,即使有的话,它们通常也是作为心得体会手工记录在手册的书页空白处或旧打印纸的背面。这本书是Peter以及 Sun 公司编译器和操作系统小组的同事们在多年 C 语言编程实践中,积累了大量的知识和经验后,用生动的语言来讲述这些有趣的 C 语言故事和轶闻,诸如连接到因特网上的自动售货机、太空软件中存在的问题,以及一个 C 语言的缺陷怎样使整个 AT&T 长途电话网络瘫痪等。

ACCU主席Francis Glassborow曾说:

即使你读过Andrew Koenig的《C陷阱与缺陷》,你还是应该看看Peter van der Linden的这本书。我想,他们两人的书你都应该千方百计地弄到,如获至宝地捧读。如果我是你的上司,这是必须的要求。”

斯克兰顿大学计算机科学系教授Jack Beidler曾说:

这本书不只是写得清晰,读起来也很有趣。这本书的基调和风格使其备受专业程序员的喜爱,也会使其非常受大学生的喜爱。单单是附录A就已经使这本书必须购买了。书中充满了极好的建议。”

希望《C专家编程》能帮助你精通这门日益流行的从 C 语言演化而来的语言。

C Primer Plus 第6版中文版学习视频

这是以畅销图书《C Primer Plus》第6版中文版为教材的一门C语言基础课程,详细讲解了程序设计的概念及C语言核心知识要点。通过本课程的学习,使学习者掌握程序设计的基本方法,具有一定的的应用计算机解决问题的能力。

C语言知识点总结(最全版)快快收藏

第一部分 \”C 语言基础知识\”知识点

1、C 程序的基本结构 C程序是由函数构成的。每个程序由一个或多个函数组成,其中必须有且仅有一个主函数main( )。 main 函数是一个可执行 C 语言程序的入口和正常出口,而不论其在整个程序中书写的位置如何。 在 C 语言中,大小写字母是有区别的。(例如习惯使用小写字母定义变量,用大写字母定义常量)。 C 程序的注释有两种方法,一种是行注释,使用\”//\”;另外一种是块注释,使用\”/* */\”,注意

\”/*\”与\”*/\”不能嵌套使用。 C 语言书写较为灵活,但是提倡采用缩进格式进行程序书写,以体现语句之间的层次感。 C 程序每条语句以\”分号\”作为结束标志。以下几种情况不得使用分号:

(1) 所定义的函数名称后不得使用分号; (2) if…else…语句是一个整体,中间不能使用分号将其分隔开; (3) 预编译命令后不能使用分号。

2、C 程序开发步骤

C 语言在计算机上的开发过程主要由以下四个步骤组成: 第一步:编辑。生成后缀名为\”.c\”的源文件 第二步:编译。生成后缀名为\”.obj\”的目标文件 第三步:连接。生成后缀名为\”.exe\”的可执行文件 第四步:运行。

3、VC++6.0 开发工具的使用

按下功能键 Ctrl+F7 编译程序;按下功能键 F7 连接程序;按下功能键 Ctrl+F5 运行程序;若程序在编译和连接过程中有语法错误,则按下功能键 F4 定位错误所在行并根据错误提示信息改正错误(原则是先解决 error,再解决 warning)。

4、C 语言中标识符的命名规则

标识符由字母、数字、下划线组成;规定第一个字符必须为字母或下划线。 标识符定义的变量名、函数名、常量名等最好做到\”见名知义\”;大小写代表不同含义;不能使

用关键字;最好不要与 C 语言的库函数同名。

5、C 语言的数据类型

C 语言的数据类型由基本类型和复杂类型构成。其中基本数据类型包括字符型(char)、整型(int,short,long)、实型(float,double);复杂数据类型包括指针类型、数组、结构体、联合体。

char 型占 1 个字节、short 型占 2 个字节、long 型和 float 型占 4 个字节、double 型占 8 个字节。

6、常量

(1) 字符型常量(用单引号括起来的一个字符) 两种形式——普通字符、转义字符(掌握\’\\n\’、\’\\0\’、\’\\t\’、\’\\\\\’、\’\\\’\’、\’\\\”\’、\’\\ddd\’、\’\\xhh\’) 不论普通字符,还是转义字符,都等价于 0-127 之间的某个整数,即 ASCII 码表。

(2) 整型常量 三种表示形式——十进制形式、八进制形式(加前导 0)、十六进制形式(加前导 0x) 注意:C 语言的整型常量没有二进制表示形式。

(3) 实型常量 两种表现形式——小数表示形式、指数表示形式(由\”十进制小数\”+\”e 或 E\”+\”十进制整数\”组成,注意:e 或 E 的两侧必须有数,其后必须为整数)

(4) 字符串常量(用双引号括起来的零个或者若干多个字符) 编译系统会在字符串的最后添加\’\\0\’作为字符串的结束符。比较\’a\’和\”a\”的不同。

(5) 符号常量:例如 #define PI 3.14159

7、变量

变量必须\”先定义、后使用\”。变量代表计算机内存中一定大小的存储空间,具体代表多少字节的存

储空间示变量的类型而定,该存储空间中存放的数据就是变量的值。 注意:变量定义后如果未赋初值,则变量的初值是随机数。因此变量应该先赋值再使用才有意义。为

变量赋值的几种方法:①初始化;②赋值语句;③调用标准输入函数从键盘为变量赋值。 (1) 字符型变量

用\”char\”定义字符型变量,字符型变量存放 1 个字节的数值。对于无符号字符型变量,取值范围是 0~255,对于有符号字符型变量,取值范围是-128~+127。

(2) 整型变量 用\”int\”、\”short\”、\”long\”定义整型变量,其中 int 型和 long 型占用 4 个字节的存储空间,short型占用 2 个字节的存储空间。

(3) 实型变量 用\”float\”、\”double\”定义实型变量,其中 float 型占用 4 个字节的存储空间,double 型占用 8个字节的存储空间。

8、表达式

表达式具有广泛的含义,根据运算符不同,有赋值表达式、算术表达式、逻辑表达式、关系表达式等,甚至单独的一个常量或一个变量也是一个表达式。

9、运算符

(1) 算术运算符(+、-、*、/、%) 除号(/)——当除数和被除数都为整数时,相除的结果自动取整。 求余号(%)——要求\”%\”号的两侧必须是整数,不能是实数。

(2) 赋值运算符( = ) 格式\”变量 = 表达式\”,表示将表达式的值赋值到变量对应的存储空间里。 注意:赋值号\”=\”的左侧必须是变量,不能是常量或者表达式。

(3) 复合赋值运算符(+=、-=、*=、/=、%=) 由算术运算符和赋值运算符组成,是两个运算符功能的组合。例如:a += a + c;

★(4) 自增、自减运算符(++、- -)表达式 当自增、自减运算符单独使用时放在变量前面或者后面没有区别。

例如:++i; 等价于 i++; 等价于 i=i+1; 自增、自减运算符与其它运算符共同存在于表达式中时,放在变量前和变量后有区别。

例如:若定义 int i = 3, j; 则 j = ++i; 语句执行后 i 的值为 4,j 的值为 4。 则 j = i++; 语句执行后 i 的值为 4,j 的值为 3。

(5) 关系运算符(>、<、>=、<=、==、!=) 注意:不能混淆赋值运算符(=)和关系运算符中的等于号(==)。前者是做赋值操作,

后者是判断两个数是否相等。

关系表达式的值只有\”逻辑真(用数值 1 表示)\”和\”逻辑假(用数值 0 表示)\”两种情况。

如果表达式的值为实型,不能使用\”==\”或者\”!=\”判断两个值相等还是不相等。 (6) 逻辑运算符(!、&&、||)

运算逻辑表达式时,当参与运算的数\”非 0 表示真\”、\”0 表示假\”;表达式的解\”1 表示真\”、\”0 表示假\”。

注意:\”短路特性\”的含义。如果逻辑与\”&&\”运算符左侧表达式的值为 0(假),则该运算符右侧的表达式被\”短路\”,即运算过程被计算机省略掉;如果逻辑或\”||\”运算符左侧表达式的值为 1(真),则该运算符右侧的表达式被\”短路\”。

(7) 位运算符(~、^、&、|、<<、>>) 只适用于字符型和整数型变量。是 C 语言具有低级语言能力的体现。 注意:不能混淆逻辑与运算符\”&&\”和按位与运算符\”&\”;逻辑或运算符\”||\”和按位

或运算符\”|\”;逻辑非运算符\”!\”和按位取反运算符\”~\”。 (8) 逗号运算符(,)

功能为从左至右依次计算由逗号隔开的各表达式的值,最后一个表达式的值即为整个逗号

表达式的值。是优先级最低的运算符。 (9) 条件运算符(? :)

这是 C 语言中唯一的一个三目运算符,其形式为:<表达式 1> ? <表达式 2> :<表达式 3> (10) 求字节运算符 sizeof

注意:不能混淆求字节运算符 sizeof 和字符串长度库函数 strlen( )。前者是运算符,后者是函数。sizeof(\”Hello\”)的值为 6,而 strlen(\”Hello\”)的返回值为 5。

(11) 各种运算符混合运算时的优先级排队口决 二、 二、 二、 与、 或、 二、 逗 ! * / % + – > >= < <= == != && || = ,

(12) 数据类型的强制转换 格式:(转换类型名)表达式。 注意:类型名两侧的小括号不能省略,表达式示情况而定可以增加小括号。

第二部分 \”C 程序的三种基本结构\”知识点

1、语句 C 语言的语句分为四类:①简单语句(分为表达式语句、函数调用语句);②空语句;③复合语句(由一对大括号括起来的一条或多条语句,复合语句在语法上视为一条语句);④控制语句(分为结构化语句,

如 if 语句、switch 语句、while 语句、do-while 语句、for 语句;非结构化语句,如 break 语句、continue语句、return 语句、goto 语句)。

2、程序的三种基本结构

顺序结构、选择结构、循环结构

3、顺序结构

(1) printf()函数的使用 难点

一般形式为:printf(\”格式控制字符串\”,输出项列表);

其中\”格式控制字符串\”包含三类字符——普通字符(即原模原样输出的字符,主要用于做

提示信息)、格式说明符(以\”%\”开头)、转义字符(以\”/\”开头) 输出项列表是可以省略的,当\”格式控制字符串\”中没有\”格式说明符\”时,输出项列表省

略;若是有\”格式说明符\”时,输出项列表不能省略,并且有几个格式说明符,输出项列表

就必须有几个对应数据类型的表达式,各表达式之间用逗号隔开。 需要掌握的格式说明符有:%c、%d、%f、%s、%u、%o、%x、%ld、%lf、%e、%%

(2) scanf()函数的使用 难点 一般形式为:scanf(\”格式控制字符串\”,地址列表); 其中\”格式控制字符串\”包含两类字符——普通字符(需从键盘原模原样输入的字符,一般

起分隔和提示作用)、格式说明符(以\”%\”开头) 地址列表通常是不省略的,根据\”格式控制字符串\”中包含多少个格式说明符,地址列表中就有几个地址。对于普通变量,需在变量名前加上取地址符\”&\”,数组名前不需加\”&\”。 注意 1:scanf()函数的\”格式控制字符串\”中不能包含\”转义字符\”,否则将引起输入无效。如 scanf (\”%d\\n\”, &a);是错误的。 注意 2:scanf()的格式控制字符串中的普通字符不是用来显示的, 而是输入时要求照普通字符原模原样输入。 注意 3:scanf()中参数的第二部分一定是地址列表,不能是表达式。 注意 4:字符和数值混合输入且二者中间没有分隔符,需注意何时加空格。例如:已定义

char x; int y; scanf(\”%c%d\”, &x, &y); 此时从键盘输入时,字符和整数之间需加空格; 而 scanf(\”%d%c\”, &y, &x); 此时从键盘输入时,整数和字符之间不能加空格。

(3) getchar()函数的使用 函数原型为:char getchar(void); 例如:char a; a=getchar( ); 该函数使用时关注函数的返回值。

(4) putchar()函数的使用 函数原型为:char putchar(char); 例如:putchar(\’A\’); 该函数使用时关注函数的参数。

(5) printf( )、scanf( )、getchar( )、putchar( )这四个函数都属于标准输入输出库函数,调用时需在程序中包含头文件 stdio.h。

(6) 例如已定义:char a, b=\’A\’; 则以下函数调用等价

4、选择结构

scanf(\”%c\”, &a); 等价于 a = getchar( ); printf(\”%c\”, b); 等价于 putchar(b);

(1) if 语句 if 语句的三种形式——单分支选择结构、双分支选择结构、多分支选择结构。 单分支选择结构: if(表达式)

注意:if 语句的表达式很多时候是关系表达式,不要将\”==\”号误用成\”=\”号。 说明 1:表达式两侧的小括号不能省略,此表达式可以是 C 语言中任意合法的表达式,只

要表达式的值为非零(真),就执行其后的语句体;否则,结束 if 语句。 说明 2:由于\”if(表达式)\”和\”语句体\”是一个整体,在语法上看作一条语句,因此在\”(表

达式)\”后面不能加\”;\”,如果加了分号,则 if 语句的语句体就成了空语句。 说明 3:\”if(表达式)\”会自动结合一条语句,如果语句体有多于一条语句时,必须使用复

合语句,即用大括号将多条语句括起来。

语句体;

易错点

易错点

说明 4:为了表示语句体从属于 if,书写时,应使语句体与关键字 if 的位置有缩进。 双分支选择结构(二选一):

说明 1:表达式只写在关键字 if 的后面,不能写在 else 的后面。 说明 2:\”if\”、\”语句 1\”、\”else\”、\”语句 2\”是一个整体,在语法上看作一条语句,因此在

\”(表达式)\”后面不能加分号,在关键字 else 后面也不能加分号。 说明 3:如果\”语句体 1\”、\”语句体 2\”有多于一条语句,则必须使用复合语句。 说明 4:书写时,应使关键字 if 和 else 对齐,\”语句体 1\”和 if 之间有缩进,\”语句体 2\”

和 else 之间有缩进。 多分支选择结构(多选一):

说明:表达式一定是跟在关键字\”if\”的后面,不能跟在关键字\”else\”的后面。

if(表达式) 语句体 1;

else 语句体 2;

if(表达式 1) 语句体 1; else if(表达式 2) 语句体 2; … else if(表达式 n) 语句体 n; else 语句体 n+1;

(2) switch 语句 switch(表达式) { case 常量表达式 1: 语句 1; <break;> case 常量表达式 2: 语句 2; <break;> ……

case 常量表达式 n: 语句 n; <break;> 说明 1:关键字 switch 后面表达式的值必须是整型或者字符型,不能是实型。 说明 2:关键字 case 后面是\”常量表达式\”,只能是常量或常量表达式,不能是变量或者变量

表达式。且表达式的值必须是整型或者字符型,不能是实型和字符串。书写时注意

\”case\”与\”常量表达式\”之间必须有空格;\”常量表达式\”后面是冒号。 说明 3:每个 case 分支后面的常量表达式必须互不相同。 说明 4:每一个分支后面的\”break\”可以省略,如果省略,则程序继续执行下一个 case 分支

的语句,否则执行完该 case 分支的语句就跳出 switch 语句。 说明 5:多个 case 分支可以共用一组语句,当某个 case 分支后面省略了语句,则意味着该分支

与它后面紧邻的分支共用语句。 说明 6:default 可以省略。 说明 7:书写时必须注意①switch 后面的表达式必须用小括号括起;②表达式的小括号后面不

能加分号;③case 和其后常量表达式之间必须加空格;④常量表达式以及 default 后面必须加冒号。

5、循环结构

循环结构程序编写过程中的三要素——循环的初始条件、循环的终止条件、控制循环结束条件的变化。

<default : 语句 n+1;> }

while(表达式) 循环体;

重点

(1) while 语句

while 语句构成的循环称为当型循环。当表达式的值为非零,则执行循环体,否则结束循环。 说明 1:表达式可以是 C 语言中任意合法的表达式,书写时不能省略其两侧的小括

号。 说明 2:\”while(表达式)\”会自动结合一条语句,如果循环体有多于一条语句时,必须使用复合

语句。 说明 3:\”while(表达式)\”与\”循环体\”是一个整体,\”(表达式)\”后面不应加分号,否则循环

体就成了一条空语句。 (2) do-while 语句 do

循环体;

do-while 语句构成的循环称为直到型循环。先执行循环体,再判断表达式的值是否为非零,是则继续下一次循环,否则结束循环。 说明 1:do 必须和 while 联合使用。 说明 2:如果循环体有多于一条语句时,必须使用复合语句。 说明 3:表达式可以是 C 语言中任何合法的表达式,书写时其两侧的小括号不能省略,\”while(表

达式)\”后面的分号也不能省略。 (3) for 语句

说明 1:小括号里有三个表达式,每个表达式之间用分号隔开。这三个表达式都可以缺省,但是应该在其它相应的位置补齐。

说明 2:\”表达式 1\”也称为初始表达式,在整个循环开始前执行一次;\”表达式 2\”也称终止表达式,每轮循环进入前执行一次,如果该表达式的值为非零,则执行循环体,否则结

束循环;\”表达式 3\”也称循环表达式,每次循环结束时执行一次,常用来控制循环的初始条件逐渐转变到终止条件。

说明 3:\”for(…)\”会自动结合一条语句,当循环体有多于一条语句时,必须使用 复合语句。

(4) break 语句 break 语句出现在循环体中的作用是提前结束本层循环。 break 语句出现在 switch 语句中的作用是跳出本层 switch 语句。

(5) continue 语句 continue 语句只能出现在循环体中,其作用是提前结束本轮循环,进入下一轮循环。即当

continue 语句被执行时,放置在该语句之后的其它语句将被略过。注意:continue 语句并没有使整个循环结束。

6、常用算法、常用库函数

(1) 交换两个变量中存放的数值——使用首尾相接的三条语句。例如:已定义 int a=3, b=4, t; 若要交换 a 和 b 中的数值,使用如下三条语句 t = a; a = b; b = t;

(2) 数学函数(需包含头文件 math.h)——sqrt( )、fabs( )、pow( )、exp( ) (3) 斐波拉契数列 (4) 素数问题 (5) N 项式求和问题 (6) 迭代法

while(表达式);

for(表达式 1; 表达式 2; 表达式 3)循环体;

重点, 难点

难点 重点, 难点

第三部分 \”数组、字符串\”知识点

1、一维数组 (1)一维数组的定义形式:类型说明符 数组名[常量表达式]; 注意:方括号中的\”常量表达式\”表示该数组的元素个数。只能是常量,不能是变量或者变量表达式。 说明 1:数组一旦定义,就在内存空间中分配连续存放的若干存储单元,每一个存储单元的大小由数

据类型决定。例如有如下定义:int a[10]; 则计算机为数组 a 连续分配 10 个存储单元,每个 存储单元占用 4 个字节,总共是 40 个字节的存储空间。

说明 2:数组一旦定义,数组名就代表了一段连续存储空间的首地址,数组名是常量,永远指向该数 组第一个元素的内存单元地址。

(2)一维数组元素的引用:数组名[下标] 与一般变量一样,数组必须先定义,后使用。数组元素的引用是指使用已定义数组中的某个指定元素,

通过\”下标\”来指定需要引用的元素。 注意 1:下标的下限一定是\”0\”,上限由数组定义时的常量表达式值决定,为\”常量表达式值-1\”。

假设已经有如下定义:int a[10]; 则引用该数组元素的下标范围是\”0~9\”,若引用时下标超过此范围,称为数组越界,会导致程序运行出错。

注意 2:必须区分数组定义时方括号中的\”常量表达式\”和数组元素引用时方括号中的\”下标\”,二者具有不同的含义和功能。前者是指明数组的大小,后者是指明要引用数组中的第几个元素。

(3)一维数组的初始化 与一般变量一样,数组定义后,如果没有为其赋初值,则数组元素中的初值是随机数。为数组元素赋

值的方法通常有两种:一种是进行初始化;一种是使用循环结构依次为每个数组元素赋值。 数组初始化的方法分为:①全部元素赋初值;②部分元素赋初值;③全部元素赋初值时可以不指定数

组长度。 (4)一维数组元素的输入、输出 由于数组中的元素是若干个相同类型的数值,不能对其进行整体的输入或者输出,必须针对单个元素

进行输入或者输出,这时就要使用循环结构,对于一维数组来说,使用单层循环。

2、二维数组

(1)二维数组的定义形式:类型说明符 数组名[常量表达式 1][ 常量表达式 2]; 说明 1:\”常量表达式 1\”指明二维数组的行数,\”常量表达式 2\”指明二维数组的列数。 说明 2:二维数组可以看作特殊的一维数组,二维数组元素在内存中是\”按行存放\”。 (2)二维数组元素的引用:数组名[行下标][列下标]

说明:与一维数组一样,二维数组元素引用时的行下标和列下标不能越界。假设已经有如下定义:int a[3][4]; 则引用该数组元素时,行下标的范围是\”0~2\”,列下标的范围是\”0~3\”。

(3)二维数组的初始化 二维数组初始化有以下四种方式:①分行全部元素初始化(使用两层花括号);②分行部分元素初始

化;③按照数值存放顺序不分行初始化(使用一层花括号);④按照数值存放顺序不分行初始化,当对全

部元素赋初值时,可以省略确定行数的常量值。 (4)二维数组元素的输入、输出 使用双层循环嵌套对二维数组的所有元素进行输入、输出。

3、字符数组与字符串

(1)字符数组与字符串的关系 字符数组是字符型数据的集合。定义方式为:char 数组名[常量表达式]; 与其它类型的数组一样,将

数组中的各个字符看作是独立的个体。当这些字符中有\’\\0\’时,可以将它们视为一个整体,即字符串。 字符串有常量,但是没有字符串型的变量,字符串常量使用字符数组进行存放,前提是字符数组的大

小要能容纳整个字符串,包括字符串的结束符\’\\0\’。 (2)字符数组的初始化 当字符数组中存放的所有字符作为独立个体时,其初始化方法与其它类型的数组一样。当字符数组中

存放的是字符串时,其初始化方法有如下几种: ① char a[6] = {\’H\’, \’e\’, \’l\’, \’l\’, \’o\’, \’\\0\’}; ② char a[6] = {\”Hello\”}; ③ char a[6] = \”Hello\”; ④ char a[] = \”Hello\”; (3)向字符数组中存放字符串的方法 定义了字符数组后,如果要向数组中存放字符串,除了以上提到的初始化方法,还有以下方法,注意

不能使用赋值语句的方法。假设已经有定义:char a[50]; 方法 1:scanf(\”%s\”, a); 注意:a 已经代表数组的首地址,前面不再有取地址符&。 方法 2:gets(\”%s\”, a); 方法 3: int i=0;

while((a[i] = getchar()) != \’\\n\’) i++; a[i] = \’\\0\’;

重点 注意:不能用赋值语句的方法向字符数组中存放字符串。以下写法是错误的,原因是数组名是常量, 永远指向数组的首地址,字符串常量书写时,系统给出其在内存中占用的一段无名存储区的首 地址,不允许将数组名这个常量重新赋值指向另一个地址空间。

char a[50]; a = \”Hello\”; (错误) (4)\’\\0\’何时系统自动添加、何时需手动添加 字符串常量的结束标志是\’\\0\’,缺少了\’\\0\’,则不能称为字符串常量。以下列出何时由系统自动添加\’\\0\’,

何时需要编程者自己手动添加\’\\0\’的几种情况。 系统自动添加的情况:(假设已有定义: char a[50];) 调用 scanf 函数从键盘输入字符串时。例如:scanf(\”%s\”, a); 调用 gets 函数从键盘输入字符串时。例如:gets(a); 以字符串常量形式对字符数组进行初始化时。例如:char a[50] = \”Hello\”; 调用 strcpy 函数将字符串拷贝到字符数组中时。例如:strcpy(a, \”Hello\”);

需手动添加\’\\0\’的情况: 以字符形式对字符数组进行初始化时。例如:char a[ ] = {\’H\’, \’e\’, \’l\’, \’l\’, \’o\’, \’\\0\’}; 先定义字符数组,再将单个字符赋值到各个数组元素中时。例如:char a[50];

a[0]=\’H\’; a[1]=\’e\’; a[2]=\’l\’; a[3]=\’l\’; a[4]=\’l\’; a[5]=\’\\0\’; 对字符数组中原来存放的字符串进行处理,破坏了原字符串的\’\\0\’,对新处理后的字符串需手动添加\’\\0\’

(5)字符串输入、输出 第一种方法:调用 scanf、printf 函数实现,格式说明符使用\”%s\”。例如:

char a[50]; scanf(\”%s\”, a); //当遇到空格或者回车时系统认为字符串输入结束 printf(\”%s\”, a); //字符串输出

第二种方法:调用 gets、puts 函数实现。例如: char a[50]; gets(a); //当遇到回车时系统认为字符串输入结束

puts(a); 说明:scanf 和 gets 输入字符串时的区别是——scanf 不接收空格,该函数认为空格是字符串输入结束

标志。而 gets 接收空格作为字符串中的有效字符,该函数只认为回车是字符串输入结束标志。 (6)字符串处理函数 求字符串长度函数:strlen(s)

例如:char s[50]; int len; len = strlen(s); 说明 1:使用 strlen 求字符串长度时,计算的是第一个\’\\0\’之前的有效字符个数,函数返回值不包

括\’\\0\’占用的字节数。 说明 2:注意区分 strlen 和 sizeof。首先,strlen 是库函数,而 sizeof 是运算符;其次,strlen 计

算的是字符串有效字符占用的字节数,不包括\’\\0\’占用的空间,而 sizeof 计算的是字符 数组或者字符串占用内存的字节数,包括\’\\0\’占用的空间。例如:

char s[20]=\”Hello\”; int x, y, m, n; x = strlen(s); y = sizeof(s); m = strlen(\”Hello\”); n = sizeof(\”Hello\”); 以上举例中,变量 x 和 m 的值都是 5,因为 strlen 函数仅仅统计字符串中有效字符的占 用的字节数。变量 y 的值是 20,因为 sizeof(s)计算的是数组 a 在内存中占用的字节数。 变量 n 的值是 6,因为 sizeof(\”Hello\”)计算的是字符串\”Hello\”在内存中占用的字节数, 包括\’\\0\’占用的空间。

字符串连接函数:strcat(s1, s2) 例如:char s1[50] = \”Hello\”, s2[50] = \” every one\”;

strcat(s1, s2); //表示把字符串\” every one\”粘贴到字符串\”Hello\”的后面 strcpy(s1, \”every one\”);

字符串比较函数:strcmp(s1, s2) 说明:该函数是从左至右依次将两个字符串的对应字符取出做比较,比的是对应字符 ASCII 码

值的大小。当字符串 s1 大于字符串 s2 时,函数返回 1;当字符串 s1 等于 s2 时,函数返 回 0;当字符串 s1 小于 s2 时,函数返回-1。

字符串拷贝函数:strcpy(s1, s2) 说明:该函数将 s2 指向的字符串拷贝到 s1 指向的存储空间里,要求 s1 指向的存储空间必须足够

大,能够容纳即将拷贝的字符串。 例如: char s1[50], s2[50] = \”Hello\”;

strcpy(s1, s2); //表示把字符数组 s2 中存放的字符串拷贝到字符数组 s1 中 strcpy(a, \”China\”); //表示把字符串\”China\”拷贝到字符数组 a 中

4、常用算法

(1)冒泡法排序 (2)选择法排序

重点

重点

第四部分 \”函数\”知识点

1、库函数与自定义函数

(1) 库函数:目前已学习过的库函数有标准输入输出类库函数、数学类库函数,当程序中调用库函数时,必须包含对应的头文件。例如标准输入输出类库函数对应的头文件是<stdio.h>,数学类库

函数对应的头文件是<math.h>。 (2) 用户自定义函数:用户自己编写的完成特定功能的函数,也称子函数。 (3) 一个 C 程序由一个 main 函数和若干多个子函数组成。

2、函数定义、函数调用、函数声明的概念

(1) 函数定义——即定义函数的功能。未经定义的函数不能使用。 (2) 函数调用——即执行一个函数,调用函数时,程序跳转到被调用函数的第一句开始执行,执行

至被调用函数的最后一句,然后程序返回调用该函数处。 (3) 函数说明——即通知编译系统该函数已经定义过了。

3、函数定义的格式

<函数类型> 函数名 (<参数表>) {

重点 函数首部

<函数体语句> } 函数由函数首部和函数体构成,其中函数首部由函数类型、函数名、参数表组成。 关于函数类型的说明 说明 1:函数类型分为\”空类型(关键字是 void)\”和\”非空类型(需指定具体的返回类型,如 int、

float、double、char、指针类型、结构体类型等)\”。 说明 2:当缺省\”函数类型\”时,默认函数返回类型为 int 型。 说明 3:当函数类型是\”非空类型\”时,函数体内必须有 return 语句,写成\”return(表达式);\”,

表达式值的类型必须与函数类型一致,否则编译系统会给出警告提示。 说明 4:当函数类型是\”void\”时,函数体内不需要 return 语句,或者直接写\”return ;\”即可。 说明 5:函数类型是 C 语言中的关键字,在 VC++6.0 编译环境中是蓝色字体。 关于函数名的说明 说明 1:函数名命名必须符合 C 语言标识符的命名规则。命名函数名最好是见名知意。 说明 2:同一段程序中的各自定义函数不允许函数名同名。 关于参数表的说明

说明 1:此时参数表中的参数称为形式参数,简称\”形参\”。形参必须用一对小括号括起来。 说明 2:如果参数表中没有参数,称为无参函数,此时小括号中可以写关键字 void,或者什么都

不写。 说明 3:如果参数表中有参数,称为有参函数,此时小括号中必须明确申明各个参数的数据类型。

注意:每个参数都必须有各自的类型说明符,如 int fun(int a, int b, char c) 关于函数体的说明

说明 1:函数体必须用一对大括号括起来,函数体前面是说明部分,后面是执行语句部分。 说明 2:函数首部与函数体是一个整体,不能被分离开。例如,在括起参数表的小括号与括起函数

体的大括号之间加上分号是错误的。

4、函数调用

一个已经定义的函数,只有在发生函数调用时才能被执行。函数调用的过程即是程序跳转到被调用函

数的第一句开始执行,执行至被调用函数的最后一句,然后程序返回函数调用语句处。 函数调用的一般形式: (1)有参数函数的调用形式: 函数名(参数) (2)无参数函数的调用形式: 函数名( )

函数的传值调用 函数调用时的参数称为实际参数,简称\”实参\”。当发生函数调用时,实参将数值传递给形参,

实现函数调用时的数值传递。 为保证函数调用时正确的数值传递,\”实参\”与\”形参\”应有严格的对应关系,可以归纳为\”3

个一致和 1 个不一致\”——规定:实参的个数、类型、顺序必须与被调用函数形参的个数、类型、顺序保持一致。而实参与形参的参数名称可以不相同。 C 语言中函数调用的三种方式

(1)作为独立的语句。例如:printf(\”Hello world!\”); (2)作为表达式中的一部分。例如:y = sqrt(9); (3)作为其它函数的实参。例如:printf(\”y = %lf\\n\”, sqrt(9));

5、函数声明

编辑 C 程序时,如果函数定义写在函数调用之后,则需要进行函数声明,否则可以省略函数声明。函数声明的一般形式为:

类型名 函数名(类型 1,类型 2,… ,类型 n); 说明:函数声明、函数定义、函数调用三者必须有严格的对应关系,三者的函数类型需一致,函数名

需相同,参数的个数、类型、顺序需一致。

6、函数的嵌套调用

C语言中不允许作嵌套的函数定义。因此各函数之

间是平行的,不存在上一级函数和下一级函数的问题。 但是C语言允许在一个函数的定义中出现对另一个函

数的调用。这样就出现了函数的嵌套调用。即在被调函

数中又调用其它函数。 其关系如图所示:在执行 main 函数的过程中调用

f1 函数,于是转去执行 f1 函数,在执行 f1 函数过程中又调用 f2 函数,于是转去执行 f2 函数,f2 函数执行完毕后返回 f1 函数的断点继续执行,f1 函数执行完毕后返回 main 函数的断点继续执行。

7、变量的作用域和存储类别(教材 12.1~12.3 节)

变量的作用域是指从空间上对变量的作用范围进行分类,分为全局变量和局部变量。其中全局变量的

作用范围宽,局部变量的作用范围窄。 变量的存储类别是指从时间上对变量的存在时间长短进行分类,分为动态变量、静态变量。其中动态

变量的存在时间短,静态变量的存在时间长。

(1)变量的作用域 变量的作用域是指变量的作用范围,分为全局变量和局部变量,局部变量又分为函数体的局部变量以

及复合语句的局部变量。

全局变量 函数体内的局部变量 复合语句内的局部变量 定义位置 定义在函数体外面 定义在函数体内部 定义在复合语句内部

作用域 从定义位置开始到整个.c 文件结束有效

本函数体内有效 本复合语句内有效

注意事项 (1)同一个.c 文件内的全局变量不能重名

(1)必须写在执行语句之前(2)同一函数体内的局部变

(1)必须写在执行语句之前(2)同一个复合语句内的局

重点

(2)全局变量允许与局部变量重名,重名时,局部变量

屏蔽全局变量

量不能重名 (3)当与全局变量重名时,局部变量屏蔽全局变量

部变量不能重名 (3)与前两种变量相比,这是作用范围最小的一种变量

说明 1:从此表格可以看出,作用范围最宽的是全局变量,其次为函数体内的局部变量,范围最窄的是复合语句内的局部变量。

说明 2:当全局变量、局部变量有重名时,范围较窄的变量会自动屏蔽范围较宽的变量。 说明 3:定义在函数体内的变量以及形参都属于局部变量。 (2)变量的存储类别 变量的存储类别分为 auto(动态型)、static(静态型)、register(寄存器型)、extern(外部型)。 动态变量—— 只在某一个时间段内存在。例如函数的形参、函数体内的局部动态变量,这类变

量在发生函数调用时,系统临时为它们分配存储空间,但是随着函数调用结束, 这些变量的存储空间被释放掉,变量的值也随之消失。 动态变量分为全局动态变量、局部动态变量。

静态变量—— 生存期为程序的整个执行过程,直到程序运行结束。这类变量一旦定义,系统就 为之分配存储空间,静态变量在整个程序运行过程中固定的占用这些存储空间, 因此也称永久存储。

静态变量分为全局静态变量、局部静态变量。 注意:静态变量定义后如果没有赋初值,则初值为零。这一点与动态变量不同, 动态变量定义后如果没有赋初值,则初值是随机数。

寄存器变量—— 可以将使用频率较高的变量定义为 register 型,以提高程序的运行速度。寄存 器变量属动态变量,存储空间到特定时候就自动释放。 注意:寄存器变量只限整型、字符型、指针型。

外部变量—— 如果在某个源文件(例如 a.c)中定义了一个全局动态变量 int x,在另外一个源

auto

static

register

extern

重点

重点

文件(例如 b.c)中需要引用这个全局变量 x,则在\”b.c\”中对变量 x 进行如下说 明\”extern int a;\”后,即可引用\”a.c\”中定义的变量 x。 注意:全局变量的定义只能有一次,但是使用 extern 对其进行说明可以有多次。 这一点与函数类似,函数定义也是只能有一次,而函数说明可以有多次。

8、函数的存储分类(教材 12.4 节)

(1)用 static 说明函数 一个函数定义后,除了被所在的源文件调用,不允许被其它的源文件调用,则在函数首部的返回值

类型前面加上 static 关键字即可达到以上目的。这样做的好处是避免不同的.c 文件定义了同名的函数而引起混乱。

(2)用 extern 说明函数 一个函数定义后,如果除了被所在的源文件调用,还能被其它源文件调用,则其它源文件在调用该函

数前,需先使用 extern 关键字进行说明,之后便可调用。

9、编译预处理(教材 13.1 节)

在 C 语言中,凡是以\”#\”开头的行都称为编译预处理命令行,要求掌握\”#define\”和\”#include\”。注意:每行的末尾不能加\”;\”号。

(1) 宏替换 —— #define 不带参数的宏定义

#define 宏名 替换文本 使用说明:替换文本中可以包含已经定义过的宏名 书写说明:当宏定义分多行书写时,在行末加一个反斜线\”\\\”;宏名习惯用大写字母;宏定义一般写在程序的开头。 带参数的宏定义

#define 宏名(参数表) 替换文本 使用说明 1:参数表中只有参数名称,没有类型说明。 使用说明 2:如果替换文本中有括号,则进行宏替换时必须有括号;反之,如果替换

文件中本身没有括号,则宏替换时不能随便加括号。 书写说明:宏名和小括号必须紧挨着;小括号不能省略;

重点

(2)文件包含 —— #include 所谓文件包含是指在一个文件中去包含另一个文件的全部内容,#include 命令行的形式如下: #include \”文件名\” 或者 #include <文件名> 如果文件名用双引号括起来,是指系统先在源程序所在的目录查找指定的包含文件,如果找不到,再

按照系统指定的标准方式到有关目录中去找。 如果文件名用尖括号括起来,系统将直接按照系统指定的标准方式到有关目录中去寻找。

第五部分 \”指针\”知识点

1、指针的基本概念(教材 8.1 节) (1)计算机的内存空间是由许多存储单元构成的,每个存储单元代表一个字节的容量,每个存储单

元都有一个唯一的编号,即地址。程序运行过程中使用变量等就存放在这些存储单元中。对变量的取值有

两种方法,一种是使用变量名对其内容进行存取,称为\”直接法\”,另一种是借助变量的地址对其内容进

行存取,称为\”间接法\”。 (2)指针──即地址。一个变量的地址称为该变量的指针,通过变量的指针能够找到该变量。 指针变量──专门用于存储其它变量地址的变量。指针与指针变量的区别,就是变量值与变量名的区

别。注意:指针变量存放的是地址值,而不是通常意义上的数值。

2、指针变量的定义、赋值(教材 8.2 节)

(1)指针变量的定义: 类型标识符 *指针变量名; 说明 1:此处的类型标识符称为指针变量的\”基类型\”,即表示该指针变量应存放何种类型的变量地

址,指针变量的基类型必须与其指向的普通变量同类型,否则会引起程序运行错误。 说明 2:与普通变量的定义相比,除变量名前多了一个星号\”*\”外,其余一样。注意:此时的星号

仅仅是一个标识符,标识其后的变量是指针变量,而非普通变量。 说明 3:例如有定义\”int *p;\”表示定义了一个 int 类型的指针变量 p,此时该指针变量并未指向某个

具体的变量(称指针是悬空的)。使用悬空指针很容易破坏系统,导致系统瘫痪。 重点

重点及难点

说明 4:不论是什么类型的指针变量,在 VC++6.0 编译环境中已定义的指针变量都占用 4 个字节的存储空间,用来存放地址。这点与普通变量不一样,普通变量根据不同的数据类型,它所占用

的存储空间字节数是有差别的。 (2)指针变量的赋值 与普通变量相同,指针变量可以在定义时为其赋值,称为初始化;也可以先定义,再使用赋值语句为

其赋值,赋值方式为:指针变量名=某一地址; 通常有以下几种方法为指针变量赋值:

方法一:指针变量名 = &普通变量名 方法二:指针变量名 = 另外一个同类型并已赋值的指针变量 方法三:第三种是调用库函数 malloc 或者 calloc,当指针使用完毕后再调用 free 将其释放。例如: int *p; //以下两种写法均能实现为指针变量 p 动态分配 40 个字节存储空间的功能 p = (int *)malloc(10 * sizeof(int)); 等价于 p = (int *)calloc(10, sizeof(int));

3、指针运算(教材 8.4.2、8.4.3 节)

(1)指针运算中两个重要的运算符 * (取内容符): 取出其后内存单元中的内容。 &(取地址符): 取出其后变量的内存单元地址。 说明:此处的取内容符也是星号,外形上与指针变量定义时的标识符一样,但是二者的含义完

全不相同,前者是运算符,后者只是一个标识符。 (2)移动指针

重点

重点

移动指针就是对指针变量加上或减去一个整数,或通过赋值运算,使指针变量指向相邻的存储单元。

只有当指针指向一串连续的存储单元(例如数组、字符串)时,指针的移动才有意义。 指针移动通过算术运算(加、减)来实现,指针移动的字节数与指针的基础类型密不可分。例如已定

义:char *p1; int *p2;进行如下运算\”p1++; p2++;\”后,指针 p1 中存放的地址值自增一个单元,指针 p2 中存放的地址值自增 4 个单元。

(3)比较运算 比较运算是比两个指针变量中存放的地址值的大小关系。 (4)指针的混合运算 例如有定义:int a, *p; 则以下一些举例的混合运算需要仔细推敲其含义。

难点

①\”&*p\”的含意是什么?②\”*&a\”的含义是什么?③\”(*p)++\”的含义是什么?④\”*p++\”的含义是什么?⑤\”*++p\”的含义是什么?⑥ \”++*p\”的含义是什么?

4、函数之间地址值的传递(教材 8.5 节)

(1)实参向形参传送地址值 如果函数的形参为指针变量,对应的实参必须是基类型相同的地址值或者是已指向某个存储单元的指

针变量。 教材 7.5 节的内容是\”函数之间数值的传递\”,这种方式下完成的是实参向形参的数值单向传递,即

当发生函数调用时,实参将其数值传递给形参,函数调用完毕后,形参的改变并不能影响对应实参的值,

因此把这种数值传递称为是\”单向\”的。 而本节的内容是\”函数之间地址值的传递\”,其特点是实参为主调用函数中某内存单元的地址,在被

调用函数中可以通过形参对主调函数中该内存单元的值进行修改,这也就使得通过形参改变对应的实参值

有了可能,因此通过地址值的传递方式,主调函数与被调函数之间数据传递可以实现\”双向\”的传递。 \”传地址\”方式的体现的另外一个优越之处在于:可以将多个数据从被调函数返回到主调函数中。这

一点也是\”传值\”方式做不到的,传值方式中被调函数只能利用 return 语句向主调函数返回一个数据。 同学需仔细区分函数之间\”传值\”与\”传地址\”这两种方式各自的特点,做题时注意分析何时为传值

方式,何时为传地址方式。 (2)通过 return 语句返回地址值 当函数返回值的类型是指针类型,而非普通数据类型时,表明被调函数调用完毕后向主调函数返回的

是一个地址值,而不是一个普通的数值。此时应注意 return 语句的表达式值应是指针类型(地址值)。

重点

重点

5、一维数组和指针(教材 9.2 节)

(1)数组名是一个地址常量 (2)使用指针对数组元素进行访问是基于数组元素顺序存放的特性。

方式一:利用数组的首地址(数组名)访问数组元素。注意:由于数组名是常量,因此对数 组名不能使用自增运算,必须借助一个变量 i 来实现对数组元素的顺序访问。

例如: int a[10], i = 0; while(i < 10) scanf(\”%d\”, &a[i++]); 或者 while(i < 10) scanf(\”%d\”, a+ i++); 方式二:利用指针变量访问数组元素。 例如: int a[10], i = 0, *p = a; while(i < 10) scanf(\”%d\”, p++);

(3)引用一维数组元素的二种等价方法——下标法、指针法 假设有如下定义:int a[3], *p = a; 从上表可总结出,下标法取数组元素数值的表达式为\”a[i]\”或\”p[i]\”,指针法取数组元素数值

的方法为\”*(a+i)\”或\”*(p+i)\”。下标法取数组元素地址的表达式为\”&a[i]\”或\”&p[i]\”,指针法取数组元素地址的方法为\”a+i\”或\”p+i\”。

(4)假设有以下定义:int a[10], *p = a; 则 p 和 a 的相同点是:都是指针,存放数组的首地址。 不同点是:a 是地址常量,p 是指针变量。a 永远指向该数组的首地址,直到该数组

的存储空间被系统收回;p 是变量,可以重新赋值指向其它的存储空间。

6、一维数组与函数参数(教材 9.3 节)

(1)数组元素作为函数实参 由于数组元素相当于一个个独立的普通变量,当数组元素作为函数实参时,实现的是\”传值\”方式,即单向传递。在被调函数中只能使用数组元素的数值,不能改变数组元素的初值。 (2)数组元素的地址作为函数实参

当某数组元素的地址作为函数实参时,实现的是\”传地址\”方式,能够达到双向数据传递的功能。即在被调用函数中,不但可以利用形参使用该数组元素的初值,还可以达到修改该数组元素初值

的目的。 (3)数组名作为函数实参

当数组名作为函数实参时,由于数组名本身就是一个地址值,因此实现的是\”传地址\”方式,能够达到双向数据传递的功能,对应的形参必须是一个与数组类型一样的指针变量。在被调用函数中,

可以通过形参(指针变量)使用数组中的所有元素,还能够修改这些元素的初值。 说明 1:数组名作为函数实参时,对应的形参有如下几种写法,都代表一个与数组类型一致的指

针变量。 void fun(int a[10]) 或者 void fun(int a[ ]) 或者 void fun(int *a) { … } { … } { … }

说明 2:数组名作为实参时,对应的形参是一个与数组同类型的指针变量,发生函数调用时,系 统只是为该指针变量(形参)分配 4 个字节的存储空间,并不是分配等同于整个数组需要 占用的存储容量。 例如:

a[0] a[1] a[2] 下标法

p[0] p[1] p[2] *a *(a+1) *(a+2)

取数

组元

素的

数值 指针法

*p *(p+1) *(p+2)

&a[0] &a[1] &a[2]

下标法 &p[0] &p[1] &p[2]

a a+1 a+2

取数

组元

素的

地址指针法

p p+1 p+2

重点

重点

void main(void) void fun(int a[10]){ { int a[10]; … … printf(\”%d\”, sizeof(a)); printf(\”%d\”, sizeof(a)); …

fun(a); } …

注:fun 函数中的打印结果是\”4\”,因为形参是一个指针变量,不论何种类型的指针变量,系统都为它分配 4 个字节的存储空间。

}

注:主函数中的打印结果是\”40\”,因为 a 数组定义后,系统为它分配 40 个字节的存储空间。

7、二维数组和指针(教材 9.6 节) 难点

(1)二维数组\”基类型\”的理解 假设有定义:int a[3][4], *p;

与一维数组一样,二维数组名也是一个地址常量。 二维数组可以看作由多个一维数组组成,由以上定义可知,二维数组 a 由三个一维数组组成,每

一个一维数组中有四个元素,a[0]、a[1]、a[2]分别是这三个一维数组的数组名,它们各自代表了这三个一维数组的首地址,同样也是不可改变的常量地址。

基于以上分析,可以这样理解:①二维数组名 a 的基类型是 4 个 int 型;②一维数组名 a[0]、a[1]、a[2]的基类型是 1 个 int 型(即数组元素的类型)。 假设有定义:int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12};以下示意图表示了二维数组名、一维数组名、二维数组中各元素之间的对应关系。

以上示意图的右侧是二维数组的 12 个元素,每个元素占用一个 int 型的存储空间(4 个字节),

假设第一行第一个元素 a[0][0]的地址为 0x1000,分析可知第二行第一个元素 a[1][0]的地址为 0x1010,第三行第一个元素 a[2][0]的地址为 0x1020,这三行元素的首地址分别由 a[0]、a[1]、a[2]来存放。示意图的中部就是 a[0]、a[1]、a[2]构成的一个一维数组,这三个元素是一级指针,存放的是地址值(分别是 0x1000、0x1010、0x1020)。示意图的左侧是二维数组名 a,它是一个二级指针,存放由 a[0]、a[1]、a[2]三个元素构成的一维数组的首地址(假设是 0x1030)。

通过以上分析可知,\”a[i]\”是一级指针,基类型为 1 个 int 型。\”a\”是二级指针,基类型是 4 个int 型。例如:\”a[0]\”指向元素 a[0][0],则\”a[0]+1\”表示地址向后移动,指向元素 a[0][1],即一级指针加 1 表示地址向后移动 1 个 int 型。\”a\”指向元素 a[0],则\”a+1\”表示地址向后移动,指向元素a[1],即二级指针加 1 表示地址向后移动 4 个 int 型。

(2)二维数组每行元素的首地址 a(或者 a[0])代表二维数组中第一行元素的首地址;a+1(或者 a[1])代表第二行元素的首地址;

a+2(或者 a[2])代表第三行元素的首地址。

1030 a

1000

1010

1020

a[0]

a[1]

a[2]

该行首地址为 1000 1 2 3 4

5 6 7 8

9 10 11 12

a[0][0] a[0][1] a[0][2] a[0][3]

a[2][0] a[2][1] a[2][2] a[2][3]

该行首地址为 1010

该行首地址为 1020

该一维数组首地址为 1030

二维数组名 a (二级指针)

一维数组名 a[i](一级指针)

二维数组元素 a[i][j] (内容)

(3)二维数组每个元素的地址 二维数组中第 i 行第 j 列的某个元素 a[i][j]的地址可以由以下几种表达式求得: ①&a[i][j] ②a[i]+j ③*(a+i)+j ④&(*(a+i)[j]) ⑤a[0]+4*i+j ⑥&a[0][0]+4*i+j

(4)通过地址引用二维数组的元素 引用二维数组第 i 行第 j 列的元素的几种表达式如下所示: ①a[i][j] ②*(a[i]+j) ③*(*(a+i)+j) ④*(a+i)[j] ⑤*(a[0]+4*i+j) ⑥*(&a[0][0]+4*i+j)

(5)通过建立一个指针数组引用二维数组元素 假设有定义:int *p[3]; 则将 p 称为指针数组。 由于\”[ ]\”的优先级高于\”*\”的优先级,因此 p 首先与\”[ ]\”结合,构成 p[3],说明是一个数 组,\”p[3]\”再与\”int *\”结合,表示该数组中每个元素的数据类型是\”整型指针\”类型,于是我们将 \”int *p[3]\”称为指针数组——即它首先是一个数组,数组中的每个元素是指针类型。 下面我们来分析\”指针数组\”与\”二维数组\”的对应关系,假设有定义:int *p[3], a[3][2]; (注 意以上定义中,必须保证指针数组的元素个数与二维数组的行号常量一致,即 p[3]中的\”3\”与 a[3][2] 中的\”3\”要保持一致)。则以下写法表示将 p 数组中的每个元素(指针变量)指向 a 数组中的每一 行。(参看教材 P128 图 9.6) 第一种方法:p = a; 第二种方法:for(i = 0; i < 3; i++) p[i] = a[i]; 这时,可以通过指针数组 p 来引用二维数组 a 中的元素。

① p[i][j] 等价 a[i][j] ② *(p[i]+j) 等价 *(a[i]+j) ③ *(*(p+i)+j) 等价 *(*(a+i)+j) ④ *(p+i)[j] 等价 *(a+i)[j]

(6)通过建立一个行指针引用二维数组元素 假设有定义:int (*q)[2]; 则将 q 称为行指针。同学需仔细区分行指针与指针数组的区别。 由于定义时加了小括号,因此 q 首先与\”*\”结合,说明 q 是一个指针变量,然后再与\”[3]\”结 合,说明指针变量 q 的基类型是一个包含两个整型元素的数组。 下面我们来分析\”行\”与\”二维数组\”的对应关系,假设有定义:int (*q)[2], a[3][2]; (注意以 上定义中,必须保证行指针的元素个数与二维数组的列号常量一致,即(*q)[2]中的\”2\”与 a[3][2] 中的\”2\”要保持一致)。则指针变量 q 的基类型与 a 的基类型相同,q = a; 是合法的赋值语句,表示 指针 q 指向了二维数组 a 的首地址,这时可以通过行指针 q 来引用二维数组 a 中的元素。

① q[i][j] 等价 a[i][j] ② *(q[i]+j) 等价 *(a[i]+j) ③ *(*(q+i)+j) 等价 *(*(a+i)+j) ④ *(*(q+i)[j]) 等价 *(*(a+i)[j])

(7)二维数组、指针数组、行指针之间的对应关系 假设有定义:int a[3][2], *p1[3], (*p2)[2]; 则 a 是二维数组名、p1 是指针数组名,p2 是行指针名,由于二维数组的行数与指针数组的维数相同,二维数组的列数与行指针的维数相同,因此它们三

者可以产生对应关系。以下语句合法 p1 = a; p2 = a; 可以将 a、p1、p2 都视为二级指针。

难点 8、二维数组名和指针数组名作为函数实参(教材 9.7 节)

(1)二维数组名作为函数实参 首先回忆一维数组名作为函数实参的时候,对应的形参是与数组元素同类型的指针变量,形参有如下几种写法:

main() { int a[3]; … fun(a); //一维数组名作为函数实参 … }

则 fun 函数首部可以有如下几种写法:(1)void fun(int

p[3])

p[ ]) *p)

(2)void fun(int (3)void fun(int

当二维数组名作为函数实参时,对应的形参必须是一个行指针变量,形参的写法有以下几种形式:

main() 则 fun 函数首部可以有如下几种写法: { int a[2][3]; (1)void fun(int p[2][3])

(2)void fun(int p[ ][3])

… fun(a); //一维数组名作为函数实参

… (3)void fun(int (*p)[3]) } 注意以上写法,列下标不可缺省。无论是哪种方式,系统都把 p 处理成一个行指针。

(2)指针数组名作为函数实参 当指针数组作为函数实参时,对应的形参应当是一个指向指针的指针。形参的写法有以下几种形式:

main() 则 fun 函数首部可以有如下几种写法:{

(1)void fun(int *p[3]) (2)void fun(int *p[ ])

int a[2][3], *p[3] = a; … fun( p ); //指针数组名作为函数实参 … }

与一维数组名作实参时形参的写法相似(一维数组名作实参时对应的形参有三种写法),当指针数组

作为函数实参时,传送的仍然是一个一维数组名,对应的形参也有三种写法,只不过形参的类型是指针类

型而已。

9、字符串与指针(教材 10.2 节)

(3)void fun(int **p)

重点

(1)使指针指向一个字符串 由于字符串中的每一个字符在内存空间里是顺序存放的,因此使用指针操作字符串是比较便利的。以

下是几种将字符型指针变量指向字符串的正确方法: 方法一:在定义字符型指针变量时为其赋初值一个字符串(初始化)。例如: char *p = \”Hello\”; 方法二:先定义字符型指针变量,然后通过赋值语句让指针变量指向字符串。例如: char *p; p = \”Hello\”; 示例中的字符串常量\”Hello\”在程序中给出的是它在内存空间的首地址,因此可以通过赋值

语句将这段无名存储区的首地址赋值给指针变量,使得指针指向该字符串。 方法三:先定义字符型指针变量,然后将指针变量赋一个有效的地址值(可以将指针赋值为一个字符

数组的首地址,或者调用 malloc 函数为指针变量动态分配一段存储空间),最后调用 strcpy 函数将字符串复制到指针所指向的这段存储空间里。例如:

char *p; p = (char *)malloc(6 * sizeof(char));

strcpy(p, \”Hello\”);

char a[6], *p; p = a; strcpy(p, \”Hello\”);

或者

注意:在调用 strcpy 函数之前,指针 p 必须已经指向一个有效的存储空间,然后才能向这个

存储空间里存放字符串常量。如果指针只是定义,没有为其赋有效的地址值,这样的 指针是不能拿来用的。

(2)一些容易范错误的用法 错误一:使用赋值语句企图为字符数组赋一个字符串。例如: char a[6]; a = \”Hello\”; (错误原因是数组名是常量,不能指向另外的存储空间) 错误二:指针变量定义后就调用 strcpy 函数企图将一个字符串复制到指针所指的存储空间里。例如: char *p; strcpy(p, \”Hello\”);

(错误原因是指针 p 中此时存放的是一个随机的地址值,即它还未指向一段有效的存储空 间,向一个随机的存储空间里赋值字符串常量是毫无意义的。)

(3)\”字符数组存放字符串\”与\”指向字符串的指针\”的比较 对于字符串的操作,既可以使用字符数组,还可以使用字符型指针变量,二者使用上有一些异同: 相同点:都可以利用初始化的方法为其赋一个字符串常量。例如: char a[6] = \”Hello\”; (正确) char *p = \”Hello\”; (正确) 不同点 1:字符数组不能使用赋值语句为其赋字符串常量;而字符型指针变量可以通过赋值语句使之

指向字符串常量;例如: char a[6]; a = \”Hello\”; (错误) char *p; p = \”Hello\”; (正确) 不同点 2:字符数组定义之后可以调用 strcpy 函数为其赋字符串常量;而字符型指针变量定义之后不

能立即调用 strcpy 函数为其赋字符串常量。例如: char a[6]; strcpy(a, \”Hello\”); (正确) char *p; strcpy(p, \”Hello\”); (错误) 不同点 3:字符数组装载字符串后,系统为数组开辟的是一段连续的存储空间(大于或等于字符串长

度),数组名代表了这段存储空间的首地址。字符型指针变量指向字符串后,系统为字符型 指针变量开辟的仅仅是 4 个字节,用来存放字符串无名存储区的首地址。例如:÷ char a[ ] = \”Hello\”; (系统为数组开辟了 6 个字节的存储空间用来存放字符串) char *p = \”Hello\”; (系统为指针变量 p 开辟了 4 个字节用来存放字符串常量的首地址) 因此 sizeof(a) 的运算结果是 6;而 sizef(p) 的运算结果是 4。

(4)字符串数组 难点

多个字符串放在一起就构成了字符串数组。可以使用一个二维数组(字符型的)来构造字符串数组,

也可以定义一个指针数组(字符型的)来构造一个类似的字符串数组。以下分别叙述: 方法一:使用二维数组来构造字符串数组。例如: char name[ ][10] = {\”China\”, \”America\”, \”English\”, \”France\”}; 定义二维数组时,可以缺省第一维的长度,该例中,系统为二维数组 name 总共开辟了 40

个字节的存储空间,用来存放四个字符串,虽然有一些单元被浪费,示意图如下所示:

name name[0]

name[1]

name[2]

name[3]

C h i n a \\0

A m e r i c a \\0

E n g l i s h \\0

F r a n c e \\0

方法二:定义一个指针数组来构造字符串数组。例如: char *pname[4] = {\”China\”, \”America\”, \”English\”, \”France\”};

pname pname[0]

pname[1]

pname[2]

pname[3]

C h i n a \\0

A m e r i c a \\0

E n g l i s h \\0

F r a n c e \\0

由以上示意图可以看出,指针数组 pname 中有四个元素,都是字符型的指针变量,每个指针指 向的存储空间不等长。因此用指针数组构造的字符串数组能够有效利用存储空间,根据不同的字符串 长度系统为之分配不同的存储容量,因此不会造成存储空间的浪费,这一点与二维数组构造的字符串 数组不一样。

第六部分 \”函数的进一步讨论\”知识点

1、main 函数的参数(教材 11.1 节) main 函数的参数通常有两个,函数首部可以写成以下形式: 第一个参数:类型必须是 int 型,参数名通常是 argc,也可以由用户自己来命名。该参数记录用户从命令行输入的字符串的个数。 第二个参数:类型必须是字符型的指针数组,参数名通常是 argv,也可以由用户自己来命名。该参数记录用户从命令行输入的各个字符串,由于多个字符串构成字符串数组,此时的形参为一个指针数组,数

组中的每一个指针指向各个字符串的首地址。 说明:从命令行输入的多个字符串中,第一个字符串必须是可执行文件的文件名。

参看教材\”P158 例 11.1\”对参数 argc 和 argv 的使用。

2、指向函数的指针(函数指针)(教材 11.2 节)

(1)指向函数的指针变量的定义、赋值

指向函数的指针也称\”函数指针\”,由于 C 语言中函数名代表该函数的入口地址,因此可以定义一种指向函数的指针来存放该入口地址,将这种指针称为指向函数的指针。

void main(int argc, char **argv){ … }

难点

重点

double fun(int a, char *p){ … }

该 fun 函数定义为返回类型是 double 型,有两参数,第一个是 int 型,第二个是 char *型。

{ … } void main(int argc, char *argv[ ])

或者

void main(void){ double (*pfun)(int, char *); //定义指向函数的指针变量

char x=2, double y; pfun = fun; //将 fun 函数的入口地址赋值给指针变量 pfun …

y = (*pfun)(10, &x); //等价于 y = fun(10, &x); }

以上示意图中,在主函数内部首先定义了一个指向函数的指针变量 pfun,明确指出该指针所指向的函数返回值是 double 型,函数有两个参数,第一个参数是 int 型,第二个参数是 char *型。然后为指针变

量 pfun 赋值,通过语句\”pfun = fun;\”将 fun 函数的入口地址赋值给指针变量 pfun,于是对函数的调用即可通过该指针来完成。最后利用 pfun 实现对 fun 函数的调用,通过语句\”y = (*pfun)(10, &x);\”来完成,该语句等价于传统用法\”y = fun(10, &x)\”。

注意 1:定义指向函数的指针变量 pfun 时,\”* pfun\”的两侧必须加小括号,写成 (* pfun)。 注意 2:为指向函数的指针变量赋值时,赋值号的左侧只写指向函数的指针变量名,赋值号的右侧只

写函数名。 注意 3:利用指向函数的指针变量调用函数时,等价于使用函数名调用函数。

(2)指向函数的指针变量作为实参 函数名作实参时,对应的形参应该是函数指针。 函数指针也可以作函数实参,对应的形参应当是类型相同的指针变量。参看教材\”P159 例 11.2\”。

3、函数的递归调用(教材 11.3 节) 重点

一个函数如果自己调用自己,则称为直接递归调用;如果是两个函数相互调用对方,则称为间接递归

调用。 一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。在

递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身。例如有函数

fun 如下图所示:

int fun (int x) {

int y; z=fun(y);return z;

}

这个函数是一个递归函数。但是运行该函数将无休止地调用其自身,这当然是不正确

的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的

办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。

第七部分 \”结构体、共用体\” 知识点 重点

1、结构体类型的说明

\”结构体\”是一种构造类型,是由数目固定,类型相同或不同的若干有序变量组成的集合。组成结构体的每个数据都称为结构体的\”成员\”,或称\”分量\”。 结构体类型说明的形式如下: struct 结构体标识名

例如:以下定义了一个日期型的结构体类型 { struct data { int year; int month; int day; };

类型名 1 结构体成员名列表 1; 类型名 2 结构体成员名列表 2; … 类型名 n 结构体成员名列表 n;

} ; 说明 1:结构体类型的说明可以嵌套。 说明 2:struct 是关键字。\”结构体标识名\”可以省略。 说明 3:右侧花括号后面的分号 ; 不能省略。 说明 4:结构体类型的说明只是列出了该结构的组成情况,标志这种类型的结构模式已存在,编译程

序并没有因此而分配任何存储空间。就类似于列出\”int\”,标志系统认可这种数据类型,但 \”int\”本身并不占用内存空间,只有定义了 int 型的变量后,系统才为变量分配内存空间。

2、用 typedef 定义类型

typedef 是一个关键字,利用它可以将已存在的数据类型命一个新的名称,可以理解为给已有的数据类型取一个别名。

例如:typedef int INT; INT x, y; //等价于 int x, y; 以上写法表示使用 typedef 给已有的数据类型\”int\”取了一个新名字\”INT\”,于是\”INT\”等价于\”int\”,

可以使用这个新类型名定义变量 x 和 y。 注意:typedef 的使用并不是定义了一种新的类型,而仅仅是将已有的数据类型取了一个新名称。 用户自己定义的结构体类型一般都比较复杂,使用 typedef 可以为结构体类型取一个较为简单的名称。 以下三种方式是使用 typedef 为结构体类型取一个别名的方法。别名为\”DATE\”。

方法一:先定义结构体类型,再使用 typedef 为之取一个别名。 struct date { int year; int month; int day; }; typedef struct data

方法二:定义结构体类型 方法三:定义结构体类型的同时使用 typedef 的同时使用 typedef为之 为之取一个别名,并且不省略 取一个别名,并且省略了结构体标识名。 typedef struct date { int year; int month; int day; }DATE; DATE;

结构体标识名。 typedef struct { int year; int month; int day; }

图 1 图 2 图 3

DATE;

3、定义结构体变量

以上提到结构体类型定义后,系统只是认可有这样一种用户自己构造的复杂数据类型,但并没有为之 分配存储空间,只有定义了该结构体类型的变量之后,系统才为变量分配相应的存储空间,结构体变量占

用的存储容量由结构体类型决定。以下几种是定义结构体变量的方法: 方法四:先定义结构体类

方法一:先定义结构体类型,再定义该结构体类型的变量。 struct date { int year; int month; int day; }; struct data

方法三:先使用 typedef 型,然后使用 typedef方法二:在定义结 为之构体类型的同时, 定义结构体类型的别名, 取一个别名,最后使用别

名定义结构体变量。 struct date { int year; int month; int day; }; typedef stuct date DATE;DATE x, y;

图 7

定义结构体变量。 再使用结构体类型的别struct date { int year; int month; int day; }

图 5

名定义变量。 typedef struct date { int year; int month; int day; }DATE; DATE

图 6

x, y;

x, y; x, y;

图 4 同学仔细比较\”图 1\”和\”图 4\”,如果结构体类型名\”struct date\”前面有关键字 typedef,则 struct date

后面的是结构体类型的别名,反之如果没有关键字 typedef,则 struct date 后面的是结构体变量。 同学再仔细比较\”图 2\”和\”图 5\”,同样道理,如果\”struct date\”前面有关键字 typedef,则右侧花

括号后面的是结构体类型的别名,反之如果没有关键字 typedef,则右侧花括号后面的是结构体变量。 以上图 4~图 7 三种方法都定义了两个结构体类型的变量 x 和 y,这两个变量各自占用 12 个字节的存

储容量,该存储容量的大小由结构体类型决定。

4、定义结构体类型的指针变量

结构体类型的指针变量定义方法与结构体类型普通变量的定义方法相同,均可使用图 4~图 7 所示的

三种方法,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, *p = &x;

右图所示定义了一个 STU 结构体类型的普通变量 x,以及指针变量 p。由于该结构体类型各成员一共占用 20+30+1+4+8=63 字节的存储容量,因此系统为变量 x 分配 63 字节的存储空间,指针 p 的基类型为STU 结构体类型,即指针 p 所指向的一则段存储空间是 63 字节。

定义结构体指针变量 p的同时对它进行初始化,为之赋值为\”&x\”,这一赋值过程很有必要,因为这使得指针变量 p 指向了一个有效的存储空间,没有指向有效存储空间的指针不能随便使用。

5、通过结构体变量或结构体指针引用成员

例如上图中定义的 STU 类型的结构体变量 x 或者结构体指针 p,它们有五个成员,如果要把某一个成员取出进行操作,不能直接使用,例如\”age = 20;\”这样的语句是错误的,原因是 age 现在不是一个独立的变量,它是变量 x 的一个成员,或者称之为一个属性,要取出 age 并将它赋值为 20,必须通过变量 x或者指针 p 才能将它取出。有以下三种方法,用到\”.\”运算符或者\”->\”运算符。

(1)结构体变量名. 成员名 (2)结构体指针变量名->成员名

重点

(3)(*结构体指针变量名). 成员名 例如: strcpy(x.name, \”LiWei\”); 或者 strcpy(p->name, \”LiWei\”); 或者 strcpy((*p)->name, \”LiWei\”); x.age = 20; 或者 p->age = 20; 或者 (*p).age = 20;

6、给结构体变量赋值

方法一:初始化 定义结构体变量的同时为它的各个成员赋初值,称为初始化,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU

右图所示在定义结构体变量 x 的同时为它的五个成员赋初值。所有初值必须要

用一对花括号括起来,各数值之间用逗号

隔开,数值的类型以及书写顺序与各成员

的类型和书写顺序保持一致。

x={\”20070102001\”, \”ZhangHua\”, \’M\’, 18, 80.0};

方法二:结构体变量的整体赋值。如果两个结构体变量类型相同,则可以对两个结构体变量进行整体

赋值。例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, y={\”20070102001\”, \”ZhangHua\”, \’M\’, 18, 80.0};x = y; //结构体变量的整体赋值

右图所示定义了两个结构体变量 x 和y。其中变量 y 使用初始化的方法已经为它的五个成员赋了初值,而变量 x 定义的时候各成员还没有初值。由于 x 和 y 是同类型的变量,因此可以通过赋值语句\”x = y;\”将变量 y 的值整体赋值给变量 x。这样做相当于将变量 y 各个成员的初值对应地赋值给变量 x 的各个成员。

方法三:结构体变量的各成员分开赋值。两个结构体变量对应成员之间可以相互赋值,例如: strcpy(x.num, y.num); strcpy(x.name, y.name); x.sex = y.sex; x.age = y.age; x.score = y.score; 注意:以上各成员分开赋值时,对于字符串类型,不能写成\”x.num = y.num;\”、\”x.name = y.name;\”,

虽然此时赋值号的两侧类型相同,都是数组名(是地址),但由于数组名本身是地址常量,不能将其赋值

为另一个存储空间的首地址,因此对于字符数组类型的成员之间进行赋值,应选用 strcpy 库函数。其它基本数据类型的成员之间可以直接使用赋值语句进行赋值。

方法四:从键盘为各成员输入数值。例如: scanf(\”%s\”, x.num); //注意:成员\”x.num\”本身是数组名,代表地址,因此前面不加取地址符 scanf(\”%s\”, x.name); //成员\”x.name\”本身是数组名,代表地址,因此前面不加取地址符 scanf(\”%c\”, &x.sex); //成员\”x.sex\”、\”x.age\”、\”x.score\”是基本数据类型的变量,前面要加取地址符 scanf(\”%d\”, &x.age); scanf(\”%lf\”, &x.score);

7、结构体变量或成员做实参

\”传值\”方式——与基本数据类型一样,当结构体变量或者结构体变量的成员做实参时,实现的是\”传

值\”方式,只能单向传递数据。对应的形参必须与实参保持同类型。 \”传地址\”方式——当结构体变量的地址或者结构体变量成员的地址做实参时,实现的是\”传地址\”

方式。对应的形参必须是同类型的指针变量。 难点 8、利用结构体变量构成链表

当结构体类型定义时有一个自身结构体类型的指针变量作为成员,则可以利用该结构体类型的变量构

成链表。构成链表有静态方式和动态方式两种,动态方式是难点,也是考查的重点。 构成单向链表时,通常有一个头结点,若干个数据结点,以及一个末尾结点。一般来说,头结点的数

据域为空,头结点的指针域指向第一个数据结点,依次类推,每一个数据结点的指针域指向后一个数据结

点,最后一个数据结点称为末尾结点,末尾结点的指针域为空(NULL)。 有关单向链表的基本算法(参考教材 P198~P201)有:链表的建立、顺序访问链表中各结点的数据

域、在单向链表中插入结点、删除单向链表中的结点。对链表的各种操作必须考虑各个指针变量的用途。

9、共用体

共用体类型的说明以及共用体变量的定义方式与结构体相似。共用体与结构体不同的是,结构体变量

的各个成员各自占用自己的存储空间,而共用体变量的各个成员占用同一个存储空间。 说明 1:共用体变量的存储空间大小由占用字节数最多的那个成员决定。 说明 2:共用体变量初始化时只能对它的第一个成员进行初始化。 说明 3:由于共用体变量所有成员占用同一个存储空间,因此它们的首地址相同,并且与该变量的地

址相同。 共用体变量中每个成员的引用方式与结构体完全相同,可以使用如下三种方式: (1)共用体变量名.成员名 (2)共用体指针变量名->成员名 (3)(*共用体指针变量名).成员名

第八部分 \”文件\”知识点

1、基本概念

(1)记录在外部介质上的数据的集合称为\”文件\”。数据可以按文本形式或二进制形式存放在介质上,因此文件可以按数据的存放形式分为文本文件和二进制文件。二进制文件的输入输出速度较快一些。

(2)对文件的输入输出方式称为存取方式,在 C 语言中,有两种存取方式——顺序存取、直接存取。 顺序存取的特点是:每当打开这类文件进行读或写操作时,总是从文件的开头开始进行读或写。 直接存取的特点是:可以通过调用库函数指定读或写的起始位置,然后直接从此位置开始进行读或写。 (3)文件指针:是一个指向结构体类型名为 FILE 的指针。对文件的打开、关闭、读、写等操作都

必须借助于文件指针来完成。例如:FILE *fp; 即表示定义了一个 FILE 结构体类型的文件指针。 (4)文件位置指针:只是一个形象化的概念,用来表示当前读或写的数据在文件中的位置。读或写

操作总是从文件位置指针所指的位置开始。

2、文件操作类库函数

文件操作类库函数都定义在 stdio.h 头文件里。 (1) fopen 和 fclose 函数——打开、关闭文件

函数调用形式:文件指针 = fopen(文件名, 文件使用方式); fclose(文件指针); 说明 1:fopen 函数的参数文件名和文件使用方式都是字符串。该函数调用成功后即返回一个

FILE 类型的指针。常用的文件使用方式及其含义如下表所示: 文件使用方式 含义

\”r\”、\”w\” 为只读、只写而打开文本文件。总是从文件开头进行读写操作。 \”r+\”、\”w+\” 为读和写而打开文本文件。 \”a\” 为在文件后面添加内容而打开文本文件。文件中原有内容保持不变。

文本 文件

\”a+\” 在文件末尾添加内容后,可以从头开始读。

\”rb\”、\”wb\” 以只读、只写而打开二进制文件。总是从文件开头进行读写操作。 \”rb+\”、\”wb+\” 为读和写而打开二进制文件。 \”ab\” 为在文件后面添加内容而打开二进制文件。文件中原有内容保持不变。

二进制 文件

\”ab+\” 同\”a+\”, 在文件末尾添加内容后,可以从指定位置读。 说明 2:当对文件的读、写操作完成之后,必须调用 fclose 函数关闭文件。 (2) fscanf 和 fprintf 函数——格式化输入输出。

函数调用形式:fscanf(文件指针, 格式控制字符串, 输入项列表); fprintf(文件指针, 格式控制字符串, 输出项列表); 功能:fscanf 函数是从文件读入格式化数据,fprintf 函数是将格式化数据写到文件中。 说明:这两个函数与 scanf、printf 函数的功能相似,表一比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向 scanf 键盘 内存 printf 内存 显示屏 fscanf 文件 内存

输入 格式化数据 fprintf 内存 文件

输出 格式化数据

表一

(3) fgetc 和 fputc 函数——也可写成 getc、putc。功能是输入、输出一个字符。 函数调用形式:ch = fgetc(文件指针); //ch 是一个字符型变量 fputc(ch, 文件指针); 功能:fgetc(或 getc)函数是从文件读入一个字符,fputc(或 putc)函数是将一个字符输出

到文件。

说明:这两个函数与 getchar、putchar 函数的功能相似,表二比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向 getchar 键盘 内存 putchar 内存 显示屏

fgetc 文件 内存 输入

一个字符 fputc 内存 文件 输出

一个字符 表二

(4) fgets 和 fputs 函数——输入、输出一个字符串。 函数调用形式:fgets(str, n, 文件指针); //str 是字符串的起始地址,n 表示读入字符串的长度 fputs(str, 文件指针); 功能:fgets 函数是从文件读入字符串,fputs 函数是将字符串输出到文件。 说明 1:fgets 函数最多只能从文件中读 n-1 个字符,读入结束后,系统将自动添加\’\\0\’。 说明 2:这两个函数与 gets、puts 函数的功能相似,表三比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向

gets 键盘 内存 puts 内存 显示屏 fgets 文件 内存

输入 字符串 fputs 内存 文件

输出 字符串

表三

(5) fread 和 fwrite 函数——读、写二进制文件。 函数调用形式:fread(buffer, size, count, 文件指针); fwrite(buffer, size, count, 文件指针); 参数说明:以上函数中的参数 buffer 是数据块的指针,输入或者准备输出的数据存放在此内

存块中;size 表示每个数据块的字节数;count 用来指定每次读、写的数据块个数。 说明:fread 和 fwrite 这两个函数只能针对二进制文件进行读写,不能操作文本文件。

(6) feof 函数——用来判断二进制文件是否结束,如果是则返回 1,否则返回 0。 函数调用形式:foef(文件指针); 说明:文本文件是以 EOF(相当于-1)作为文件的结束标志。二进制文件没有明显的结束

标志,判断二进制文件是否结束必须调用 feof 函数。 (7) fseek 函数——用来移动文件位置指针到指定的位置上,接着的读或写操作就从此位置开始。

函数调用形式:fseek(文件指针, offset, origin); 参数说明:以上函数中的参数 offset 是以字节为单位的位移量,为长整型;origin 是起始点,

用以指定位移量是以哪个位置为基准,起始点既可以用标识符(表四)来表示, 也可以用数字来表示。

位置指针起始点的标识符 代表的起始点 数字 SEEK_SET 文件开始 0 SEEK_END 文件末尾 2 SEEK_CUR 文件当前位置 1

表四

说明 1:对于文本文件来说,位移量 offset 必须是 0。例如:fseek(pf, 0L, SEEK_SET); 表示 将文件位置指针移到文件开头;fseek(pf, 0L, SEEK_END); 表示将文件位置指针移 到文件末尾;

说明 2:对于二进制文件来说,如果位移量是正整数,表示位置指针从指定的起始点处向后移 动;如果位移量是负整数,表示位置指针从指定的起始点处向前移动。

(8) ftell 函数——用来获得当前文件位置指针的位置,该函数返回值是一个长整型的数,表示当前位置指针相对于文件开头的字节数。 函数调用形式:t = ftell(文件指针); //t 是一个长整型的变量

(9) rewind 函数——又称\”反绕\”函数,功能是使文件的位置指针回到文件开头处。 函数调用形式:rewind(文件指针);

常用库函数

1、标准输入输出函数(头文件 stdio.h) 函数名 函数原型 功能

scanf scanf(格式控制, 地址项列表) 从键盘输入格式化数据 printf scanf(格式控制, 输出项列表) 将格式化数据输出到显示屏 getchar char getchar(void) 读取键盘输入的一个字符 putchar putchar(char ch) 将一个字符输出到显示屏 gets gets(char *s) 读取键盘输入的一个字符串,可以包含空格 puts puts(char *s) 将一个字符串输出到显示屏

2、数学函数(头文件 math.h) 函数名 函数原型 功能

sqrt double sqrt(double x) 计算并返回参数 x 的平方根值 pow double pow(double x, double y) 计算并返回参数 x 的 y 次方的值 fabs double fabs(double x) 计算并返回参数 x 的绝对值 log double log(double x) 计算并返回参数 x 的对数值,即求 ln(x)的值

3、字符串处理函数(头文件 string.h) 函数名 函数原型 功能

strlen int strlen(char *str) 计算 str 所指字符串的长度,不包括\’\\0\’ strcpy strcpy(char *dest, char *sour) 将 sour 所指字符串复制到 dest 所指的存储空间里 strcat strcat(char *dest, char *sour) 将 sour 所指字符串粘贴到 dest 所指字符串的末尾

strcmp int strcmp(char *str1, char *str2) 比较 str1 和 str2 所指的两个字符串,并返回比较的结果。如果前者>后者,返回 1;如果前者<后者,返回-1;如果前者==后者,返回 0。

4、动态存储分配函数(头文件 stdlib.h) 函数名 函数原型 功能

malloc void *malloc(unsigned n) 按照形参给定的大小动态分配内存空间,并返回指向该内存块的指针。(形参 n 即代表 n 个字节)

calloc void *calloc(unsigned n, unsigned size) 按照形参给定的大小动态分配内存空间,并返回指向该内存块的指针。(形参 n 即代表有 n 个数据块,形参 size 代表每个数据块的字节数)

free void free(void *p) 释放之前调用 malloc 或 calloc 分配的内存空间。形参指针 p 指向即将被释放的内存空间的首地址。

5、文件函数(头文件 stdio.h) 函数名 函数原型 功能

fopen FILE *fopen(文件名, 文件使用方式) 按照使用方式打开文件,返回文件指针 fclose fclose(FILE *fp) 关闭由 fp 指向的已打开的文件 fscanf fscanf(FILE *fp, 格式控制, 地址列表) 从 fp 指向文件读入格式化数据 fprintf fprintf(FILE *fp, 格式控制,输出项列表) 将格式化数据写到 fp 指向文件中 fgetc/getc char fgetc(FILE *fp) 从 fp 指向文件读入一个字符 fputc/putc fputc(char ch, FILE *fp) 将一个字符写到 fp 指向文件中 fgets fgets(char *s, int n, FILE *fp) 从 fp所指文件的指定位置读入一个字符串(含 n-1

个字符),将此字符串存放到 s 所指的内存空间里。fputs fputs(char *s, FILE *fp) 将 s 所指字符串写到 fp 指向的文件中。

fread fread(void *p, int s, int n, FILE *fp) 从 fp 指向的二进制文件读出 n 个数据块,每个数据块有 s 个字节大小,将读出的数据块存放到 p所指的内存空间里。

fwrite fwrite(void *p, int s, int n, FILE *fp)从 p 所指的内存空间里读取信息写到 fp 指向的二进制文件里,读取的信息由 n 个数据块组成,每个数据块有 s 个字节大小。

feof int feof(FILE *fp) 判断 fp 指向的二进制文件是否结束,如果是返回1,否则返回 0。

fseek fseek(FILE *fp, long n, int origin) 移动 fp 指向的文件的位置指针,使之移动到距离origin 起始点 n 个字节的位置。

ftell long ftell(FILE *fp) 获得并返回 fp 指向的文件当前位置指针相当于文件开头的字节数。

rewind rewind(FILE *fp) 反绕函数,使文件位置指针回到文件开头。

其 它

1、C 语言中的常用关键字

(1) 与数据类型有关的:char、int、float、double、short、long、signed、unsigned、void、struct、union、typedef、enum、sizeof

(2) 与存储类别有关的:auto、static、register、extern (3) 与程序控制结构有关的:if、else、switch、case、default、while、do、for、break、continue、return、

goto

2、容易用错的运算符

(1)= 是赋值号,功能是将其右侧表达式的值赋值给左侧的变量,注意它的左侧只能是变量名。 == 是关系运算符中的等于号,功能是比较其左右两侧表达式的值是否相等。

(2)* 当把它放在两个表达式中间时作乘号使用(双目运算符);当变量定义时把它放在变量名前时它

是一个标志,标志此时定义的变量时指针变量;当把它放在变量名前作为表达式中的一部分,则

它是取内容符(单目运算符)。

(3)&& 是逻辑与运算符 对比 & 是按位与运算符(双目) 对比 & 是取地址符(单目)

|| 是逻辑或运算符 对比 | 是按位或运算符 ! 是逻辑非运算符 对比 ~ 是按位取反运算符

(4)^ 是按位异或运算符,注意它不是计算次方的运算符,计算次方需调用 pow 库函数完成。

(5)sizeof 是求字节数运算符,注意它不是库函数,而是运算符。注意它与 strlen 库函数的区别。

(6)! 逻辑非运算符(单目) != 是关系运算符中的不等于号(双目)

(7), 是逗号运算符,是逗号 C 语言中比较特殊的一个运算符,其优先级最低。 (8)? : 是条件运算符,是指 C 语言中唯一的三目运算符。

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。