c(已经学过java的人非常适合).doc_第1页
c(已经学过java的人非常适合).doc_第2页
c(已经学过java的人非常适合).doc_第3页
c(已经学过java的人非常适合).doc_第4页
c(已经学过java的人非常适合).doc_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

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

文档简介

C语言学习(主要记录一些和java不一样的东西)1.数据类型1.1.常量与符号常量#define 程序用使用这个来定义常量#define PRICE 30 这个模式1.2.变量其值可以改变的量称为变量,一个变量有一个名字,在内存中占据一定的存储单元,在该存储单元中,存放变量的值,注意区分变量名与变量值的概念。变量名实际上是一个符号地址,在程序编译连接时,对变量名分配一个内存地址,通过变量名找到相应的内存地址,从其存储单元中读取数据。1.3.整型数据1.3.1 整型常量C的整型常量有三种表现形式,十进制,八进制,十六进制1.3.2 整型变量1) 基本类型,int类型2) 短整型 short int 或者short3) 长整型 long int 或者long4) 整型在5)1.4. 实型数据1.4.1.实型数据的表示方法实数又称浮点数十进制小数形式表示指数形式表示,科学计数法表示1.4.2 实型变量实型数据在内存的存储形式实型变量的分类实型变量的舍入误差实型变量是用有限的存储单元存储的,因此能提供的有效数字总是有限的,在有效位以外的数字将被舍去,由此可能会产生一些误差。1.5 字符型数据1.5.1 字符常量Abc ? $ 等等,常见转义字符1.5.2 字符变量Char 只能存放一个字符,1.5.3 字符数据在内存中的存储形式和使用方法将一个字符常量存放到一个字符变量中,实际上并不是把该字符本身放到内存单元中,而是将该字符的相应的ASCII代码放到存储单元中,而实际上是以二进制存放的。1.5.4 字符串常量使用”包裹的是字符串常量,而使用是字符,这是不一样的,字符串可以是很多个字符,在C语言中,每个字符串的末尾都有一个0作为字符串结束标志,在ASCII码中0是一个空操作字符。所以“a”虽然看上去只有一个字符,其实有一个隐藏的结束字符。不能赋值给char类型1.6 变量赋值可以在声明变量的时候,进行赋初始值1.7 各类数值之间的混合运算在不同类型混合运算的时候,要先转换为同一类型,在进行运算,转换的规则如图:1.8 算术运算符,算术表达式1.9赋值运算,和赋值表达式1) 赋值运算符就是“=”2) 类型转换,将实型转换为整型的时候,会舍弃小数部分,3) 小转大,一般没有问题,4) 大转小,要强制转换,且考虑溢出的问题5) 字符型数据赋给整型变量的时候,由于字符只占一个字节,在赋值的时候是放到整型变量的低8位中,有两种情况,对于无符号的,放低8位,高8位补0,对于有符号的,若字符最高位是1,高8位补1,反之亦然。6) 将int,short, long, 给char时,低8位不变送到char类型,即截断2. 简单的C程序设计2.1 C语句概括5大类一个语句必定有一个分号2.2 计算机输入输出的概念在使用C语言的库函数的时候,要用预编译命令 #include 将有关的头文件,包括到用户源文件中,在头文件中包含了与用到函数有关的信息。2.3 字符数据的输入输出2.3.1 putchar函数Char a = a;Putchar(a); 输出单个字符2.3.2 getchar 函数,单个字符输入函数2.4 格式输入与输出2.4.1 printf 函数Printf(格式控制,输出列表)格式控制=“格式说明,用%,普通字符,需要按照原样输出的”。输出列表=可以是表达式格式字符1) %d 用来输出10进制整型,%md,m可以指定输出字段的长度,%ld长整型2) O格式 %o ,以8进制输出,将内存单元中各位按照8进制输出,不带符号的3) X格式,%x,按照16进制4) U格式,%u用来输出无符号整型数5) C格式 ,%c 输出一个字符6) S格式 , %s 输出一个字符串7) f格式,%f,输出实数8) e格式,按照指数格式9) G格式,输出实数2.4.2 scanf 函数格式输入函数Scanf(格式控制,地址列表)比较要注意的就是,后面地址列表,不是变量名,而是&变量名并且输入的时候,要严格按照格式控制里的输入2.5 顺序结构程序设计从上至下,按照程序顺序执行即可3. 选择结构程序设计If else3.1 关系运算符与表达式3.1.1 关系运算符3.1.2 关系表达式用关系运算符将表达式连接起来的表达式!3.2 逻辑运算符与表达式3.2.1 逻辑运算符3.2.2 逻辑表达式由逻辑运算符连接起来的表达式!3.3 if与java差不多,不做解释3.4 switch和java差不多,也不做多解释4. 循环结构4.1 概述相比java多了一个goto语句和if语句构成循环4.2 goto语句以及goto语句构造的循环但是这个东西基本现在不用了4.3 while4.4 dowhile4.5 for4.6 循环的嵌套4.7 break和continue与java都差不多,不做解释几个程序例子,自己练练5. 数组与java有许多不同之处,主要在于指针的涉及,后面学到指针在补充5.1 一维数组5.1.1 定义与java一样5.1.2 使用与java一样5.1.3 初始化1) 在定义数组时,对元素赋以初值2)3) 可以只给一部分元素赋值4)5) 在对全都数组元素赋值的时候,可以不指定数组长度6)5.1.4 冒泡法5.2 二维数组5.2.1 二维数组的定义二维数组就相当于一个特殊的一维数组5.2.2 二维数组的引用与java差不多5.2.3 二维数组的初始化1) 分行给二维数组赋值2)3)4)5)5.3 字符数组用来存放字符数据的数组,都是字符数组5.3.1 字符数组的定义与整型无太大区别5.3.2 字符数组的初始化5.3.3 字符串和字符串的结束标志字符串结束都是以0为结束标志的,0前面的为实际长度但是字符数组,0是要算一个长度的C语言中,数组名就代表了该数字的起始地址因为C语言用一维字符数组来存放字符串,而且允许使用数组名输入或者输出字符串,因此可以把一维字符数组当作是java的String5.3.4 字符串处理函数Puts函数:输出字符串Gets函数:得到一个字符串到字符数组,并且得到一个函数值,该函数值是字符数组的起始地址。Strcat函数:字符串连接函数,连接两个字符串数组中的字符串,把字符串2连接到字符串1,结果放到字符数组1中,函数调用后得到一个函数值,字符数组1的地址连接的字符数组1必须足够大才可以Strcpy函数:字符串复制,将字符串2复制到字符串1Strcmp函数:字符串比较函数,字符串的比较规则,从左至右,比较每个字符的ASCII码的大小,直到出现不同的字符或者遇到0为止,如果全都一样,则相同,如果不相同,则以第一个不相同的字符的大小的比较结果为准。Strlen函数:字符串长度函数6. 函数6.1 概述每一个大的程序都是由若干个子程序构成的,C语言中,每一个子程序都是由一个函数构成的在程序设计中,常将一些常用的功能模块编写成函数,放在函数库中供公共使用,要善于利用函数,以减少程序重复编写的工作量。1) 一个源程序由一个或者多个函数组成,一个源程序是一个编译单位,即以源程序为单位进行编译,而不是以函数为单位进行编译。2) 一个C语言程序一般是是由多个或者一个源程序组成,对较大的程序,一般不希望全放在一个文件中,而将函数和其他内容(预定义),分别放在若干个源文件,这样分别编写,分别编译,提供调度效率,一个源文件可以为多个C程序调用。3) C程序的执行是从main函数开始的4) 所有函数的定义都是平行的,函数可以互相调用,但不能调用主函数5) 标准函数库,即库函数,可以直接使用的,不同C系统,库函数不一样,用户自己的函数,用以解决用户专门的需要6) 从函数的形式上看,有无参函数,与有参函数6.2 函数的一般定义形式1. 无参定义2. 有参定义3. 空函数6.3 函数参数和函数的值6.3.1 形式参数和实际参数函数定义的时候,在函数名后面的括号中的变量名为形式参数,在主调函数中,调用一个函数,函数名后面的函数为实际参数。1) 形式参数在函数调用的时候,才占用内存,调用完了之后,内存也就释放。2) 调用时,是将实参的值赋给形参,如果形参是数组名,则传递的是首地址,而不是数组的值3) 实参和形参的类型相同,或者兼容赋值4) C语言中,实参变量对形参的数据传递是“值传递”即是单向传递,只有实参传给形参,而不能由形参传回给实参6.3.2 函数的返回值与java类似,不做解释6.4 函数的调用6.4.1 调用的一般形式与java相同,不做解释6.4.2 函数的调用的方式可以作为函数语句可以作为函数表达式可以作为函数参数6.4.3 对被调用函数的声明1. 首先函数要已经存在了,自己定义或者库函数里有2. 使用库函数,要在程序开头#include将有关库函数的信息包含到头文件中3. 如果使用自己定义的函数,而且该函数与主调函数在同一个文件中,一般还应该在主调函数中对被调用的函数作声明。6.5 函数的嵌套使用C语言的函数的平行的,独立的,也就是说在一个函数里可以调用其他函数,但是却嵌套定义函数。6.6 函数的递归调用在调用一个函数的时候,又出现直接或者间接调用这个函数本身,称为函数的递归调用。6.7 数组作为函数参数6.7.1 数组元素作为实参数组元素作为实参的时候和一般的变量是一样的6.7.2 数组名作为函数参数6.8 局部变量和全局变量与java差不多,不做解释6.9变量的存储类别6.9.1 动态存储方式和静态存储方式内存中,供用户使用的存储空间,程序区,静态存储区,动态存储区。全局变量是存储在静态存储区的,从程序开始执行给全局变量分配空间,到程序结束,它们是占据固定的存储单元。动态存储区,根据函数的调用的需要,动态的分配和释放存储地址。6.9.2 auto变量默认的都是6.9.3 用static声明的局部变量有时候希望函数中的局部变量的值在函数调用时,不消失而保留原值,即占用的存储单元不释放,在下一次调用该函数的时候,该变来那个已经有值,而且就是上一次结束的值。则用static声明为局部变量。6.9.4 register变量一般情况下,变量的值是存放在内存中的,当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中,经过运算器进行运算,如果需要存数,再从运算器送回内存中。如果有一些需要频繁使用的变量,上述做法比较浪费时间,为了提高程序效率,C语言允许将局部变量的值放在CPU中的寄存器中,这样比从内存存取变量的速度快很多,这种变量就是寄存器变量用register声明。现在的编译系统很智能,所以基本不用开发人员自己定义寄存器变量。6.9.5 用extern声明的外部变量即是全局变量。作用域从定义除开始,到程序结束。6.9.6 用static声明的外部变量有时候有些程序的某些外部变量不希望其他文件使用,可以使用static声明。6.9.7 声明和定义把建立存储空间的声明,叫做定义,没有建立存储空间的声明为声明6.10 外部函数与内部函数Static内部函数,只能被本文件中使用。Extern外部函数,可以被其他文件使用。7. 预处理命令7.1宏定义7.1.1 不带参数的宏定义#define 标识符 字符串这就是已经介绍过的定义符号常量7.1.2 带参数的宏定义不是简单的字符串替换了,还要进行参数替换。#define 宏名(参数列表) 字符串7.2 文件包含 处理#include将文件包含进来,类似于java的import可以在一个文件中声明许多宏定义,然后其他文件想要使用,只需文件包含即可。文件包含里一般都是头文件,以.h结尾的,当然不用.h结尾,也可以写在里面,但使用了,更能看出是干什么的。7.3 条件编译一般情况下,源程序的所有行都参加编译,但是有时候希望对其中一部分内容只在满足条件才进行编译,也就是对一部分内容指定编译的条件。希望对满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。8. 指针8.1指针与地址的概念首先为了理解指针,要先知道在C中数据在内存中是怎么存储的。又是如何读取的。如果说在程序中定义了一个变量,在编译时就给这个变量分配内存单元,系统根据变量的类型,分配一定的长度的单元,内存区中每一个字节有一个编号,就是地址,例如,一个int型变量,是2个字节,他在内存中分配的存储单元就是两个字节,他所对应的地址,是指他的第一个字节所在地址。由上图可以看出,在C中,对变量进行操作,其实在程序编译后,已经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。这种访问方式,就是直接访问。当然还有另一种访问方式,就是间接访问,我们可以定义一种特殊的变量,叫做指针变量,专门用来存放同类型的变量的地址的。我们定义一个指针变量i_point,假如的他的地址是3001,3002,然后将i的地址存放在这个指针变量中,i_point=&i,i_point的值就是2000,也就是i的首地址,然后我们可以先找到存放i地址的变量,从中取出i的地址,然后再通过地址取出i,这就是间接访问,C中形象的将地址称为指针,意思是通过他能找到以他为地址的存储单元,一个变量的地址称为该变量的“指针”,如果有一个变量专门存放另一个变量的指针,那么这个变量就是指针变量。8.2变量的指针和指向变量的指针变量变量的指针就是变量的地址,存放变量地址的变量是指针变量,用来指向另一个变量,为了表示指针变量和他所指向的变量之间的联系,在程序中用*符号来表示指向。*i_point就是i_point所指向的变量。8.2.1 定义一个指针变量C规定,所有的变量在使用前,都要定义,指定其类型,并按此分配内存单元,指针变量需要指向什么类型的变量,那么就需要定义为什么类型,定义方式如下基本类型 *指针变量名这里之所以要指定类型是因为,不同类型数据的字节是不一样的,当我们在操作指针运算和指针移动的时候,如果指针指向的是整型,那么指针移动1,意味着移动了两个字节,指针加1,意味着地址加两节个字节,所以对于指向不同类型的指针变量,必须要说明其类型。这里*号的意思是指定义此变量为指针变量。8.2.2 指针变量的引用需要牢记的是,指针变量只能存放地址,不同将整型量或者其他任何非地址的数据赋值给一个指针变量。1. &运算符,取地址运算符2. *运算符,指针运算符,间接访问运算符&a意思是取a的地址,*p为指针变量p所指向的存储单元&*运算级相同,按照自右向左,8.2.3 指针变量做函数函数的参数不仅可以是基本类型,也可以是指针变量。作用是将一个变量的地址传入另一个函数中。这样做的操作可以到达一个效果,就是将传入的实参通过形参就可以改变其值,不用将形参返回给实参。8.3 数组的指针和指向数组的指针变量所谓的数组的指针是指数值的起始地址,数组元素的指针是数组元素的地址。引用数组元素可以使用下标法,也可以使用指针法。8.3.1 指向数组元素的指针指向数组元素的指针与指向变量的指针相同,无大区别。C语言规定数组名代表数组的首地址,也就是第0号元素的地址。Int *p=a0与int *p=a等价,都是将数组的首地址赋值给了指针变量上述写法与int *p p=a0 p=a,也是等价的8.3.2 通过指针引用数组元素如果已经有int *p=a,a是一个数组那么p+1,意思是指向同一个数组中的下一个元素,而不是简单的将p加1。对于上面这个程序,需要注意一下,在第一个循环的时候,p已经指向a的最后一个元素地址了,那么第二个循环的时候,是无法输出正常情况的。8.3.3 数组名做函数参数这里以数组名作为实参,当用数组名做参数时,形参各值发生变化,实参数组元素随时发生变化。原因就是因为,数组名是代表的数组首地址,调用函数的时候,是将数组的首地址传送给形参,但实际上能够接受并存放地址值的只能是指针变量,因此,C编译系统是将形参数组名作为指针变量来处理的。相当于在编译时是将arr按指针变量处理的,f(int *arr,int n)与上诉写法是等价的,在调用该函数的时候,系统会建立一个指针变量arr,用来存放从主调函数传递过来的实参数组首地址,如果在f函数中使用sizeof来测定其所占字节,可以得到是2个字节。对C比较熟悉的人往往喜欢用指针变量做形参。总结归纳一哈:通过对X值的改变,可以使X指向数组a的任何一个元素发送改变。这样也是可以的,8.3.4 指向多维数组的指针或者指针变量1. 多维数组的指针为了说清楚多维数组的指针,先要想一哈多维数组的性质,假如一个二维数组,它有3行4列,Int a34 = 1,2,3,41,1,1,11,1,1,1这里的a是一个数组名,他包含3个行,即三个元素,a0,a1,a2,而每一个元素又是一个一维数组,他包含4个元素,从整个二维数组来看,a代表整个二维数组的首地址,也就是第0行的首地址,a+1代表第一行的首地址,如果a的首地址是2000,那么a+1就是代表2008,a+1的含义是a1的地址,这里a0,a1,a2是一维数组名,数组名的意思就是数组的首地址,因此a0代表第0行一维数组中第0列元素的首地址,即是&a00,a1则是&a10,a2则是&a10,那么第0行第1列的元素的地址怎么表示呢,a0+1即可,就是把a0看作是一个一维数组名即可,a0+1与&a01等价。还有一个等价,a1和*(a+1),这个等价,相等容易搞混,一定要记住。因为a是第0行首地址,a+1是第1行的首地址,*(a+1)就相当于是第1行第0列的地址,所以其值是一样的。进一步解释一哈,在一维数组中ai代表a数组第i个元素所占的内存单元,ai是有物理地址的,是占内存单元的。但如果a是二维数组,则ai是代表一维数组名,ai并不占实际的内存单元,它也不存放a数组中各个元素,它只是一个地址,a,a+i,ai,*(a+i)都是他的地址。2. 指向多维数组的指针变量指向由m个元素组成的一维数组的指针变量用p指向一个包含m个元素的一维数组,这时,如果p先指向a0,(即p=&a0),则p+1,就不是指向a01,而是指向a10,增值的方式以一维数组的长度为单位程序中int (*p)4表示的是指针变量,它指向的是包含4个元素的一维数组,而且,注意p两边的括号不能少。有时容易和另一个混淆,*(p+2)是第2行的首地址,而p+2也是第2行的首地址,*(p+2)+3能否写成(p+2)+3,这里显然是不行的,(p+2)+3的意思就成了第5行的首地址了,而*(p+2)+3中*(p+2)是指第2行首地址指向第2行第0列,这里的3就是p所指的一维数组内部各元素的长度了。3. 多维数组的指针做函数参数主要是两种,一个就是指向变量的指针变量,一个就是指向一维数组的指针变量当用第一种方式,想要指定多维数组里的具体元素个数时,就需要*(p+i*m+j)来指向,i是第几行,m是每行共有多少列,j是多少第几列。而第二种方式,指向就是一维数组,可以方便锁定访问第几行第几列。*(*(p+i)+j)容易混淆的地方,假如arr是一个二维数组,那么arr指的是arr的首地址,是首行地址,含义为行,而*arr,即是arr0,8.4 字符串的指针和指向字符串的指针变量在C中有两种形式访问字符串,8.4.1 字符串的访问形式用字符数组存放一个字符串,然后输出该字符串。还有一个就是用字符指针指向一个字符串,可以不定义字符数组,而定义一个字符指针,用字符指针指向字符串中的字符。在这里没有定义字符数组,而是定义了一个字符指针,给定赋值一个字符串常量,C语言对字符串常量是按字符数组处理的,在内存开辟了一个字符数组用来存放字符串常量。这两行是等价的,这很重要程序在定义字符指针变量string时把字符串首地址(即存放字符串的字符数组的首地址)赋给string。String是一个指针变量,指向字符类型。所以只能存放地址,而只能指向一个字符类型数据,所以只能字符数据类型的地址。%s表示输出一个字符串,指定遇到字符串结束标识符0才停止输出。8.4.2 字符串指针做函数参数将一个字符串从一个函数传递到另一个函数,可以用地址传递的方法,即用字符数组名作参数或者用指向字符串的指针变量做参数,在被调用的函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。8.4.3 对使用字符指针变量和字符数组的讨论1. 字符数组由若干个元素构成,每一个元素存放一个字符,而字符指针变量存放的是地址,决不是将字符串放到字符指针变量中2. 赋值方式,对字符数组只能对各个元素赋值,不能像下面这样赋值只能是定义的时候,str=”sunlandong”但是,字符指针可以,所以综合来说,指针变量指向字符串的方式更为方便简单一些8.5 函数的指针和指向函数的指针变量8.5.1 用函数指针变量调用函数可以用指针变量指向整型变量,字符串,数组,也可以指向一个函数,一个函数在编译时候被分配给一个入口地址,这个入口地址就称为函数的指针,可以用一个指针变量指向函数,然后通过该指针变量调用此函数。Int (*p)()定义就是一个指向函数的指针变量。并且此函数带回整型的返回值。注意*p两侧的括号不能省略。表示p先与*结合,是指针变量,然后再与后面的()结合,表示此指针变量指向函数,这个函数值,(即函数返回值)是整型的,如果写成int *p()就成了声明了一个函数,函数的返回值是一个指向整型变量的指针。函数名代表是函数的入口地址,就是相当于首地址。可以通过函数指针调用函数,也可以通过函数名调用(*p)()表示一个指向函数的指针变量,它不是固定指向哪一个,而是说定义了这样一个变量,它是专门用来存放函数的入口地址,在程序中把那一个函数的地址给它,它就指向哪一个函数,在一个程序中,一个指向变量可以先后指向不同的函数。再给函数指针变量赋值时,只需给出函数名,不用给出参数。在调用的时候,只需将(*p)当作是平常的函数名,然后进行调用就可以了,对指向函数的指针变量,p+1,p+n这些运算是没有意义的。8.5.2 用指向函数的指针做函数参数函数指针变量常用的用途之一是把指针作为参数传递到其他函数,这个问题是C语言比较深入的地方了,注意重点学习。以前遇到过函数的参数是指针变量,数组名,指向数组的指针变量,现在看一下指向函数的指针也可以作为参数,以便实现函数地址的传递。这里用函数指针变量作为形参的一个好处是,如果只是单纯的一次调用f1,f2,这是没有区别的,但是如果调用的函数不是固定的,这次调用的是f1,f2,下次就是f3,f4,再下次就是f5,f6,这时,用指针变量就比较方便了,只要在每次调用sub函数时给出不同的函数名作为实参,sub不必做任何修改,这种方法是符合结构化程序设计方法原则的,是程序设计中常使用的。对作为实参的函数,应在主调函数中用函数原型做函数声明,原来说过,对本文件中的整型函数可以不加说明就可以调用,是的,但那只是限于函数调用的情况,函数调用的时候在函数名后面的括号和实参,编译的时候根据形式判断它为函数,而当函数名作为实参的时候,编译系统无法判断它是变量名还是函数名,故应该先声明。8.6 返回指针值的函数一个函数可以带回一个整型值,字符值,实型值,也可以带回指针类型的数据,即地址,其概念与以前类似,只是带回的值的类型是指针类型而已。这种带回指针类型的函数一般定义为:类型吗 *函数名(参数列表)分析一下这个例子:Float *search(float(*pointer)4,int n)返回指针值的函数,该指针函数指向实型,第一个参数是指向一个实型含有4个元素的一维数组,p是一个指向实型的指针变量,search赋值给p函数里,先将socre的首地址传给pointer,指向第0行,然后*(pointer+n)的就是相当于第1行第0列的地址,赋值给pt,*pt就相当于第1行第0列的元素。返回回去给了p,那么p+1,就是第1行下一列元素的地址,以此来输出了第1行的4个元素。如果将*(pointer+n)改成了(*pointer+n),那么pointer接收了socre,相当于是第0行的首地址,那么*pointer就是

温馨提示

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

评论

0/150

提交评论