第0章C语言程序设计_第1页
第0章C语言程序设计_第2页
第0章C语言程序设计_第3页
第0章C语言程序设计_第4页
第0章C语言程序设计_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

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

文档简介

第0章C语言程序设计数据结构C程序结构如下图所示。即一个C程序可以由若干个源程序文件(分别进行编译的文件模块)组成,一个源文件可以由若干个函数和预处理命令以及全局变量声明部分组成。一个函数由数据定义部分和执行语句组成。C程序的结构即、C源程序文件的结构一般如下:预处理命令全局变量声明函数1

函数2...

函数n

主函数其中,函数分为库函数和用户自定义函数两大类。库函数也称作系统函数,是包括在高级语言软件中的提供基础功能的函数。用户自定义函数是软件开发者根据所处理的特定问题设计的提供特定功能的函数。在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?(1)首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)。但光有这一条件还不够。(2)如果使用库函数,一般还应该在本文件开头用#include命令将调用有关库函数时所需用到的信息“包含”到本文件中来。

例如,#include<stdio.h>其中“studio.h”是一个“头文件”。在stdio.h文件中放了输入输出库函数所用到的一些宏定义信息。如果不包含“stdio.h”文件中的信息,就无法使用输入输出库中的函数。同样,使用数学库中的函数,应该用

#include<math.h>C头文件一览

#include<assert.h>

//设定插入点

#include<ctype.h>

//字符处理

#include<errno.h>

//定义错误码

#include<float.h>

//浮点数处理

#include<fstream.h>

//文件输入/输出

#include<iomanip.h>

//参数化输入/输出

#include<iostream.h>

//数据流输入/输出

#include<limits.h>

//定义各种数据类型最值常量

#include<locale.h>

//定义本地化函数

#include<math.h>

//定义数学函数

#include<stdio.h>

//定义输入/输出函数

#include<stdlib.h>

//定义杂项函数及内存分配函数

#include<string.h>

//字符串处理

#include<strstrea.h>

//基于数组的输入/输出

#include<time.h>

//定义关于时间的函数

#include<wchar.h>

//宽字符处理及输入/输出

#include<wctype.h>

//宽字符分类类型标识符函数名(数据类型参数1,……,数据类型参数n){声明部分语句}例如:int

max(int

x,inty){

int

z;/*函数体中的声明部分*/

z=x>y?x∶y;

return(z);}函数在调用函数时,大多数情况下,主调函数和被调用函数之间有数据传递关系。这就是前面提到的有参函数。形式参数:在定义函数时函数名后面括弧中的变量名称为"形式参数"(简称"形参"),实际参数:在主调函数中调用一个函数时,函数名后面括弧中的参数(可以是一个表达式)称为"实际参数"(简称"实参")。返回值通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。下面对函数返回值作一些说明:(1)函数的返回值是通过函数中的return语句获得的。return语句将被调用函数中的一个确定值带回主调函数中去。一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个语句起作用。return语句后面的括弧也可以不要,如returnz;它与"return(z);"等价。return后面的值可以是一个表达式。例如,例8.2中的函数max可以改写如下:

max(int

x,inty)

{

return(x>y?x∶y);

}这样的函数体更为简短,只用一个return语句就把求值和返回都解决了。(2)

函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。例如:int

max(float

x,floaty)/*函数值为整型*/charletter(charc1,charc2)/*函数值为字符型*/doublemin(int

x,inty)/*函数值为双精度型*/在定义函数时对函数值说明的类型一般应该和return语句中的表达式类型一致。(3)如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。(4)如果被调用函数中没有return语句,并不带回一个确定的、用户所希望得到的函数值,但实际上,函数并不是不带回值,而只是不带回有用的值,带回的是一个不确定的值。(5)为了明确表示"不带回值",可以用"void"定义"无类型"(或称"空类型")。例如,例8.1中的定义可以改为voidprintstar(){…}voidprint-message(){…}例0-1设计一个从两个大整数类型的数据中得到较大数值的函数,并设计一个主函数调用该函数。#include<stdio.h>typedeffloatDataType;DataTypeMax3(DataTypex1,DataTypex2){if(x1>=x2)returnx1;elsereturnx2;}voidmain(void){

DataTypet1=5.1,t2=8.8,max;max=Max3(t1,t2);

printf("Max=%f\n",max);max=Max3(t2,t1);

printf("Max=%f\n",max);}输入型参数输入型参数是指调用函数只通过该参数传递数据给被调用函数。由于调用函数只向被调用函数传递数据,所以称为输入型参数。比如,例0-1中Max3()函数中的两个形式参数x1,x2都是输入型参数。55形参x1实参t1调用函数时5形参x1实参t1调用结束时输出型参数输出型参数是指调用函数只通过该参数把被调用函数处理后得到的结果传送给调用函数。由于这样的参数数据是离开被调用函数的,所以称为输出型参数。#include<stdio.h>voidMax2(intx1,intx2,intx3,int*y1,int*y2)/*输出参数y1和y2设计为指针类型*/{if(x1>=x2&&x1>=x3){*y1=x1;if(x2>=x3)*y2=x2;else*y2=x3;}if(x1>=x2&&x1<x3){*y1=x3;if(x1>=x2)*y2=x1;else*y2=x2;}if(x1<x2&&x2>=x3){*y1=x2;if(x1>=x3)*y2=x1;else*y2=x3;}例0-2设计一个从三个整数中得到最大值和次大值的函数if(x1<x2&&x2<x3){*y1=x3;if(x1>=x2)*y2=x1;else*y2=x2;}}voidmain(void){intv1=5,v2=9,v3=7,f1,f2;Max2(v1,v2,v3,&f1,&f2);

/*&f1表示f1的地址,为指针类型*/printf("f1=%df2=%d\n",f1,f2);}形参y1实参f1调用函数时形参y1实参f1调用结束时f1f1输出型参数写程序时自己定义的数据类型称作“用户定义类型”。形式:typedef

类型名

标识符;typedef的作用仅仅是用新类型名来代表已存在的类型名,并未产生新的数据类型。原有的类型名依然有效。

新的类型名可以和C语言中原有的各种基本类名一样,方便地用于定义变量、定义函数的返回值、定义其它构造类型的元素或成员。

例1:typedef

intINTEGER;给int类型一个新的名字INTEGER,此后,可以用INTEGER来定义整型变量。如:INTEGERi,j,a[10];类型定义

例2:typedefchar*CHARP;

新类型名CHARP是字符指针类型,表示的旧类型是char*。

CHARPp;

等价于:char*p;例3:typedefdoubleVECT[4];

定义一种具有4个元素的双精度数组类型VECT;程序中VECTv1,v2;定义两个4个元素的双精度数组。定义新类型的步骤:

首先按通常定义变量的方法写出定义的主体;如:

double*f;(2)将变量名换成新类型名;

double*PDOUBLE;(3)在最前面加上关键字typedef;

typedefdouble*PDOUBLE;(4)可以用新类型定义变量了;

PDOUBLEf1,f2;结构体可以将若干个不同类型的数据组合成一个复合数据对象。组成结构体的数据项称结构体的成分或成员。结构体类型成员的数量必须固定,但该结构体中各个成员的类型可以不同。一、结构体类型说明、结构体变量定义

1结构体类型说明

struct

结构体名{成员说明序列};

结构体名是结构体类型说明的标志,如果所定义的结构体类型,在程序中很少使用,可以省略结构体名,在说明类型的同时定义结构体变量;如果所定义的结构体类型,在程序中要多次使用,应该使用结构体名说明结构类型,以后在程序需要该结构体类型的地方,用“struct

结构体名”的形式代表整个说明。相当于一个类型名。

结构体

例日期可以用包含三个成员的结构体来描述:

structdate{intyear,month,day;};学生信息的结构体类型可说明如下:

structstudent{charname[15];charsex;

structdatebirthday;floatscore[4];};其中structdate是一个已说明过的结构体类型名。2结构体变量定义

结构体变量定义有4种方法:(1)直接定义结构体类型变量,将一个结构体说明当成类型描述,在它后面列出变量标识符。这种表示方法没有结构体名,定义形式如下:struct{成员说明序列}结构体变量表;例:struct

{charname[10];

intage;

intclass;}stu1,stu2[5],*stu3;intstu1,stu2[5],*stu3;它类似于:(2)声明类型同时,定义结构体变量struct

结构体名{成员说明序列}结构体变量表;例:structpoint{doublex,y,z;}p1,p2,*p3;说明结构体类型point,并定义三个变量。

(3)使用已声明的结构体类型,定义结构体变量struct

结构体类型名

结构体变量表;例:使用上面的例子中说明的structpoint。

structpointp1,p2[5],*p3;(4)定义结构体类型,再定义结构体变量

typedef

struct{成员说明序列}结构体类型名;结构体类型名结构体变量表;3结构体的实现

C语言为结构体对象分配足够大的存储空间,顺序地放入各个成员,但具体的存储位置,由一组对齐规则来调整,结构体里的成员未必一个紧接着一个存放,它们之间可能有空位。结构体类型和结构体变量的空间计算:sizeof运算符:sizeof(<已定义的数据类型>)结构体名二、结构体变量的初始化和使用

1结构体变量的初始化

可以在定义的同时初始化,使用{}将变量的成员的初始化值组合起来。如

structpoint{doublex,y;}p1={1.5,4.6},p[3]={{1.5,2.5},{3.4,2.4},{8.6,9.0}};初始化描述中的初始值将顺序提供给结构变量的各基本成员,初始化表达式只能是可静态求值的表达式。给出的初始化数据与结构成员类型一致,个数不得多于成员数量,如果提供的数据项不够,与数组的规定一样,其余成员自动用0初始化。如果定义时没有提供初始值,系统对结构变量的处理方式与其它变量一样。外部和全局变量,用0初始化,自动变量不进行初始化,各成员的状态不确定。

2结构体变量操作

(1).整体赋值:同样类型的结构体变量,可整体进行相互赋值。(2).结构体成员引用成员运算符:两个运算符“.”和“->”优先级:与圆括号、下标运算符相同,在C的运算符中优先级最高结合方式:自左向右结构体中简单变量成员的引用形式有下面三种:(1)结构体变量名.成员名

(名字引用)(2)结构体指针->成员名

(指针引用)(3)(*结构体指针).成员名

(将指针转化为名字应用)3.对结构体成员进行操作结构体变量中的每一个成员都属于某个具体的类型,可以象普通变量一样,对它进行同类变量所允许的任何操作。例:structdate{intyear,month,day;};

structstudent{charname[15];charsex;

structdatebirthday;floatscore[4];}stu1,stu2;

scanf(“%s”,);strcpy(,”Zhangyang”);scanf(“%c”,&stu1.sex);stu1.sex=’M’;stu1.birthday.year=1963;scanf(“%d”,&stu1.birthday.year);三、结构体与函数(1)向函数传递结构体变量的成员C语言函数实参、形参传递数据只有值传递,结构体变量的成员可以是简单变量、数组或指针变量等,作为成员变量,可以参与其类型允许的任何操作,这个原则也适用于参数传递结构体变量中的每一个成员都属于某个具体的类型,可以象普通变量一样,对它进行同类变量所允许的任何操作。(2)向函数传递结构体变量

把结构体变量作为一个整体传递给函数,要求函数的形参也属于相同的结构体类型。这时传递的是实参结构体变量的值,系统将为相同结构类型体的形参开辟相应的存储单元,并将实参中各成员的值赋给对应的形参成员。

(3)传递结构体的地址

结构体指针做函数实参,对应形参应该是一个基类型相同的结构指针。讨论结构体地址作为函数参数的好处四、结构体指针与链表链表的特点是将数据存储在位置任意的结构体存储块中,用结构体指针将这些存储块连接在一起,从第一个存储块顺着指针可以访问到所有的数据。链表中的每一个存储块叫一个结点。实现链表需要使用结构体指针和动态存储管理机制。链表示意:链表实现结点类型构造的讨论:指向本结点类型的指针是实现链表的基础structnode{intdata;

structnode*next;};

动态内存分配一、为什么用动态内存分配在我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组。比如说我们要存储一个班级学生的某科分数,总是定义一个float型数组:floatscore[30];但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?

在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道该班级的学生的人数,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道该班级的学生数,但是如果因为某种特殊原因人数有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。那么有没有其它的方法来解决这样的外呢体呢?有,那就是动态内存分配。所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点:1、不需要预先分配存储空间;2、分配的空间可以根据程序的需要扩大或缩小。二、如何实现动态内存分配及其管理要实现根据程序的需要动态分配存储空间,就必须用到以下几个函数1、malloc函数

malloc函数的原型为:void*malloc(unsignedintsize)其作用是:在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作。下例是一个动态分配的程序:#include<stdlib.h>main(){

intcount,*array;/*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/

if((array=(int*)malloc(10*sizeof(int))

)==NULL)

{

printf("不能成功分配存储空间。");

exit(1);

}

for(count=0;count〈10;count++)/*给数组赋值*/

array[count]=count;

for(count=0;count〈10;count++)/*打印数组元素*/

printf("%2d",array[count]);}上例中动态分配了10个整型存储区域,然后进行赋值并打印。例中if((array=(int*)malloc(10*sizeof(int)))==NULL)语句可以分为以下几步:1)分配10个整型的连续存储空间,并返回一个指向其起始地址的整型指针2)把此整型指针地址赋给array3)检测返回值是否为NULL2、f

温馨提示

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

评论

0/150

提交评论