一、C的数据类型
1.常量——其值不能改变的量称为常量。 定义:#define price 30
2.变量——其值可以改变的量称为变量。
变量名实际上是一个符号地址,在对程序编译连接时由系统给每一个变量名分配一个内存地址。 3.数据类型 (1)整型
(2)实型:float(占4字节,6~7位有效数字)、double(占8字节,15~16位有效数字)、long double(占10个字节,18~19位有效数字) (3)字符型
字符常量:
Char c=’a’;
int i;
i=’a’; // i赋值’a’的ASCII码 c=97; // c赋值’a’的ASCII码 printf(”%c,%d\\n”,i,i); printf(”%c,%d\\n”,c,c); 结果:a,97 a,97
C语言的运算符:
基本的算术运算符:
? + (加法运算符,或正值运算符。如:3+5、+3) ? - (减法运算符,或负值运算符。如:5-2、-3) ? * (乘法运算符。如:3*5) ? / (除法运算符。如:5/3)
? % (模运算符,或称求余运算符,%两侧均应为整型数据,如:7%4的值为3)。 C的运算符有以下几类: (1)算术运算符 (+ - * / %)
(2)关系运算符 (><==>=<=!=) (3)逻辑运算符 (!&&||)
(4)位运算符 (<< >> ~ |∧&)
(5)赋值运算符 (=及其扩展赋值运算符) (6)条件运算符 (?:) (7)逗号运算符 (,)
(8)指针运算符 (*和&) (9)求字节数运算符(sizeof)
(10)强制类型转换运算符( (类型) ) (11)分量运算符(.->) (12)下标运算符([ ])
(13)其他 (如函数调用运算符())
自增自减运算:i++,++i,i--,--i
例如:5/3=1 除后取整,
5%3=2 除后取余,%两侧必须是整型数
参加运算+ - * / 中有一个数是实数,则结果为double型
二、数据存储基础 1.数组 2.指针 3.结构 4.链表
5.类型定义:typedef 原类型名 新类型名
三、C语言语句
例:编写程序,将一个大小为n的整数数组循环左移m位。如1,2,3,4,5,6,7,8循环左移3位后结果是:4,5,6,7,8,1,2,3. 四、流程控制
程序设计语言除了能表达各种各样的数据外,还必须提供一种手段来表达数据处理的过程,即程序的控制过程。程序的控制过程通过程序中的一系列语句来实现。
按照结构化程序设计的观点,任何程序都可以将程序模块通过三种基本控制结构进行组合来实现。这三种基本的控制结构是顺序、分支和循环。
顺序结构是一种自然的控制结构,通过安排语句或模块的顺序就能实现。所以,对一般程序设计语言来说,需要提供表达分支控制和循环控制的手段。C语言为分支控制提供了if-else和switch两类语句,而为循环控制提供了for、while和do-while三类语句。
以上三种控制方式称为语句级控制。它实现了程序在语句间的跳转。 当要处理的问题比较复杂时,为了增强程序的可读性和可维护性,常常将程序分为若干个相对独立的子程序。在C语言中,子程序的作用由函数完成。函数通过一系列语句的组合来完成某种特定的功能(如求整数n的阶乘)。当程序需要相应功能时,不用重新写一系列代码,而是直接调用函数,并根据需要传递不同的参数(如求阶乘函数中的n)。同一个函数可以被一个或多个函数(包括其自身)多次调用。函数调用时可传递零个或多个参数,函教被调用的结果将返 回给主调函数。这种涉及函数定义和调用的控制称为单位级控制。所以,程序设计语言的另一个功能就是提供单位级控制的手段,即函数的定义与调用手段。 分支控制
1.if-else语句
If- else语句的一般形式为: if(表达式) 语句1; else
语句2;
该语句用于实现分支结构,根据表达式的值选择语句1或语句2中的一条执行。if-else语句首先求解表达式,如果表达式的值为“真”,则执行语句l;如果表达式的值为“假”,则执行语句2。if-else语句的else部分(如果不需要)可以省略。
可以通过多个二路分支语句if—else的嵌套组合实现多路选择,其一般形式为:
if(表达式1)
语句1; else if(表达式2) 语句2; else if(表达式n-1) 语句n -1; ‘ else 语句n:
它的执行流程是:首先求解表达式1,如果表达式1的值为“真”,则执行语句1,并结束整个if语句的执行,否则,求解表达式2,??最后的else处理给出的条件都不满足的情况,即表达式1、表达式2、??和表达式n -1的值都为“假”时,执行语句n。
在嵌套的if-else语句中,如果内嵌的if省略了else部分,会存在后面的else与哪个if配对的问题。在C语言中,else和if的匹配准则是:else与最靠近它的、没有与别的else匹配过的if相匹配。 2.switch语句
switch语句可以处理多分支选择问题,典型的形式是: switch(表达式) {
case常量表达式1:语句段1;break; case常量表达式2:语句段2;break; case常量表达式n:语句段n;break;
default: 语句段n+1;break; }
该switch语句首先求解表达式.如果表达式的值与某个常量表达式的值相等,则执行该常量表达式后的相应语句段,如果表达式的值与任何一个常量表达式的值都不相等,则执行default后的语句段。当碰到break语句时,跳出switch语句。
在switch语句中,表达式和常量表达式的值一般是整型或字符型,各常量表达式的值不能相等。每个语句段可以包括一条或多条语句,也可以为空。 Switch语句中default可以省略,如果省略了default,当表达式的值与任何一个常量表达式的值都不相等时,就什么都不做。
break语句在switch语句中也是可选的。如果在switch语句中不使用break,那么该switch语句的执行流程将会不一样:求解表达式后,如果表达式的值与某个常量表达式的值相等,则执行该常量表达式后的所有语句段(包括其他常量表达式后面的语句段),如果表达式的值与任何一个常量表达式的值都不相等,则执行default后的所有语句段。
由此可见,在switch语句所有语句段的末尾使用break,可以简单、清晰地实现多分支选择,这也是switch语句的主要用法。
五、循环控制
在程序设计中,如果需要重复执行某些操作,就要用到循环结构。C语言提供了3种循环语句,分别是for语句、while语句和do-while语句。 1.for语句
在C语言中,for语句是一种常用的循环语句。它的一般形式为: for (表达式1;表达式2;表达式3)
{ 循环体语句;} //如果{ }内只有一条语句,则可省略{} 例1:for (i=0;i<10;i++) Sum=sum+i; 例2:for (i=0;i<10;i++) {j=i+2; sum=sum+j;}
for语句的执行顺序是:(1) 先计算表达式1;
(2) 再判断表达式2,若其值为“真”,则执行循环
体语句,并接着计算表达式3,然后继续判断表达式2;
(3) 如此循环;若表达式2的值为“假”,则结束循
环,继续执行for语句的下一条语句。
2.while语句
while语句的一般形式为: while(表达式)
{循环体语句;} //如果{ }内只有一条语句,则可省略{ }
while语句的执行顺序是:当表达式的值为“真”时,循环执行,直到表达式的值为“假”,循环终止,并继续执行while的下一条语句。
while语句的构成简单,只有一个表达式和循环体语句,分别对应循环的两个核心要素:循环条件和循环体。
循环的实现一般包括4部分,即初始化、条件控制、重复的操作以及通过改变某些量的值最终改变条件的真假性,使循环能正常结束。这4部分可以直接和for语句中的4个成分(表达式1、表达式2、循环体语句和表迭式3)对应。
当使用while语句时,由于它只有2个成分(表达式和循环体语句),就需要另加初始化部分,至于第四部分,while语句的循环体语句可包含for语句的循环体语句和表达式3,所以while的循环体语句中必须包含能最终改变循环条件真假性的操作。
可以把for语句改写成while语句: 表达式1;
while(表达式2) {
for的循环体语句;
表达式3; }
for语句和while语句都能实现循环。一般情况下,如果问题比较明显地蕴含了循环次数,使用for语句更清晰,循环的4个组成部分一目了然;其他情况下多使用while语句。 3.do-while语句
do-while语句与上述两种循环语句略有不同,它先执行循环体,后判断循环条件。所以无论循环条件的真假性如何,至少会执行一次循环体。其一般形式为:
do {
循环体语句: } while(表达式)
xxxxxx //这是do—while的下一条语句
do-while语句第一次进入循环时,首先执行循环体语句,然后再检查循环控
制条件,即计算表达式,若其值为“真”,继续循环,直到表达式的值为“假”,循环结束,执行do -while的下一条语句。
do-while语句的使用方法和while语句类似,语句中的表达式可以是任意合法的表达式,使用时要另加初始化部分,循环体语句中必须包含能最终改变条件真假性的操作。
do -while语句适用于先循环后判断循环条件的情况,一般在循环体的执行过程中要明确改变循环控制条件。它每执行一次循环体后,再判断条件,以决定是否进入下一次循环。
4.break语句和continue语句
break语句强制循环结束,一旦执行了break语句,循环提前结束,不再执行循环体中位于break后的其他语句。break语句应该和if语句配合使用,即条件满足时,才执行break语句跳出循环;否则,若break语句无条件执行,就意味着永远不舍执行循环体中break后面的其他语句。
continue语句的作用是跳过循环体中continue后面的语句,继续下一次循环。continue语句一般也需要与if语句配合使用。
continue语句和break语句的区别在于,break结束循环,而continue只是跳过后面语句,继续循环。break除了可以中止循环外,还用于结束switch语句,而continue只能用于中止本次循环。 5.嵌套循环
嵌套循环(或多重循环)是指大循环中嵌套小循环。在处理许多比较复杂问题时经常会使用嵌套循环,3种循环( for、while、do-while)可以相互嵌套。
六、函数和递归
函数是一个完成特定工作的独立程序模块。程序中一旦调用了某个函数,该函数就会完成一些特定的工作,然后返回到调用它的地方。函数包括库函数和自定义函数两种。例如,scanf、printf等库函数由C语言系统提供定义,编程时只要直接调用即可。在程序设计中,根据模块化程序设计的需要,往往需要用户自己定义函数,即自定义函数。 函数定义的基本形式是:
函数类型 函数名(形参表) /*函数首部*/ {
函数实现过程; /*函数体*/ }
函数的定义包括函数首部和函数体两部分。其中,函数首部由函数类型、函
数名和形参表组成;函数体包括函数实现过程和return语句(return 表达式;),体现为一对大括号内的若干条语句。
在函数首部,函数类型指函数返回值的类型,一般与return语句中表达式的类型一致;函数名是一个合法的标识符;形参表中给出函数所有形参的名称和类型,它的格式为:
类型1 形参1,类型2 形参2,?,类型n形参n
形参表中各个形参之间用逗号分隔,每个形参前面的类型必须分别写明。函数形参的数量可以是0~n个,即根据具体情况,形参可以是一个,也可以是多个,或者没有形参。
在函数体中,函数的实现过程是一些完成特定工作的语句,return语句中的表达式反映了函数运算的结果,通过return话句结束该函数的运行并将该结果回送给主调函数。return语句的作用有两个:一是结束函数的运行,二是带着运算结果(表达式的值)返回主调函数。在函数定义中也可以没有return语句,此时函数执行时最后一个语句的值作为函数的返回值。
Return浯句只能返回一个值,如果函数产生了多个运算结果,将无法通过return直接全部返回。如果函数要返回多个运算结果,一般有以下几种方法:①通过全局变量;②通过函数参数传递变量地址,在函数中通过这个参数为变量赋值;③把准备返回的多个结果组成一个结构体返回。
有些函数可以不返回任何值,仅仅是执行一个过程。这类函数的类型可以说明为void,其函数体中的return语句后面的表达式可以省略。
注意:在函数定义时,若不说明函数类型(即函数类型缺省),该函数的类型默认为int。 1.函数的调用
定义一个函数后,就可以在程序中调用这个函数。调用函数时,将实参传递给形参并执行函数定义中所规定的程序过程,以实现相应的功能。
在C语言中,调用标准库函数时,只需要在程序的最前面用#include命令包含相应的头文;调用自定义函数时,程序中必须有与调用函数相对应的函数定义。 函数调用的一般形式为: 函数名(实参表)
其中,实参可以是常量、变量和表达式。
计算机在执行程序时,从主函数main开始执行,如果遇到某个函数调用,主函数被暂停执行,转而执行相应的函数;该函数执行完后,将返回主函数,然后再从原先暂停的位置继续执行。
函数定义中的参数称为形参,函数调用时的参数称为实参。形参和实参必须
一一对应,要求两者数量相同、类型一致。在程序运行中,遇到函数调用时,将实参的值依次传给形参,这就是参数传递。
函数的形参必须是变量,用于接收实参传递过来的值,形参的使用方法和普通变量相同;而实参可以是常量、变量或表达式,其作用是把常量、变量或表达式的值传递给形参。
按照C语言的规定,在参数传递过程中,将实参的值复制给形参。这种参数传递是单向的,只允许实参把值复制给形参,而形参的值即使在函数中改变了,也不会反过来影响实参。
例:设计一个函数swap实现两个整形变量值的交换。 Void swap(int x,int y) {
int temp ; temp=x ; x=y ; y=temp ; } int main( ) {
int x=10,y=20 ; swap(x,y) ;
printf(“x=%d,y=%d”,x,y ) ; return 0 ;
} //上述代码并没有真正实现交换
应该这样:
Void swap(int *x,int *y) {
int temp ; temp=*x ; *x=*y ; *y=temp ; } int main( ) {
int x=10,y=20 ; swap(&x,&y) ;
printf(“x=%d,y=%d”,x,y ) ; return 0 ; }
C语言要求函数先定义后调用,将主调函数放在被调函数的后面,就像变量先定义后使用一样。如果主调函数放在自定义函数的前面,就需要在函数调用前,加上函数原型声明。如果不声明,编译时会默认调用函数是int类型。
函数声明的目的主要是说明函数的类型和参数的情况,以保证程序编译时能判断对该函数的调用是否正确并进行相应的编译处理。函数声明的一般格式为: 函数类型 函数名(参数表); 在设计函数时,应注意掌握以下原则。
①函数功能的设计原则:结合模块的独立性原则,函数的功能要单一,不要设计多用途的函数,否则会降低模块的聚合度。
②函数规模的设计原则:函数的规模要小,尽量控制在50行代码以内,这样可以使函数更易于维护。
③函数接口的设计原则:结合模块的独立性原则,函数的接口包括函数的参数(入口)和返回值(出口),不要设计过于复杂的接口,合理选择、设置并控制参数的数量,尽量不要使用全局变量,否则会增加模块的耦合度。 2.递归函数
一个函数除了可以调用其他函数外,C语言还支持函数直接或间接调用自己。这种函数自己调用自己的形式称为函数的递归调用,带有递归调用的函数也称为递归函数。
从递归函数的程序设计角度看,有两个关键点必须紧紧抓住: ①递归出口:即递归的结束条件,到何时不再递归调用下去;
②递归式子:当前函数结果与准备调用的函数结果之间的关系,如求阶乘函数Factorial(n)=n*Factorial(n-1)。
递归程序设计是一种非常有用的工具,可以解决一些用其他方法很难解决的问题。但递归程序设计的技巧性要求比较高,对于一个具体问题,要想归纳出递归式子有时是很困难的,并不是每个问题都像求阶乘函数Factorial那样直截了当。
当函数调用自己时,每一次调用都会产生一个新的、同先前调用相独立的版本。因此递归调用并不能减少空间消耗,相反大多数情况下采用递归操作会大大消耗内存;同样,递归也无法提高程序的运行速度。
递归函数的主要优点是可以把算法写得比使用非递归函数时更清晰、更简洁,相对其他方法,递归能更加自然地反映问题的解决过程,而且在程序的理解和调试方面,递归也更容易让人接受。 例2.8设计函数求n!
利用递归函数求整数的阶乘是一个很经典也很简单的问题。这个问题的递归函数设计相对直接,代码如下所示: int factorial(int n) {
if (n==0) return 1;
else return n*factorial(n-1); }
程序执行过程如图所示;
写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输入。
递归函数的主要优点是可以把算法写得比使用非递归函数时更清晰、更简洁,相对其他方法,递归能更加自然地反映问题的解决过程,而且在程序的理解和调试方面,递归也更容易让人接受。 例2.8设计函数求n!
利用递归函数求整数的阶乘是一个很经典也很简单的问题。这个问题的递归函数设计相对直接,代码如下所示: int factorial(int n) {
if (n==0) return 1;
else return n*factorial(n-1); }
程序执行过程如图所示;
写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输入。