第一部分 数组在 C程序中声明一个变量,只能用于存储一个数据。
有时程序中需要存放一组数据,这就需要声明一个数组。
数组,数组必须 先定义,后使用 。最常用的是二维以下的数组,尤其是一维数组。
一维数组的定义和初始化
定义格式,
元素类型名 数组名 [常量表达式 ]
说明,
(1) 元素类型名指定该数组各元素的数据类型。
(2) 用方括号 []括起来的常量表达式的值表示该数组含数组元素的个数,即数组长度。
注意:引用时,数组元素的下标从 0开始 。
如,
int m[20];
表示整型数组 m有 20个元素,m[0],m[1]…,m[19]。
float x [10];
表示实型数组 x有 10个元素,x[0],x[1],… x[9]。
一维数组元素的引用
数组元素的引用格式,
数组名 [下标 ]
( 1)下标为整型表达式,它确定了引用元素的序号
( 2)下标从 0开始编号,最大等于定义的数组长度减 1
在程序中数组元素等价于一个同类型的变量。
注意:数组引用时千万不得越界。
例如:
void main()
{ int m[10]={1,2,3,4,5,6,7,8,9,0};
m[9]=m[3]*6; /* 正确,m[9]的值为 24 */
m[6]=m[10]; /* 不正确,m[10]下标越界 */
printf ( "%d %d %d %d\n",m[4],m[5],m[6],m[9]);
}
给数组元素读值、输出、处理的方法通常采用 循环结构 实现,循环控制变量作为数组下标,对数组元素逐个进行操作。
例如:将数组 m的十个元素输出
for (i=0;i<10;i++)
printf(“%4d”,m[i]);
将十个数据从键盘输入存入数组 m中
for(i=0;i<10;i++)
scanf(“%d”,&m[i]);
注意:数组 m的输入输出这样做是错误的
scanf(“%d”,m);
printf (“%d”,m);
使用数组的常见错误是下标越界,对于这种错误 C的编译系统不检测错误,也没有警告,但结果往往不正确。
例 1:输入十个整数,选择出其中的最大数。
( 1)将最大数存放在一个整型变量 max中;
( 2)将最大数放在数组的最前端。
(注意:不能将原来数组的第一个元素覆盖)
#include <stdio.h>
void main()
{int i,a[10],max;
printf("input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
max=a[0];
for(i=1;i<10;i++)
if(a[i]>max) max=a[i];
printf("max number is %d",max);
}
( 1)
#include <stdio.h>
void main()
{int i,a[10],t;
printf("input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=1;i<10;i++)
if(a[i]>a[0])
{t=a[i];
a[i]=a[0];
a[0]=t;}
printf("max number is %d",a[0]);
}
( 2)
例 2:输入十个整数,按照从大到小的顺序排列。
排序基本思想:
从全部 10个数中选出最大的,将其放在最前端;
从第 2-10个数中选出最大的,将其放在第二位置;
从第 3-10个数中选出最大的,将其放在第三位置;
……………
从第 9-10个数中选出最大的,将其放在第 9个位置;
#include <stdio.h>
void main()
{int i,j,a[10],t;
printf("input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<9;i++)
for(j=i+1;j<10;j++)
if(a[j]>a[i])
{t=a[i];
a[i]=a[j];
a[j]=t;}
printf("from big to small:\n");
for(i=0;i<10;i++)
printf(" %4d",a[i]);
}
第二部分 函数模块化程序设计
基本思想:将一个大的程序按功能分割成一些小模块,
特点:
– 各模块相对独立、功能单一、结构清晰、接口简单
– 控制了程序设计的复杂性
– 提高软件的可靠性
– 缩短开发周期
– 避免程序开发的重复劳动
– 易于维护和功能扩充
开发方法,自上向下,逐步分解,分而治之函数分类从用户角度
– 标准函数(库函数):由系统提供
– 用户自定义函数在程序中要调用某个库函数,则要用预处理命令 #include将该函数所在的头文件包含到程序中用户自定义函数的定义与调用
1.函数定义类型说明 函数名(含类型说明的形式参数表)
{
说明部分执行部分
}
int add(int x,int y)
{
int z;
z=x+y;
return(z);
}
例,输入两个正整数 m,n( m>n),计算从 m个元素中任取 n个元素的组合数。计算公式为:
long fac(int x)
{ int i;
long f =1;
for(i=1;i<=x;i++) f=f*i;
return (f);
}
在该问题的求解中,需要三次计算阶乘值:如果有一个函数可以提供求阶乘的功能,调用三次就可以解决问题了。可以自行编写求阶乘的函数。
函数编写如下:
)!(!
!
mnn
mC n
m
主调函数与被调函数
main函数是一个程序的执行入口程序的执行是从 main函数开始的其它函数必须由 main函数调用才能得到执行。
main
a b c
d e f
函数调用关系示意图
函数值的返回在函数体中,对形式参数接收的数据进行具体操作,
并应该在函数体的最后将处理结果返回给主调函数。返回处理结果必须采用 return语句完成。
return语句的形式:
return (表达式 );
或 return 表达式;
return语句执行后,程序将退出被调函数,被调函数携带函数值返回主调函数,在主调函数中继续执行。
int add(int x,int y)
{ int z;
z=x+y;
return(z);
}
2.函数调用函数调用是使函数实际执行的过程。
格式:
函数名(实在参数表)
long fac(int x); /* 函数原型说明 */
void main()
{ int m,n,c;
printf("input m,n:");
scanf("%d%d",&m,&n);
if (m>n)
{ c=fac(m)/(fac(n)*fac(m-n));
printf("c(%d,%d)=%d\n",m,n,c);
}
else printf("input data error\n");
}
函数的调用过程函数调用过程是使函数得到执行的过程,有以下步骤:
( 1) 根据函数名找到被调函数,若没找到,系统将报告出错信息。
( 2) 计算实在参数的值。
( 3) 将实在参数的值传递给形式参数。
( 4) 中断在主调函数中的执行,转到被调函数的函数体中开始执行。
( 5) 遇到 return语句或函数结束的花括号时,返回主调函数。
( 6) 从主调函数的中断处继续执行
参数的结合问题在函数调用时,将实参值传给对应的形参注意
( 1)实参的个数和形参的 个数应该相等
( 2)实参与形参的应该在 顺序上一一对应,
( 3)实参的类型一般应该与对应形参的 类型相同
( 4) C语言中实参与形参的结合是一种 传值方式将实参的值拷贝一份传递给对应的形参
( 5)如形参的值发生改变,不影响实参的值 。
第三部分 结构体
1 结构体的引入存放一个班学生的成绩可以定义数组,但是如果要存放一个同学的学号、性别、姓名、成绩等信息,如何定义数据类型。
常常把这些关系密切但类型不同的数据项组织在一起,
即,封装,起来,并为其取一个名字,在 C语言中,就称其为结构体(有些高级语言称之为记录)。所以,结构体通常是由不同数据类型的成员组成,
结构体的引入为处理复杂的数据结构提供了有力的手段。
2 结构体类型的定义结构体类型属于用户自定义类型,必须先定义后使用 。
结构体类型定义的一般格式,
struct 结构体名
{
结构体成员表 ;
};
注:大括号中的结构体成员表包含若干成员,每一个成员都具有如下的定义形式,
数据类型标识符 成员名;
例如:对一个学生的描述,其结构体类型定义如下:
struct stud_type
{
long num; /* 学号 */
char sex; /* 性别 */
char name[10]; /* 姓名 */
float score; /*成绩 */
};
3 结构体变量的引用在 C语言程序中,不准许对结构变量 整体 进行输入输出等操作,而只能分别对其各个成员进行此类操作。
引用结构体变量成员的一般形式:
结构体变量名,成员名例如:
struct stud_type student1,student2;
student1.num=196103;
student1.sex='m';
strcpy(student1.name,"wang“);
student1.score=98;
printf(“%ld %c %d %s”,student1.num,student1.sex,
student1.score,student1.name);
5 结构体数组
结构体数组的定义定义如下:
struct stud_type
{long num;
char sex;
char name[10];
float score;
};
struct stud_type student[3];
由此就定义了一个结构体数组 student,它有 3个元素,每个元素都是 struct stud_type类型。
student[0]
student[1]
name
num
sex
score
num
sex
name
score

注意,不能把结构体数组元素作为一个整体直接进行输入或输出。
如 printf ("%d",student[0]);
或 scanf("%d",&student[0]);
只能以单个成员为对象进行输入输出,如:
scanf("%s %ld ",student[0].name,& student[0].num);
printf ("%s%ld\n",student[0].name,student[0].num);
例:从键盘输入 10名学生信息,每个学生有姓名、学号、
成绩,要求按学生成绩降序排列,并输出学生成绩排行榜。
#define N 10
#include<string.h>
struct stud_type
{ char name[10];
int num;
int score;
};
void main()
{ int i,j,k;
struct stud_type stu[N],t;
printf("\n请输入 %d 个学生的姓名 学号 成绩 \n",N);
for(i=0;i<N;i++)
scanf("%s%d%d",stu[i].name,&stu[i].num,&stu[i].score);
/* 对学生信息按照成绩进行排序 */
printf("排序结果如下 \n");
for(i=0;i<N;i++)
printf("%s%5d %5d\n",stu[i].name,stu[i].num,stu [i].score);
}
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
if(stu[j].score>stu[i].score)
{t=stu[i];
stu[i]=stu[j];
stu[j]=t;
}
}
注,结构体变量整体可以相互赋值,但注意相互赋值的两个结构体变量必须是同一个结构体类型,
/* 对学生信息按照成绩进行排序 */
第四部分 指针存储地址的数据类型就是指针类型能直接对内存单元通过地址进行操作学习时应特别细心,多动脑、多对比、多上机程序中,int i;
float k;
内存中每个字节有一个编号 -----地址
…...
…...
2000
2001
2002
2005
内存
0
2003
i
k 编译或函数调用时为其分配内存单元变量 是对程序中数据存储空间的抽象
…...
…...
2000
2004
2006
2005
变量 a
10
变量 p
2001
2002
2003
指针:一个变量的地址指针变量:专门存放变量地址的变量叫指针变量
2000
指针指针变量变量的 内容变量的 地址整型变量一,指针变量的定义与引用定义格式,
基类型名 *指针变量名 ;
char *p1; int *p2; float *p3;
指针变量赋值 int i,*i_point;
i_point=&i;
指针变量的引用 *i_point=1;
两个与指针有关的运算符
&:取地址运算符,取其右边变量的地址。
如,&a 取变量 a的地址。
*:指向运算符 (“间接访问,运算符 )
访问右边指针变量所指向的变量。
如,*p 是指针变量 p所指向的变量。
i=1;等价于直接访问与间接访问直接访问:按变量名存取变量值间接访问:通过存放变量地址的变量去访问变量例 i=3; -----直接访问指针变量
…...
…...
2000
2004
2006
2005
整型变量 i
10
变量 i_pointer
2001
2002
2003
2000
3
例 *i_pointer=20; -----间接访问
20
前提条件 i_pointer=&i;
空指针
– 定义,指针变量值为零
– 表示,int * p=0;
p指向地址为 0的单元,
系统保证该单元不作它用表示指针变量值 没有意义
#define NULL 0
int *p=NULL:
– 用途,避免指针变量的非法引用在程序中常作为 状态 比较例 int *p;
......
while(p!=NULL)
{,..…
}
例 main( )
{ int i=10;
int *p;
*p=i;
printf(“%d”,*p);
}
危险!
例 main( )
{ int i=10,k;
int *p;
p=&k;
*p=i;
printf(“%d”,*p);
}
注意:指针变量必须先赋值,再使用。即不能使用盲指针。
…...
…...
2000
2004
2006
2005
整型变量 i
10
指针变量 p
2001
2002
2003
随机注意,
(1) 指针变量定义和引用时,*” 含义有差别。
在引用中,*” 是 运算符,。
表示指针变量指向的变量。
在指针变量定义时,*” 理解为指针类型 定义符表示定义的变量是指针变量。
(2) 不能引用没有赋值的指针变量 。( 盲指针 )
(3) p=&a;是给指针变量 p赋值 。
*p=3; 是给 p指向的变量赋值。
两者含义完全不同。
(4) 指针变量只能存放地址 。
不能直接用整型量 (或非地址量 )赋值给指针变量。
#include<stdio.h>
void swap(int *p1,int *p2);
void main()
{ int x,y;
printf("Input x,y,");
scanf("%d %d",&x,&y);
if(x>y) swap(&x,&y);
printf(“sorted,%d %d \n",x,y);
}
void swap(int *p1,int *p2)
{ int p;
p=*p1;
*p1=*p2;
*p2=p;
}
二,函数中用指针变量作形参通过形参指针对主函数中的变量进行间接引用。
三,用数组名作函数参数。
数组名代表该数组 下标为 0的 元素地址(数组首地址)
例:通过调用一个函数,将整型数组的所有元素加 10。
程序如下,
#include<stdio.h>
void add(int b[ ],int n)
{ int i;
for(i=0; i<n; i++) b[i]+=10;
}
void main( )
{ int i,a[10]= {1,2,3,4,5,6,7,8,9,10};
add(a,10);
for(i=0; i<10; i++) printf("%4d",a[i]);
}