Chap 7 数 组

75
Chap 7 数 数 7.1 数数数数 7.2 数数数数数数数数数数数数数 7.3 数数数数

description

Chap 7 数 组. 7.1 投票情况统计 7.2 找出矩阵中最大值所在的位置 7.3 判断回文. 本章要点. 什么是数组? 为什么要使用数组?如何定义数组? 如何引用数组元素? 二维数组的元素在内存中按什么方式存放? 什么是字符串? 字符串结束符的作用是什么? 如何实现字符串的存储和操作,包括字符串的输入和输出? 怎样理解 C 语言将字符串作为一个特殊的一维字符数组?. 7.1 投票情况统计. 输入一个正整数 n (1

Transcript of Chap 7 数 组

Page 1: Chap 7   数 组

Chap 7 数 组

7.1 投票情况统计

7.2 找出矩阵中最大值所在的位置

7.3 判断回文

Page 2: Chap 7   数 组

本章要点 什么是数组 ? 为什么要使用数组 ? 如何定义数组 ? 如何引用数组元素 ? 二维数组的元素在内存中按什么方式存放 ? 什么是字符串 ? 字符串结束符的作用是什么 ? 如何实现字符串的存储和操作,包括字符串的输

入和输出 ? 怎样理解 C 语言将字符串作为一个特殊的一维字

符数组 ?

Page 3: Chap 7   数 组

7.1 投票情况统计 输入一个正整数 n (1<n≤10) ,再输入 n 个整数,用选择法将它们从小到大排序后输出。

7.1.1 程序解析

7.1.2 一维数组的定义和引用

7.1.3 一维数组的初始化

7.1.4 使用一维数组编程

Page 4: Chap 7   数 组

7.1.1 程序解析【例 7-1 】调查电视节目欢迎程度。某电视台要进行一次对该台 8 个栏目 ( 设相应栏目编号为 1~8) 的受

欢迎情况,共调查了 1000 位观众,现要求编写程序,输入每一位观众的投票,每位观众只能选择一个最喜欢的栏目投票,统计输出各栏目的得票情况。

分析:本题涉及新问题 如何存储 8 个栏目计票数据

Page 5: Chap 7   数 组

# include<stdio.h>int main( void ) { int i,response, count[9]; /* 设立得票计数器 */ for(i = 1; i <= 8; i++) count[i] = 0; /* 得票计数器清 0 */ for( i = 1; i <= 1000; i++) { printf("input your response: "); /* 输入提示 */ scanf("%d",&response); if(response < 1 || response > 8) /* 检查是否有效票 */ printf("this is a bad response: %d\n",response); else count[response]++; /* 对应栏目得票加 1 */ } printf("result:\n"); /* 输出得票情况 */ for(i = 1;i <= 8;i++) printf("%4d%4d\n",i,count[i]); return 0;}

例 7-1 程序

Page 6: Chap 7   数 组

7.1.2 一维数组的定义和引用1. 数组的一般概念 数组是按序排列的同类型变量的集合,是一组具有相 同名字 , 不同下标的下标变量。 下标变量又称数组元素,形式为:数组名 [ 下标 ] 如: a[0] 、 a[1] 、 a[2] 、 a[3] 、…、 a[9] 数组名表示整个数组,如: a 下标指出该数组元素在数组中的位置。 有 1 个下标的下标变量所组成的数组称为一维数组; 有 2 个下标的下标变量所组成的数组称为二维数组。 如: x[1] 、 y[5] 数组 x 和 y 都是一维数组 a[1][2] 、 b[2][3] 数组 a 和 b 都是二维数组

Page 7: Chap 7   数 组

7.1.2 一维数组的定义和引用2. 一维数组的定义 定义的一般形式 类型名 数组名 [ 数组长度 ] ;

类型名:数组元素的数据类型数组名:数组的名称,标识符数组长度:常量表达式,指定数组元素的个数

例如: int a[10]; 定义一个含有 10 个整型元素的数组 a

char c[81]; 定义一个含有 81 个字符元素的数组 c

float f[5]; 定义一个含有 5 个实型元素的数组 f

Page 8: Chap 7   数 组

7.1.2 一维数组的定义和引用 数组中元素的下标从 0 开始依次编号。 经定义的数组 , 编译后 , 会分配到一段 连续的内存单元。如有定义 int a[10]; , 情况如图所示, a[0], a[1],…, a[9] 依 次连续存储。 数组名 ( 如 a ) 是一个地址常量,存放 数组内存空间的首地址。也就是第 1

个元素的存储地址,即 a 和 &a[0] 同值。 各个元素的存储地址用数组的首地址以及每个元 素所需的字节数,均可计算得到。

a[0]

a[1]

a[9]

……

Page 9: Chap 7   数 组

7.1.2 一维数组的定义和引用 数组定义中的数组长度只能是常量表达式,不能 含变量。如以下定义是非法的: int n, m=10; double a[n], b[m]; 同类型数组、变量可一起定义 :

int i, a[10], b[20];

Page 10: Chap 7   数 组

7.1.2 一维数组的定义和引用3. 一维数组的引用 只能引用单个数组元素,不能一次引用整个数组。 数组元素的引用方法有两种:下标法和指针法。 下标法引用一维数组元素的形式为: 数组名 [ 下标 ]

其中下标为整型表达式,取值范围是 : [0, 数组长 度 -1] ,它表示了元素在数组中的顺序位置。 数组元素又称下标变量,使用方法与同类型变量 完全相同。 编译时,不检查数组元素的下标是否越界。

Page 11: Chap 7   数 组

7.1.3 一维数组的初始化 数组初始化就是在定义数组时,对数组元素赋值。 其一般形式为: 类型名 数组名 [ 数组长度 ] = { 初值表 }; 初值表中用逗号分隔的各值为将依次赋予各对应 元素的初值,必须是常量表达式,且类型应与数 组的类型相一致。例如, int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 字符数组初始化有两种形式

char b[6]={'C','h','i','n','a','\0'};char s[6]={"China"}; 或 char s[6]="China";

Page 12: Chap 7   数 组

7.1.3 一维数组的初始化 允许只给部分元素赋初值 ( 其余元素初始化为 0 ) 。 如: int a[10]={1, 2, 3}, b[10]={ 0 }; 如对全部元素都赋初值,可缺省数组长度,数组 长度为初值表中初值的个数。例如, int a[ ] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char s[ ] = "China"; 对数组未指定初始化

自动类型数组,各元素的值是随机的未知值。全局数组和静态数组,各元素值则会自动初始 化为 0 。

Page 13: Chap 7   数 组

7.1.3 一维数组的初始化 一维数组的输入和输出

对数组元素赋初值,更多的是通过键盘输入的 方法。如输入长度为 n 的整型数组 a 的各元: for( i=0; i<n; i++ )

scanf("%d", &a[i]);输出长度为 n 的整型数组 a 的各元: for( i=0; i<n; i++ )

printf("%d ", a[i]);

Page 14: Chap 7   数 组

7.1.4 使用一维数组编程【例 7-2 】利用数组计算 fibonacci 数列的前 10 个 数,即 1, 1, 2, 3, 5, …, 35 ,并按每行打印 5 个数的格式输出。

分析: 本题与【例 4-11 】的差别仅是先将算出的各项值存入数组,最后再输出。 定义数组并初始化: int i, fib[10] = {1, 1}; 初始条件: fib[0]=1, fib[1]=1 ( i = 0, 1 )

递推公式: fib[i] = fib[i-1] + fib[i-2] ( i > 1 )

Page 15: Chap 7   数 组

例 7-2 程序#include <stdio.h>

int main(void){ int i, fib[10] = {1, 1}; for(i = 2; i < 10; i++) fib[i] = fib[i - 1] + fib[i - 2]; for(i = 0; i < 10; i++) { printf("%6d", fib[i]); if((i + 1)%5==0) printf("\n"); } return 0;}

运行结果 : 1 1 2 3 5 8 13 21 34 55

Page 16: Chap 7   数 组

7.1.4 使用一维数组编程【例 7-3 】输入 5 个整数,将它们存入数组 a 中,再输入一个数 x ,然后在数组中查找 x ,如果找到,输出相应的最小下标,否则,输出“ Not Found” 。

分析:这是个查找问题中的顺序查找问题。 通过遍历 (扫描 ) 数组 a ,对数组各元逐个比较是否 等于 x 即可。 最后判断是否未找到,可用标志法或 break 法。

Page 17: Chap 7   数 组

例 7-3 程序

#include <stdio.h>int main(void){ int i, flag, x, a[5]; printf("Enter 5 integers: "); for(i = 0; i < 5; i++) scanf("%d", &a[i]); printf("Enter x: "); scanf("%d", &x); for(flag = i = 0; i < 5; i++) if(a[i] == x) { printf("Index is %d\n", i); flag = 1; break; } if(flag == 0) printf("Not Found\n"); return 0;}

运行结果 1: Enter 5 integers: 2 9 8 1 6 Enter x: 9 Index is 1

运行结果 2: Enter 5 integers: 2 9 8 1 6 Enter x: 7 Not Found

i == 5

Page 18: Chap 7   数 组

7.1.4 使用一维数组编程【例 7-4 】输入一个正整数 n(1< n <11), 再输入 n 个 整数,将它们存入数组 a 中。 ① 输出最小值和它所对应的下标。 ② 将最小值与第一个数交换,输出交换后的 n 个数。分析:① 这是个求最值问题。可先假定 a[0] 最小,即最小元素的下标 index=0 ,然后遍历数组 a ,各元素逐个与 a[index]比较,若小于,则其下标存入 index ,这样就是使 index 中始终是到当前为止的最小元素的下标 。

Page 19: Chap 7   数 组

7.1.4 使用一维数组编程实现语句: for(index = i = 0; i<n; i++)

if(a[i] < a[index]) index = i;

② 交换两个变量的值有多种方法: 借助第三者 t = a; a = b; b = t; 不借助第三者 a =a+b; b= a-b; a =a-b;

a ^= b; b ^=a; a ^= b; 或写成 a ^= b ^= a ^= b;

Page 20: Chap 7   数 组

#include <stdio.h>int main(void){ int i, index, n, a[10], t; printf("Enter n: "); scanf("%d", &n); printf("Enter %d integers: ", n); for(i = 0; i < n; i++) scanf("%d", &a[i]); for(index = 0, i = 1; i < n; i++) if(a[i] < a[index]) index = i; printf("min is %d\tsub is %d\

n",a[index],index);

例 7-4 程序

Page 21: Chap 7   数 组

例 7-4 程序 t = a[index];

a[index] = a[0];

a[0]=t;

for(i = 0; i < n; i++)

printf("%d ", a[i]);

return 0;

}运行结果 :Enter n: 6Enter 6 integers: 2 9 -1 8 1 6min is -1 sub is 2-1 9 2 8 1 6

Page 22: Chap 7   数 组

7.1.4 使用一维数组编程【例 7-5 】选择排序法。输入一个正整数 n(1< n ≤

10) ,再输入 n 个整数,用选择法将它们从小到大排

序后输出。

Page 23: Chap 7   数 组

例 7-5 程序#include <stdio.h>

int main(void){ int i, j, k, n, t, a[10]; printf("Enter n: "); scanf("%d", &n); printf("Enter %d integers: ", n); for(i = 0; i < n; i++) scanf("%d", &a[i]); for(i = 0; i < n-1; i++) { for(k = i, j = i+1; i < n; i++) if(a[j] < a[k]) k = j; t = a[i]; a[i]=a[k]; a[k]=t; }

Page 24: Chap 7   数 组

例 7-5 程序 printf("After sorted: ");

for(i = 0; i < n; i++)

printf("%d ", a[i]);

return 0;

}

运行结果 : Enter n: 10Enter 10 integers: 3 5 2 8 1 22 89 0 -1 7After sorted: -1 0 1 2 3 5 7 8 22 89

Page 25: Chap 7   数 组

选择法排序 选择法排序的基本思想是: 通过比较找到最小数,如不是第 1 个数,则与第 1

个数交换,再在余下的数 ( 即第 2 个开始 ) 中找到最小数,如不是第 2 个数,则与第 2 个数交换,再在余下的数 ( 即第 3 个开始 ) 中找到最小数,如不是第 3

个数,则与第 3 个数交换,依此类推, n 个数经过

n-1 轮比较即可完成排序。

Page 26: Chap 7   数 组

选择法排序选择法排序的实现 1 :int n=5, i, j, t;

int a[5] = {3, 5, 2, 8, 1};

for(i = 0; i < n-1; i++)

for( j = i+1; j < n; j++)

if(a[i]>a[j])

{ t = a[i];

a[i] = a[j];

a[j] = t;

}

i j a[0] a[1] a[2] a[3] a[4]0 1 3 5 2 8 10 2 3 5 2 8 10 3 2 5 3 8 10 4 2 5 3 8 1

1 5 3 8 21 2 1 5 3 8 21 3 1 3 5 8 21 4 1 3 5 8 2

1 2 5 8 32 3 1 2 5 8 32 4 1 2 5 8 3

1 2 3 8 53 4 1 2 3 8 5

1 2 3 5 8

Page 27: Chap 7   数 组

选择法排序的实现 1流程:

i < n-1

i = 0

交换a[i],a[j]

T

F

j = i+1

j < n

a[i]>a[j] j ++

i ++ T

T

end

F

F

Page 28: Chap 7   数 组

选择法排序选择法排序的实现 2 :int n=5, i, j, k, t;

int a[5] = {3, 5, 2, 8, 1};

for(i = 0; i < n-1; i++)

{ for(k=i, j=i+1; j<n; j++)

if(a[k]>a[j]) k = j;

if(k != i)

{ t=a[i]; a[i]=a[j]; a[j]=t; }

}

i k j a[0] a[1] a[2] a[3] a[4]0 0 1 3 5 2 8 10 0 2 3 5 2 8 10 2 3 3 5 2 8 10 2 4 3 5 2 8 10 4 3 5 2 8 11 1 2 1 5 2 8 31 2 3 1 5 2 8 31 2 4 1 5 2 8 31 2 1 5 2 8 32 2 3 1 2 5 8 32 2 4 1 2 5 8 32 4 1 2 5 8 33 3 4 1 2 3 8 53 4 1 2 3 8 5

1 2 3 5 8

Page 29: Chap 7   数 组

选择法排序的实现 2流程:

j < n

i < n-1

i = 0

k = j

TF

k=i, j=i+1

a[k]>a[j]

j ++

T

T

end

F

F

i ++

交换 a[i],a[k]

k != i T

F

Page 30: Chap 7   数 组

冒泡法排序冒泡法排序 1 的基本思想是: 从第 n 个数开始,依次比较相邻两个数,即第 n 个与第 n-1 个、第 n-1 个与第 n-2 个、… ,每次比较,若不满足由小到大的顺序,则两者对调位置,通过一轮比较,参加比较的数中的最小数就“上升”到它们中最前面的位置,下一轮再从第 n 个数开始,把余下的数依次比较,这样,通过 n-1轮比较,就完成了全部 n 个数的升序排列。在第 i轮比较时,从第 1 个位置开始已排序定位了 i-1 个数,余下 n-i+1 个数,需两两比较 n-i 次。

Page 31: Chap 7   数 组

冒泡法排序冒泡法排序 1 的实现:int n=5, i, j, t;int a[5] = {3, 5, 2, 8, 1};for(i = 0; i < n-1; i++) for( j = n-1; j > i; j--) if(a[j] < a[j-1]) { t = a[j]; a[j] = a[j-1]; a[j-1] = t; }

i j a[0] a[1] a[2] a[3] a[4]0 4 3 5 2 8 10 3 3 5 2 1 80 2 3 5 1 2 80 1 3 1 5 2 8

1 3 5 2 81 4 1 3 5 2 81 3 1 3 5 2 81 2 1 3 2 5 8

1 2 3 5 82 4 1 2 3 5 82 3 1 2 3 5 8

1 2 3 5 83 4 1 2 3 5 8

1 2 3 5 8

Page 32: Chap 7   数 组

冒泡法排序冒泡法排序 2 的基本思想是: 从第 1 个数开始,依次比较相邻两个数,即第 1 个与第 2 个、第 2 个与第 3 个、… ,每次比较,若不满足由小到大的顺序, 则两者对调位置, 通过一轮比较,参加比较的数中的最大数就 “ 下沉 ” 到它们中最后面的位置,下一轮再从第 1 个数开始,把余下的数依次比较,这样,通过 n-1轮比较,就完成了全部 n 个数的升序排列。在第 i轮比较时,从第 n

个位置开始向前已排序定位了 i-1 个数,余下 n-i+1

个数,需两两比较 n-i 次

Page 33: Chap 7   数 组

冒泡法排序冒泡法排序 2 的实现:int n=5, i, j, t;int a[5] = {3, 5, 2, 8, 1};for(i = 0; i < n-1; i++) for( j = 0; j < n-1-i ; j--) if(a[j] > a[j+1]) { t = a[j]; a[j] = a[j+1]; a[j+1] = t; }

i j a[0] a[1] a[2] a[3] a[4]0 0 3 5 2 8 10 1 3 5 2 8 10 2 3 2 5 8 10 3 3 2 5 8 1

3 2 5 1 81 0 3 2 5 1 81 1 2 3 5 1 81 2 2 3 5 1 8

2 3 1 5 82 0 2 3 1 5 82 1 2 3 1 5 8

2 1 3 5 83 0 2 1 3 5 8

1 2 3 5 8

Page 34: Chap 7   数 组

7.1.4 使用一维数组编程【例 7-6 】二分查找法。设已有一个 10 个元素的整形数组 a ,且按值从小到大有序。输入一个整数 x ,然后在数组中查找 x ,如果找到,输出相应的下

标 ,否则,输出“ Not Found” 。

设:待查数在变量 x 中; 变量 low 用于存放查找范围的顶部位置; 变量 mid 用于存放查找范围的中间位置; 变量 high 用于存放查找范围的底部位置;

Page 35: Chap 7   数 组

二分法查找流程图

mid=(low+high)/2

x!=a[mid] T

F

输入 x

low=0;hghi=n-1;

Not found

hghi=mid-1 low=mid+1

low<=hghi

low<=hghi 输出 mid

x<a[mid]

F

F

F

T

T

T

Page 36: Chap 7   数 组

#include <stdio.h>int main(void){ int low, high, mid, n=10, x, a[10]={1,2,3,4,5,6,7,8,9,10}; printf("Enter x: "); scanf("%d",&x); low = 0; high = n - 1; while (low <= high) { mid = (low + high) / 2; /* 中间位置 */ if (x == a[mid]) break; /* 找到 , 中止循环 */ else if (x < a[mid]) high = mid - 1; /* 前半段 , high前移 */

else low = mid + 1; /* 后半段 , low 后移 */ } if(low <= high) printf("Index is %d \n",mid); else printf( "Not Found\n"); return 0;}

例 7-6 程序

运行结果 1:Enter x: 8Index is 7

运行结果 2:Enter x: 71Not Found

Page 37: Chap 7   数 组

7.2 找出矩阵中最大值所在的位置 将 1 个 3*2 的矩阵存入 1 个 3*2 的二维数组中,

找出最大值以及它的行下标和列下标,并输出该矩阵。

7.2.1 程序解析

7.2.2 二维数组的定义和引用

7.2.3 二维数组的初始化

7.2.4 使用二维数组编程

Page 38: Chap 7   数 组

7.2.1 程序解析【例 7-7 】将 1 个 3*2 的矩阵存入 1 个 3*2 的二维数

组 中,找出最大值以及它的行下标和列下标,并输出 该矩阵。分析: 涉及新问题:二维数组 求最值方法与【例 7-4 】①的一维数组中求最值方 法类似。 row 记录最大值的行下标 col 最大值的列下标 a[row][col] 就是最大值

Page 39: Chap 7   数 组

#include <stdio.h>int main(void){ int i, j, col, row, a[3][2]; printf("Enter 6 integers:\n") ; for(i = 0; i < 3; i++) for(j = 0; j < 2; j++) scanf("%d", &a[i][j]); for(i = 0; i < 3; i++) { for(j = 0; j < 2; j++) printf("%4d", a[i][j]); printf("\n"); }

例 7-7 程序

Page 40: Chap 7   数 组

例 7-7 程序 row = col = 0;

for(i = 0; i < 3; i++) for(j = 0; j < 2; j++) if(a[i][j] > a[row][col]) { row = i; col = j; } printf("max = a[%d][%d] = %d\n", row, col, a[row][col]); return 0;

}

运行结果 :Enter 6 integers: 3 2 10 -9 6 -1 3 2 10 -9 6 -1max = a[1][0] = 10

Page 41: Chap 7   数 组

7.2.2 二维数组的定义和引用1. 二维数组的定义 定义的一般形式 类型名 数组名 [ 行长度 ][ 列长度 ]

其中行长度和列长度只能是常量表达式。 如: int a[3][2];

定义 3 行 2 列的二维数组 a, 各元素为: a[0][0] a[0][1]

a[1][0] a[1][1]

a[2][0] a[2][1]

如图所示,按行存放在一段连续的内存中。

a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]

Page 42: Chap 7   数 组

7.2.2 二维数组的定义和引用 二维数组是一维数组的数组 可以把 a看作含有 a[0] 、 a[1] 和 a[2] 共 3 个元素

的一 维数组,而 a[0] 、 a[1] 和 a[2] 又都是含有 2 个元

素 的一维数组, a[0] 、 a[1] 和 a[2] 就是这 3 个一维

数 组的名字,即: a: a[0]: a[0][0] a[0][1]

a[1]: a[1][0] a[1][1]

a[2]: a[2][0] a[2][1]

Page 43: Chap 7   数 组

7.2.2 二维数组的定义和引用2. 二维数组的引用 数组元素的引用方法有两种:下标法和指针法。 下标法引用二维数组元素的形式为: 数组名 [ 行下标 ] [ 列下标 ]

其中: 行、列下标 可以是整型表达式; 行下标 取值范围 : [0, 行长度 -1] ; 列下标 取值范围 : [0, 列长度 -1] 。

Page 44: Chap 7   数 组

7.2.3 二维数组的初始化1. 分行赋初值的一般形式 类型名 数组名 [ 行长度 ][ 列长度 ] = { { 初值表

0}, … … , { 初值表 k},… }; 其中初值表 k 中的数据依次赋给 k 行的元素。 例如: int a[3][2]={{1,2},{3,4},{5,6}};2. 顺序赋初值的一般形式 类型名 数组名 [ 行长度 ][ 列长度 ] = { 初值表 }; 按数组元素在内存中的存放顺序,把初值表中的数 据依次赋给元素。 例如: int a[3][2]={1,2,3,4,5,6};

Page 45: Chap 7   数 组

7.2.3 二维数组的初始化3. 初始化说明 允许只给部分元素赋初值 ( 其余元素初始化为 0) int a[3][4]={{8,4}, {5}, {4}}; int a[3][4]={8,4,2,1,5}; 当用分行赋值给出了所有行,或者当用顺序赋值

给出全部数组元素初始化值时,可以缺省行长度 int a[ ][4]={{8,4}, {5},{4}}; int a[ ][4]= {8,4,2,1, 5,7,0,3, 4,0,9,6}; 对数组未指定初始化

自动类型数组,各元素值是随机的未知值。全局数组和静态数组,各元素值自动赋初值 0 。

Page 46: Chap 7   数 组

7.2.3 二维数组的初始化 二维数组的输入和输出

对数组元素赋初值,更多的是通过键盘输入的方法。 如输入 n 行 m 列的整型数组 a 的各元: for( i=0; i<n; i++ ) for( j=0; j<m; j++ ) scanf("%d", &a[i]); 输出 n 行 m 列的整型数组 a 的各元: for( i=0; i<n; i++ ) { for( j=0; j<m; j++ ) printf("%d ", a[i]); printf("\n"); }

Page 47: Chap 7   数 组

7.2.4 使用二维数组编程【例 7-8 】定义 1 个 3*2 的二维数组 a ,数组元素

的值 由下式给出,按矩阵的形式输出 a 。

a[i][j] = i + j ( 0≤i≤2 , 0≤j≤1 )

Page 48: Chap 7   数 组

例 7-8 程序#include <stdio.h>

int main(void){ int i, j, a[3][2]; for(i = 0; i < 3; i++) for(j = 0; j < 2; j++) a[i][j] = i + j; for(i = 0; i < 3; i++) { for(j = 0; j < 2; j++) printf("%4d", a[i][j]); printf("\n"); } return 0;}

运行结果 : 0 1 1 2 2 3

Page 49: Chap 7   数 组

7.2.4 使用二维数组编程【例 7-9 】输入一个正整数 n(1 < n≤6) ,根据下式 生成 1 个 n*n 的方阵,然后将该方阵转置 ( 行列互

换 ) 后输出。 a[i][j] = i * n + j + 1 ( 0≤i≤n-1 , 0≤j≤n-1 ) 例如,当 n=3 时,有: 转置前 转置后 1 2 3 1 4 7

4 5 6 2 5 8

7 8 9 3 6 9

Page 50: Chap 7   数 组

7.2.4 使用二维数组编程 矩阵术语与二维数组下标的对应关系:

int a[N][N]; N 是正整数a[i][j] : i 、 j 的取值范围 [0 , N-1]

设 N 为 3 ,用二维数组 a 表示 N*N 方阵时:

a[0][0] a[0][1] a[0][2]

a[1][0] a[1][1] a[1][2]

a[2][0] a[2][1] a[2][2]

主对角线 i==j

上三角 i<=j

下三角 i>=j

副对角线 i+j==N-1

Page 51: Chap 7   数 组

7.2.4 使用二维数组编程 遍历主对角线: for(i = 0; i < N; i++) { a[i][i] = …; …… } 遍历副对角线: for(i = 0; i < N; i++) { a[i][N-1-i] = …; …… } 遍历上三角: for(i = 0; i < N; i++) for(j = i; j < N; j++) { a[i][j] = …; …… } 遍历下三角: for(i = 0; i < N; i++) for(j = 0; j <= i; j++) { a[i][j] = …; …… }

Page 52: Chap 7   数 组

#include <stdio.h>

int main(void)

{ int i, j, n, t, a[6][6];

printf("Enter n: "); scanf("%d", &n);

for(i = 0; i < n; i++) /* 遍历数组各元赋值 */

for(j = 0; j < n; j++)

a[i][j] = i * n + j + 1;

for(i = 0; i < n; i++)

for(j = 0; j < n; j++)

if(i <= j) /* 只遍历上三角 */

{ t = a[i][j]; a[i][j] = a[j][i]; a[j][i] = t; }

例 7-9 程序

for(j = i; j < n; j++)

Page 53: Chap 7   数 组

例 7-9 程序 for(i = 0; i < 3; i++)

{ for(j = 0; j < 2; j++) printf("%4d", a[i][j]); printf("\n"); }

return 0;

} 运行结果 :Enter n: 3 1 4 7 2 5 8 3 6 9

Page 54: Chap 7   数 组

7.2.4 使用二维数组编程【例 7-10 】定义函数 day_of_year(year, month, day),

计算并返回年 year 、月month 和日 day 对应的是该年的第几天。判别闰年的条件是年份能被 4 整除但不能被 100 整除,或能被 400 整除。分析:主要要考虑各月天数如何获取: 用二维数组 0 行和 1 行的 1~12 列分别预存平年和闰年 的 1~12 月天数。 用一维数组下标 1~12 的元素预存平年的 1~12月 天 数, 2月的天数根据是否闰年在计算时修正。 其他不用数组,用分支语句的方法。

Page 55: Chap 7   数 组

#include <stdio.h> /* 用一维数组 */int day_of_year(int y, int m, int d){ int i, tab[ ]={0,31,28,31,30,31,30,31,31,30,31,30,31}; tab[2] += (y%4==0 && y%100!=0) || y%400==0; for(i=1; i<m; i++) d += tab[i]; return d;}int main(void){ int y, m, d; scanf("%d%d%d", &y, &m, &d); printf("%d\n", day_of_year(y,m,d)); return 0;}

例 7-10 程序

运行结果 1:2000 3 161

运行结果 2:2013 3 160

Page 56: Chap 7   数 组

/* 用二维数组存放月天数 */

int day_of_year(int y, int m, int d)

{ int i, leap;

int tab[2][13] = {

{0,31,28,31,30,31,30,31,31,30,31,30,31}

{0,31,29,31,30,31,30,31,31,30,31,30,31} };

leap = (y%4==0 && y%100!=0) || y%400==0;

for(i=1; i<m; i++)

d += tab[leap][i];

return d;

}

例 7-10 程序

Page 57: Chap 7   数 组

int day_of_year(int y, int m, int d){ switch( m-1 ) /* 不用数组 */ { case 11: d += 30; case 10: d += 31; case 9: d += 30; case 8: d += 31; case 7: d += 31; case 6: d += 30; case 5: d += 31; case 4: d += 30; case 3: d += 31; case 2: d+=28+(y%4==0&&y%100!=0||y%400==0); case 1: d += 31; } return d;}

例 7-10 程序

Page 58: Chap 7   数 组

7.3 判断回文【例 7-11 】输入一个以回车结束的字符串 (少于 10个字符 ) ,判断该字符串是否是回文?所谓回文就是字符串中心对称,如 "abcba" 、 "abccba" 是回文, "abcdba" 不是回文。

7.3.1 程序解析7.3.2 一维字符数组7.3.3 字符串7.3.4 使用字符串编程

Page 59: Chap 7   数 组

7.3.1 程序解析【例 7-11 】输入一个以回车结束的字符串 (少于 1

0个字符 ) ,判断该字符串是否是回文?所谓回文就是字符串中心对称,如 "abcba" 、 "abccba" 是

回文, "abcdba" 不是回文。

分析: 新内容:字符串

Page 60: Chap 7   数 组

例 7-11 程序# include <stdio.h>

int main(void) { int i, n, m; char s[10]; printf("Enter a string: "); i = 0; while((s[i] = getchar( )) != '\n') i++; s[i] = '\0'; for(n = 0,m = i-1; n < m;n++,m--) if(s[n] != s[m]) break; if( n >= m) printf("It is a plalindrome\n"); else printf("It is not a plalindrome\n"); return 0;}

Enter a string: abcbaIt is a plalindrome

Enter a string: abcdbaIt is not a plalindrome

Page 61: Chap 7   数 组

7.3.2 一维字符数组 一维字符数组用于存放字符型数据。其定义、引用、初始化与其他类型的一维数组相同。 定义: char str[81]; 初始化: char s[6]={'H','a','p','p','y','\0'};

char s[6]={"Happy"};

char s[6]="Happy"; 允许只给部分元素赋初值 ( 其余元素初始化为 0) : char s[81] = {'H','a','p','p','y'};

char s[81] = { 0 };

Page 62: Chap 7   数 组

7.3.2 一维字符数组 如对全部元素都赋初值,可缺省数组长度,数组 长度为初值表中初值的个数。 char s[ ] = {'H','a','p','p','y','\0'};

char s[ ] = "Happy"; 对数组未指定初始化

自动类型数组,各元素的值是随机的未知值。全局数组和静态数组,各元素值则会自动初始 化为 0 。

编译时,不检查数组元素的下标是否越界。

Page 63: Chap 7   数 组

1. 对字符串的约定 字符串是借助于字符数组来存放的,规定以字符'\0' 作为“字符串结束标志”。 '\0' 占用存储空间,但

不计入字符串长度。 '\0' 的 ASCII码值为 0 。2. 字符串常量的约定 C 语言中没有字符串变量,但却允许使用字符串常量,用一对双引号括起来的字符序列来表示,其隐式包含最后的结束标志 '\0' ,无需人为添加。 "A" 存储 : 'A' 存储 : "" 存储 :

7.3.3 字符串

'A' '\0' '\0''A'

Page 64: Chap 7   数 组

7.3.3 字符串3. 字符数组与字符串的区别 字符数组可以存放一串字符,但并不限定最后一 个字符应该是什么。而字符串最后必须是 '\0' 。 在字符数组中的有效字符后加上 '\0'这一特定情况 下,可以把它“看作”字符串变量,但又不同于一 般的变量。 存储字符串是字符数组的一种具体应用。 一般,一维字符数组存放一个字符串,二维字符 数组则可每行存放一个字符串。

Page 65: Chap 7   数 组

7.3.3 字符串4. 字符数组存储字符串— 数组初始化 , 赋值和输入 数组初始化 char s[81] = "China"; 赋值 char s[81]; s[0]='C'; s[1]='h'; s[2]='i'; s[3]='n';

s[4]='a'; s[5]='\0'; 输入 ( 按目前的知识 ) char s[81]; int i;

for : for(i=0; (s[i] = getchar()) != '\n'; i++);

s[i] = '\0';

Page 66: Chap 7   数 组

7.3.3 字符串while : i = 0;

while((s[i++] = getchar()) != '\n');

s[--i] = '\0';

或: i = 0;

while((s[i] = getchar()) != '\n') i++;

s[i] = '\0';do-while : i = 0;

do s[i] = getchar();

while(s[i++] != '\n');

s[--i] = '\0';

Page 67: Chap 7   数 组

7.3.3 字符串5. 对字符数组中字符串的操作 ( 遍历字符串 ) 遍历字符串时 , 一般以是否到达结束符 '\0'来控制。 for(i = 0; s[i] != '\0'; i++) { …… }【例 7-12 】输入一个以回车符结束的字符串 ( 少于10 个字符 ) ,过滤所有非数字字符后转成十进制整数输出。分析:可用以下语句实现数字字符串转十进制整数 for(n = i = 0; str[i] != '\0'; i++) n = n * 10 + (str[i] - '0');

Page 68: Chap 7   数 组

例 7-12 程序#include <stdio.h>

int main(void){ int i, number; char str[10]; printf("Enter a string: ");   /* 输入字符串 */ for(i = 0;(s[i] = getchar( )) != '\n'; i++); str[i] = '\0'; number = 0; /* 将字符串转换为整数 */ for(i = 0; str[i] != '\0'; i++) if(str[i] >= '0' && str[i] <= '9') number = number * 10 + (str[i] - '0'); printf("digit = %d\n", number); return 0;}

Enter a string: ab1cb23adigit = 123

Page 69: Chap 7   数 组

7.3.4 使用字符串编程【例 7-13 】输入一个以回车结束的字符串 (少于 8

0

个字符 ) ,统计其中数字字符的个数。

Page 70: Chap 7   数 组

#include <stdio.h>int main(void){ int count, i; char str[80];  printf("Enter a string:"); for(i = 0; (str[i] = getchar( )) != '\n'; i++); str[i] = '\0'; for(count = i = 0; str[i] != '\0'; i++) if(str[i] <= '9' && str[i] >= '0') count++; printf("count = %d\n", count); return 0;}

例 7-13 程序

运行结果 :Enter a string:It's 512count = 3

Page 71: Chap 7   数 组

7.3.4 使用字符串编程【例 7-14 】输入一个以回车结束的字符串 ( 少于

80

个字符 ) ,滤去所有的非十六进制字符后,组成一个新字符串 ( 十六进制形式 ) ,输出该字符串并将

其转换为十进制数后输出。

Page 72: Chap 7   数 组

#include <stdio.h>int main(void){ int i, k; long number; char str1[80], str2[80];  printf("Enter a string:"); for(i=0; (str1[i]=getchar( )) != '\n'; i++); /* 输入 */ str1[i] = '\0'; for(k=i=0; str1[i] != '\0'; i++) /* 虑去非 16 进制字符

*/ if( str[i] >= '0' && str[i] <= '9' || str[i] >= 'a' && str[i] <= 'f' || str[i] >= 'A' && str[i] <= 'F' ) str2[k++]=str1[i]; str2[k]='\0';

例 7-14 程序

Page 73: Chap 7   数 组

例 7-14 程序 for(number=i= 0; str2[i] != '\0'; i++)

if(str2[i]>= '0'&&str2[i]<= '9') /*16 进制转 10 进制 */ number = number*16 + str2[i] - '0'; else if(str2[i] >= 'a' && str2[i] <= 'f') number = number*16 + str2[i] - 'a'+10; else number = number*16 + str2[i] - 'A'+10; printf("New string:"); for(i = 0; str2[i] != '\0'; i++) /* 输出 16 进制串 */ putchar(str2[i]); printf("\nnumber=%ld\n",number); /* 输出 10 进制 */ return 0;}

运行结果 :Enter a string:zx1ma0!kbqNew string:1a0bnumber=6667

Page 74: Chap 7   数 组

本章总结 一维数组:

定义、初始化、引用 使用一维数组:选择排序

二维数组 定义、初始化、引用 使用二维数组:矩阵

字符串 字符数组与字符串 字符串的存储 字符串的操作

使用数组进行程序设计

Page 75: Chap 7   数 组

本章结束