标题:
C基础教程 第六章 数 组
[打印本页]
作者:
苹果也疯狂
时间:
2011-10-21 12:10
标题:
C基础教程 第六章 数 组
为了解决比较复杂的问题,本章介绍
C
语言提供的一种最简单的构造类型──数组。
6.1
1
维数组的定义和引用
6.1.1
1
维数组的定义
6.1.2
1
维数组元素的引用
6.1.3
1
维数组元素的初始化
6.1.4
1
维数组应用举例
6.1.1
1
维数组的定义
[
案例
6.1]
从键盘上任意输入
10
个整数,要求按从小到大的顺序在屏幕上显示出来。
排序的方法有很多,本题采用冒泡法。
冒泡法的基本思想:通过相邻两个数之间的比较和交换,使排序码(数值)较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部。就像水底的气泡一样逐渐向上冒,故而得名。
由
A[n]~A[1]
组成的
n
个数据,进行冒泡排序的过程可以描述为:
(
1
)首先将相邻的
A[n]
与
A[n-1]
进行比较,如果
A[n]
的值小于
A[n-1]
的值,则交换两者的位置,使较小的上浮,较大的下沉;接着比较
A[n-1]
与
A[n-2]
,同样使小的上浮,大的下沉。依此类推,直到比较完
A[2]
和
A[1]
后,
A[1]
为具有最小排序码(数值)的元素,称第一趟排序结束。
/*
冒泡法排序
*/
for(i=0; i<NUM-1; i++)
/*
外循环:控制比较趟数
*/
for(j=NUM-1; j>i; j--)
/*
内循环:进行每趟比较
*/
if(data[j]<data[j-1])
/*
如果
data[j]
大于
data[j-1],
交换两者的位置
*/
{temp=data[j];
data[j]=data[j-1];
data[j-1]=temp;
};
/*
输出排序后的数据
*/
printf("\nthe
result ofsort:\n");
for(i=0; i<NUM; i++)
printf("%d ",data
);
getch();
/*
等待键盘输入任一字符,目的使程序暂停
*/
}
[
程序演示
]
(
2
)
然后在
A[n]~A[2]
区间内,进行第二趟排序,使剩余元素中排序码最小的元素上浮到
A[2]
;重复进行
n-1
趟后,整个排序过程结束。
/*
案例代码文件名:
AL6_1.C*/
/*
功能:从键盘上任意输入
n
个整数,用冒泡法按从小到大地排序,并在屏幕上显示出来。
*/
#include "stdio.h"
#define NUM 10
/*
定义符号常量(数据个数
N
)
*/
main()
{ int data[NUM];
/*
定义
1
个
1
维整型数组
data*/
int i,j,temp;
/*
定义循环变量和临时变量
*/
clrscr();
/*
库函数
clrscr()
:清屏
*/
printf("Please input 10 numbers:\n");
for(i=0; i<NUM; i++)
scanf("%d", &data
);
(
3
)
数组同变量一样,也必须先定义、后使用。
1
维数组是只有
1
个下标的数组,定义形式如下:
数据类型
数组名
[
常量表达式
][,
数组名
2[
常量表达式
2]
……
]
;
(
1
)“数据类型”是指数组元素的数据类型。
(
2
)数组名,与变量名一样,必须遵循标识符命名规则。
(
3
)“常量表达式”必须用方括号括起来,指的是数组的元素个数(又称数组长度),它是一个整型值,其中可以包含常数和符号常量,但不能包含变量。
注意:
C
语言中不允许动态定义数组。
特别说明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是
C
语言语法规则所要求的,不是本书所约定的可选项的描述符号!
(
4
)
组元素的下标,是元素相对于数组起始地址的偏移量,所以从
0
开始顺序编号。
(
5
)
数组名中存放的是一个地址常量,它代表整个数组的首地址。同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元。
6.1.2
数组元素的引用
引用数组中的任意一个元素的形式:
数组名
[
下标表达式
]
1
.“下标表达式”可以是任何非负整型数据,取值范围是
0~
(元素个数
-1
)。
特别强调:在运行
C
语言程序过程中,系统并不自动检验数组元素的下标是否越界。因此在编写程序时,保证数组下标不越界是十分重要的。
2
.
1
个数组元素,实质上就是
1
个变量,它具有和相同类型单个变量一样的属性,可以对它进行赋值和参与各种运算。
3
.在
C
语言中,数组作为
1
个整体,不能参加数据运算,只能对单个的元素进行处理。
6.1.3
1
维数组元素的初始化
初始化格式:
数据类型
数组名
[
常量表达式
]
=
{
初值表
}
(
1
)如果对数组的全部元素赋以初值,定义时可以不指定数组长度(系统根据初值个数自动确定)。如果被定义数组的长度,与初值个数不同,则数组长度不能省略。
(
2
)“初值表”中的初值个数,可以少于元素个数,即允许只给部分元素赋初值。
(
3
)根据存储类型的不同,数组有静态数组(
static
)和动态数组(
auto
)之分;根据定义的位置不同,数组有内部数组(在函数内部定义的数组)和外部数组(在函数外部定义的数组)之分。
6.1.4
1
维数组应用举例
[
案例
6.2]
已知某课程的平时、实习、测验和期末成绩,求该课程的总评成绩。其中平时、实习、测验和期末分别占
10
%、
20
%、
20
%、
50
%。
/*
案例代码文件名:
AL6_2.C*/
/*
功能:从键盘上循环输入某课程的平时、实习、测验和期末成绩,按
10
%,
20
%,
20
%,
50
%的比例计算总评成绩,并在屏幕上显示出来。按空格键继续循环,其他键终止循环。
*/
#include “stdio.h”
main()
{ int i=1,j;
char con_key=
‘
\x20
’
;
/*
‘
\x20
’
空格键的
ASCII
码
*/
float score[5],ratio[4]={0.1,0.2,0.2,0.5};
/*
定义成绩、比例系数数组
*/
while(con_key=='\x20')
while(con_key=='\x20')
{clrscr();
printf("
输入第
%2d
个学生的成绩
\n", i++);
printf("
平时
实习
测验
期末成绩
\n");
score[4]=0;
/*score[4]
:存储总评成绩
*/
for(j=0; j<4; j++)
{scanf("%f",&score[j]);
score[4] += score[j] * ratio[j];
}
printf("
总评成绩为
:%6.1f\n",score[4]);
printf("\n
按空格键继续
,
其它键退出
");
con_key=getch();
/*getch()
函数等待从键盘上输入一个字符
*/
}
}
6.2
2
维数组的定义和引用
6.2.1
2
维数组的定义
6.2.2
2
维数组元素的引用
6.2.3
2
维数组元素的初始化
6.2.4
2
维数组应用举例
6.2.1
2
维数组的定义
[
案例
6.3]
给一个
2
*
3
的
2
维数组各元素赋值,并输出全部元素的值。
/*
案例代码文件名:
AL6_3.C*/
/*
功能:从键盘上给
2
*
3
数组赋值,并在屏幕上显示出来。
*/
#define Row 2
#define Col 3
#include "stdio.h"
main()
{int i, j, array[Row][Col];
/*
定义
1
个
2
行
3
列的
2
维数组
array*/
for(i=0; i<Row; i++)
/*
外循环:控制
2
维数组的行
*/
for(j=0; j<Col; j++)
/*
内循环:控制
2
维数组的列
*/
{printf("please input array[%2d][%2d]:",i,j);
scanf("%d",&array
[j]);
/*
从键盘输入
a
[j]
的值
*/
}
printf("\n");
/*
输出
2
维数组
array*/
for(i=0;i<Row;i++)
{ for(j=0;j<Col;j++)
printf("%d\t",array
[j]);
/*
将
a
[j]
的值显示在屏幕上
*/
printf("\n");
}
getch();
}
2
维数组的定义方式如下:
数据类型
数组名
[
行常量表达式
][
列常量表达式
][,
数组名
2[
行常量表达式
2][
列常量表达式
2]
……
];
1
.数组元素在内存中的排列顺序为“按行存放”,即先顺序存放第一行的元素,再存放第二行,以此类推。
2.
设有一个
m*n
的数组
x
,则第
i
行第
j
列的元素
x
[j]
在数组中的位置为:
i*n+j
(注意:行号、列号均从
0
开始计数)。
3
.可以把
2
维数组看作是一种特殊的
1
维数组:它的元素又是一个
1
维数组。
例如,对
x[3][2]
,可以把
x
看作是一个
1
维数组,它有
3
个元素:
x[0]
、
x[1]
、
x[2]
,每个元素又是一个包含
2
个元素的
1
维数组,如图
6-4
所示。即把
x[0]
、
x[1]
、
x[2]
看作是
3
个
1
维数组的名字。
?6.2.2
2
维数组元素的引用
引用
2
维数组元素的形式为:
数组名
[
行下标表达式
][
列下标表达式
]
1
.“行下标表达式”和“列下标表达式”,都应是整型表达式或符号常量。
2
.“行下标表达式”和“列下标表达式”的值,都应在已定义数组大小的范围内。假设有数组
x[3][4]
,则可用的行下标范围为
0~2
,列下标范围为
0~3
。
3
.对基本数据类型的变量所能进行的操作,也都适合于相同数据类型的
2
维数组元素。
6.2.3
2
维数组元素的初始化
1
.按行赋初值
数据类型
数组名
[
行常量表达式
][
列常量表达式
]
=
{{
第
0
行初值表
}
,
{
第
1
行初值表
}
,……,
{
最后
1
行初值表
}}
;
赋值规则:将“第
0
行初值表”中的数据,依次赋给第
0
行中各元素;将“第
1
行初值表”中的数据,依次赋给第
1
行各元素;以此类推。
2
.按
2
维数组在内存中的排列顺序给各元素赋初值
数据类型
数组名
[
行常量表达式
][
列常量表达式
]
=
{
初值表
}
;
赋值规则:按
2
维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素。
如果对全部元素都赋初值,则“行数”可以省略。注意:只能省略“行数”。
6.2.4
2
维数组应用举例
[
案例
6.4]
有
M
个学生,学习
N
门课程,已知所有学生的各科成绩,编程:分别求每个学生的平均成绩和每门课程的平均成绩。
/*
案例代码文件名:
AL6_4.C*/
/*
功能:计算个人平均成绩与各科平均成绩,并在屏幕上显示出来。
*/
#define NUM_std
5
/*
定义符号常量人数为
5*/
#define NUM_course
4
/*
定义符号常量课程为
4*/
#include "stdio.h"
main()
{ int i,j;
static float score[NUM_std+1][NUM_course+1]={{78,85,83,65},
{88,91,89,93}, {72,65,54,75},
{86,88,75,60}, {69,60,50,72}};
for(i=0;i<NUM_std;i++)
{for(j=0;j<NUM_course;j++)
{ score
[NUM_course] += score
[j];/*
求第
i
个人的总成绩
*/
score[NUM_std][j] += score
[j]; /*
求第
j
门课的总成绩
*/
}
score
[NUM_course] /= NUM_course;/*
求第
i
个人的平均成绩
*/
}
for(j=0;j<NUM_course;j++)
score[NUM_std][j] /= NUM_std; /*
求第
j
门课的平均成绩
*/
clrscr();
/*
输出表头
*/
printf("
学生编号
课程
1
课程
2
课程
3
课程
4
个人平均
\n");
/*
输出每个学生的各科成绩和平均成绩
*/
for(i=0;i<NUM_std;i++)
{ printf("
学生
%d\t",i+1);
for(j=0;j<NUM_course+1;j++)
printf("%6.1f\t",score
[j]);
printf("\n");
}
/*
输出
1
条短划线
*/
for(j=0;j<8*(NUM_course+2);j++)
printf("-");
printf("\n
课程平均
");
/*
输出每门课程的平均成绩
*/
for(j=0;j<NUM_course;j++)
printf("%6.1f\t",score[NUM_std][j]);
printf("\n");
getch();
}
6.3
字符数组与字符串
6.3.1
字符数组的逐个字符操作
6.3.2
字符数组的整体操作
6.3.3
常用的字符串处理函数
6.3.1
字符数组的逐个字符操作
[
案例
6.5]
从键盘输入一个字符串,回车键结束,并将字符串在屏幕上输出。
/*
案例代码文件名:
AL6_5.C*/
main()
{int i;
static char str[80];
clrscr();
for(i=0;i<80;i++)
{ str
=getch();
/*
逐次给数组元素
str
赋值,但不回显在屏幕上
*/
printf("*");
/*
以星号代替输入字符的个数
*/
if(str
=='\x0d') break;/*
若输入回车则终止循环
*/
}
i=0;
while(str
!='\x0d')
printf("%c",str[i++]);
/*
逐次输出字符数组的各个元素
*/
printf("\n");
getch();
/*
程序暂停
*/
}
1
.字符数组的定义
1
维字符数组,用于存储和处理
1
个字符串,其定义格式与
1
维数值数组一样。
2
维字符数组,用于同时存储和处理多个字符串,其定义格式与
2
维数值数组一样。
2
.字符数组的初始化
字符数组的初始化,可以通过为每个数组元素指定初值字符来实现。
3
.字符数组的引用
字符数组的逐个字符引用,与引用数值数组元素类似。
(
1
)字符数组的输入
除了可以通过初始化使字符数组各元素得到初值外,也可以使用
getchar()
或
scanf()
函数输入字符。
例如:
char str[10]
;
……
for(i=0; i<10; i++)
{ scanf("%c", &str
)
;
fflush(stdin);
/*
清除键盘输入缓冲区
*/
}
……
(
2
)字符数组的输出
字符数组的输出,可以用
putchar()
或
printf()
函数。
例如:
char
str[10]="clanguage";
……
for(i=0; i<10; i++)
printf("%c", str
)
;
printf("\n");
……
注意:逐个字符输入、输出时,要指出元素的下标,而且使用“
%c
”格式符。另外,从键盘上输入字符时,无需输入字符的定界符──单引号;输出时,系统也不输出字符的定界符。
6.3.2
字符数组的整体操作
[
案例
6.6]
字符数组的整体输入与输出。
/*
案例代码文件名:
AL6_6.C*/
/*
功能:将
2
维字符数组进行初始化,并在屏幕上输出
*/
main()
{ int i;
char name[5][9]={"
张三山
","
李四季
", "
王五魁
", "
刘六顺
","
赵七巧
"};
for(i=0;i<5;i++)
printf("\n%s\t",name
);
/*name
代表该行数组元素的首地址
*/
getch();
}
[
程序演示
]
1
.字符串及其结束标志
所谓字符串,是指若干有效字符的序列。
C
语言中的字符串,可以包括字母、数字、专用字符、转义字符等。
C
语言规定:以‘
\0
’作为字符串结束标志(‘
\0
’代表
ASCII
码为
0
的字符,表示一个“空操作”,只起一个标志作用)。因此可以对字符数组采用另一种方式进行操作了──字符数组的整体操作。
注意:由于系统在存储字符串常量时,会在串尾自动加上
1
个结束标志,所以无需人为地再加
1
个。
另外,由于结束标志也要在字符数组中占用一个元素的存储空间,因此在说明字符数组长度时,至少为字符串所需长度加
1
。
2
.字符数组的整体初始化
字符串设置了结束标志以后,对字符数组的初始化,就可以用字符串常量来初始化字符数组。
3
.字符数组的整体引用
(
1
)字符串的输入
除了可以通过初始化使字符数组各元素得到初值外,也可以使用
scanf()
函数输入字符串。
(
2
)字符串的输出
printf()
函数,不仅可以逐个输出字符数组元素,还可以整体输出存放在字符数组中的字符串。
6.3.3
常用的字符串处理函数
字符串标准函数的原型在头文件
string.h
中。
1
.输入字符串──
gets()
函数
(
1
)调用方式:
gets(
字符数组
)
(
2
)函数功能:从标准输入设备
(stdin)
──键盘上,读取
1
个字符串(可以包含空格),并将其存储到字符数组中去。
(
3
)使用说明
1
)
gets()
读取的字符串,其长度没有限制,编程者要保证字符数组有足够大的空间,存放输入的字符串。
2
)该函数输入的字符串中允许包含空格,而
scanf()
函数不允许。
2
.输出字符串──
puts()
函数
(
1
)调用方式:
puts(
字符数组
)
(
2
)函数功能:把字符数组中所存放的字符串,输出到标准输出设备中去,并用‘
\n
’取代字符串的结束标志‘
\0
’。所以用
puts()
函数输出字符串时,不要求另加换行符。
(
3
)使用说明
1)
字符串中允许包含转义字符,输出时产生一个控制操作。
2)
该函数一次只能输出一个字符串,而
printf()
函数也能用来输出字符串,且一次能输出多个。
3
.字符串比较──
strcmp()
函数
(
1
)调用方式:
strcmp(
字符串
1 ,
字符串
2)
其中“字符串”可以是串常量,也可以是
1
维字符数组。
(
2
)函数功能:比较两个字符串的大小。
如果:字符串
1=
字符串
2
,函数返回值等于
0
;
字符串
1<
字符串
2
,函数返回值负整数;
字符串
1>
字符串
2
,函数返回值正整数。
(
3
)使用说明
1
)如果一个字符串是另一个字符串从头开始的子串,则母串为大。
2
)不能使用关系运算符“==”来比较两个字符串,只能用
strcmp()
函数来处理。
[
案例
6.7]
gets
函数和
strcmp
函数的应用。
/*
案例代码文件名:
AL6_7.C*/
/*
功能:简单密码检测程序
*/
#include
"stdio.h"
main()
{char pass_str[80];
/*
定义字符数组
passstr*/
int i=0;
/*
检验密码
*/
while(1)
{clrscr();
printf("
请输入密码
\n");
gets(pass_str);
/*
输入密码
*/
if(strcmp(pass_str,
“
password
”
)!=0)
/*
口令错
*/
printf("
口令错误,按任意键继续
");
else
break;
/*
输入正确的密码,中止循环
*/
getch();
i++;
if(i==3) exit(0);
/*
输入三次错误的密码,退出程序
*/
}
/*
输入正确密码所进入的程序段
*/
}
4
.拷贝字符串──
strcpy()
函数
(
1
)调用方式:
strcpy(
字符数组
,
字符串
)
其中“字符串”可以是串常量,也可以是字符数组。
(
2
)函数功能:将“字符串”完整地复制到“字符数组”中,字符数组中原有内容被覆盖。
(
3
)使用说明
1
)字符数组必须定义得足够大,以便容纳复制过来的字符串。复制时,连同结束标志
'\0'
一起复制。
2
)不能用赋值运算符“=”将一个字符串直接赋值给一个字符数组,只能用
strcpy()
函数来处理。
5
.连接字符串──
strcat()
函数
(
1
)调用方式:
strcat(
字符数组
,
字符串
)
(
2
)函数功能:把“字符串”连接到“字符数组”中的字符串尾端,并存储于“字符数组”中。“字符数组”中原来的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改。
(
3
)使用说明
1
)由于没有边界检查,编程者要注意保证“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则,会因长度不够而产生问题。
2
)连接前两个字符串都有结束标志
'\0'
,连接后“字符数组”中存储的字符串的结束标志
'\0'
被舍弃,只在目标串的最后保留一个
'\0'
。
6
.求字符串长度──
strlen()
函数(
len
是
length
的缩写)
(
1
)调用方式:
strlen(
字符串
)
(
2
)函数功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。
7
.将字符串中大写字母转换成小写──
strlwr()
函数
(
1
)调用方式:
strlwr(
字符串
)
(
2
)函数功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换。
8
.将字符串中小写字母转换成大写──
strupr()
函数
(
1
)调用方式:
strupr(
字符串
)
(
2
)函数功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0