以下每行php 输出数组8个数据的方式,来php 输出数组a数组

| 漏洞检测 |
| 隐藏捆绑 |
C语言 有一个整形数组a,有10个元素,要求输出数组中的全部元素
有一个整形数组a,有10个元素,要求输出数组中的全部元素 解题思路:引用数组中各元素的值有3种方法:1.下标法,如a[3];2.通过数组名计算数组元素的地址,找出元素的值 3.用指针变量指向数组元素。 //用指针变量指向数组元素#include int main(){int a[10];int
解题思路:引用数组中各元素的值有3种方法:1.下标法,如a[3];2.通过数组名计算数组元素的地址,找出元素的值
3.用指针变量指向数组元素。
//用指针变量指向数组元素
int main()
int a[10];
printf(&请输入整数\n&);
for(i=0;i&10;i++)
scanf(&%d&,&a[i]);
for(p=a;p&(a+10);p++)
printf(&%2d&,*p);
printf(&%\n&);
//通过数组名计算数组元素地址
int main()
int a[10];
printf(&请输入10个整数\n&);
for(i=0;i&10;i++)
scanf(&%d&,&a[i]);
for(i=0;i&10;i++)
printf(&%2d&,*(a+i));
printf(&%\n&);
int main()
int a[10];
printf(&请输入10个整数\n&);
for(i=0;i&10;i++)
scanf(&%d&,&a[i]);
for(i=0;i&10;i++)
printf(&%2d&,a[i]);
printf(&%\n&);
(责任编辑:幽灵学院)
------分隔线----------------------------
空指针NULL在C语言中,如果一个指针不指向任何数据,我们就...
> 软件开发 > C语言 > 正文C语言中模拟实现strcpy,strstr,st...
#define _CRT_SECURE_NO_WARNINGS 1#includestdio.h#include...
符号:^ 按位异或,规则:相同为零,相异为一。 实际举例:...
今天学习了C语言不定参数,C语言中的不定参数主要靠strarg.h...
问题描述: 两个int(32位)整数m和n的二进制表达中,有多少...
工作日:9:00-21:00
周 六:9:00-18:00
&&扫一扫关注幽灵学院数组-海文库
全站搜索:
您现在的位置:&>&&>&理学
高级语言程序设计 (C语言描述)陆黎明 朱媛媛 蒋 培 编著 科学出版社日星期一 第4章 数 组2013.1第1页 上海师范大学 计算机系 4.1.1 一维数组的定义? 前面章节中所使用的基本数据类型变量称为简单变量。但在 实际编程时往往需要处理大量具有相同性质的数据,这时仅 用简单变量处理实际问题就显得很不方便。例如,输入50个 学生的学号和某门课程的成绩,输出低于平均分的学生的学 号和成绩。 ? 要想如数学中使用下标变量ai形式存放这50个成绩,则可以 引入下标变量a[i]。这些按序排列的同类数据元素的集合称 为数组。 ? 使用数组必须先进行定义,一维数组定义的一般形式为: 类型标识符 数组名[常量表达式]; 其中,类型标识符可以是任一种基本数据类型或构造数据类 型。数组名是用户定义的数组标识符。方括号中的常量表达 式表示数据元素的个数,也称为数组的长度。例如: int a[10]; float b[10],c[20]; char ch[20];日星期一 第4章 数 组 第2页 上海师范大学 计算机系 4.1.1 一维数组的定义? 关于数组定义还有以下几点需要说明: (1) 数组的类型实际上是指数组元素的取值类型。 (2) 允许在同一个变量定义中,定义多个数组和多个变量,但数 组名不能与其它变量名相同。例如: int a,b,c,d, a[10],b[20]; 是非法的 (3) 方括号中常量表达式必须是整型,如a[5]表示数组a有5个元 素。但是其下标从0开始计算,因此5个元素分别为a[0]、 a[1]、a[2]、a[3]、a[4]。 (4) 不能在方括号中用变量来表示元素的个数,但是可以是符号 常数或常量表达式。例如:#define N 5 合法 int a[3+2],b[N+1];……日星期一 第4章 数 组int n=5; int a[n]; ……第3页非法上海师范大学 计算机系 4.1.1 一维数组的定义(5) 定义了一维数组以后, 每个数组元素都有确定 的内存单元,它们按元 a或&a[0],2000 素下标顺序排列。要得 到某一元素的内存单元 &a[1],2004 地址同简单变量一样, &a[2],2008 可用&运算符,如&a[0], &a[3],2012 &a[3]等。而数组名a是 整个数组的首地址,是 &a[4],2016 地址常量,与元素a[0] 的地址相同,见右图。a[0] a[1]a[2] a[3] a[4]日星期一第4章 数组第4页上海师范大学 计算机系 4.1.2 一维数组的初始化数组初始化赋值是指在数组定义时给数组元素赋予初值。数 组初始化是在编译阶段进行的,这样将减少运行时间,提高 效率。初始化赋值的一般形式为: 类型标识符 数组名[常量表达式]={值,值,…,值}; 例如: int a[5]={ 3,4,5,6,7 }; 相当于a[0]=3; a[1]=4; a[2]=5; a[3]=6; a[4]=7; C语言对数组的初始化赋值还有以下几点规定: (1) 可以只给部分元素赋初值。例如:int a[5]={3,4}; 表示 a[0]=3,a[1]=4,其他元素自动赋初值0。日星期一第4章 数组第5页上海师范大学 计算机系 4.1.2 一维数组的初始化(2) 只能给元素逐个赋初值,不能给数组整体赋初值。例如: int a[5]={1,1,1,1,1}; 而不能写为:int a[5]=1; (3) 若给全部元素都赋初值,则在数组定义时可以不给出数组的 长度。例如: int a[5]={ 3,4,5,6,7 }; 等价于 int a[ ]= { 3,4,5,6,7 }; (4) 若在数组定义时没有给数组赋初值,则全部元素的初值不确 定,而不是为0。日星期一第4章 数组第6页上海师范大学 计算机系 4.1.3 一维数组元素的引用? 数组元素也是一种变量,其一般形式为: 数组名[下标表达式] 其中的下标表达式只能为整型常量或整型表达式,不能为小 数。例如,a[3],a[i+j],a[i++]都是合法的数组元素,而a[3.6] 则是非法的。[]在C语言中称下标运算符,它里面的整数表示 离开数组名(首地址)几个元素,例如,a[1]离开数组名1个 元素(相隔a[0])。 ? 在C语言中,数组作为一个整体,不能参加输入、输出等操 作,只能对单个数组元素进行处理。例如,若要输出有10 个 元素的整型数组必须使用循环语句逐个输出各数组元素: for (i=0; i&10; i++) printf(&%d&, a[i]); 而不能用一句语句“printf(&%d&, a);”输出整个数组。日星期一 第4章 数 组 第7页 上海师范大学 计算机系 4.1.3 一维数组元素的引用? 数组元素通常也称为下标变量。必须先定义数组,才能使用 下标变量。下标变量的使用规则等同于相同类型的简单变量。? 要特别强调的是,在程序的编译和运行过程中,系统并不会 自动检查数组元素的下标是否越界。因此这种错误不易发现 而且往往会造成严重的后果,初学者必须避免下标越界。例4.1 用数组来输出Fibonacci数列的前20个数。 分析:Fibonacci数列的定义为:当n=1或2时fib1=fib2=1, 当n≥3时fibn= fibn-1+ fibn-2 。用数组中的下标变量来表示数 学中的下标变量显得直接而方便。日星期一第4章 数组第8页上海师范大学 计算机系 4.1.3 一维数组元素的引用#include &stdio.h& int main() { long f[20]={1,1}; /* 数组部分元素初始化 */ for (i=2; i&20; i++) /* 这里不提倡条件写成i&=19的形式 */ f[i]=f[i-2]+f[i-1]; for (i=0; i&20; i++) { printf(&%6ld&, f[i]); if ((i+1)%5==0) printf(&\n&); /* 每行输出5个数 */ } return 0; }例4.2 输入8个数,输出其中的最大值以及它的下标。 分析:本例显然要用到数组,与上一章例题中找最大值不同 的是,本例中不但要找出最大值,还要记住它的下标,因此 要增加一个变量来存放下标。日星期一 第4章 数 组 第9页 上海师范大学 计算机系 4.1.3 一维数组元素的引用#define N 8 #include &stdio.h& int main() { int i, float a[N], /* pmax存放最大值的下标 */ printf(&请输入%d个数:\n&, N); for (i=0; i&N; i++) scanf(&%f&, &a[i]); max=a[0]; pmax=0; /* 首先假定第1个数是最大的 */ for (i=1; i&N; i++) if (a[i]&max) { max=a[i]; pmax=i; } /* 必须同时记住它的下标 */ printf(&最大值:a[%d]=%f\n&, pmax,max); return 0; } 请输入8个数: ? 运行结果: 71 64 82 77 83 76 95 78 最大值:a[6]=95.000000日星期一 第4章 数 组 第10页 上海师范大学 计算机系 4.1.4 一维数组应用举例数组主要用来存放大量具有相同性质的数据,但合理利用数 组也可以起到简化程序、便于编程等其他作用,下面就通过 几个例子来说明如何合理利用数组。 例4.3 输入年份和月份,输出该月的天数。 分析:一个月的天数有28或29(闰年)或30或31四种情况, 如果不用数组,就要用到if语句或switch语句来区分这四种 情况,程序显得长且繁。如果事先将每个月的天数放到数组 中,月份作为下标直接去读取,程序就显得非常简洁且易读。 由于月份从1开始,而数组的下标从0开始,所以程序中的数 组多定义了1个元素,以方便读取天数。日星期一第4章 数组第11页上海师范大学 计算机系 4.1.4 一维数组应用举例#include &stdio.h& int main() { int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int y,m,d; /* 省去了数 组的长度 */printf(&请输入年份和月份(yyyy-mm): &); scanf(&%d-%d&, &y,&m); /* 假定输入的年份和月份是合法的 */ d=days[m]; if ( (m==2) && (y%4==0 && y%100!=0 || y%400==0) ) d++; printf(&该月有%d天\n&, d); return 0;} ? 运行结果:请输入年份和月份(yyyy-mm): 2012-2该月有29天日星期一 第4章 数 组 第12页 上海师范大学 计算机系 4.1.4 一维数组应用举例例4.4 输入8个学生的成绩,统计并输出其中的优、良、中、及 格、不及格的人数。分析:百分制成绩score的范围为0~100,五级制成绩的标 准为:90分以上为优;80~89为良;70~79为中;60~69为 及格,60分以下为不及格。如果不用数组,就要用到if语句 或switch语句以及五个计数器来分别统计优、良、中、及格、 不及格的人数。如果用score/10-5作为下标(当下标为负数 时改为0,都对应不及格),对应的数组元素作为计数器就 可以简化程序。本例主要说明如何巧用下标,成绩的个数同 样可以通过修改符号常量的定义来扩大。#define N 8日星期一第4章 数组第13页上海师范大学 计算机系 4.1.4 一维数组应用举例#include &stdio.h& int main() { int score,i,n,c[6]={0}; printf(&请输入%d个百分制成绩(0~100):\n&, N); for (i=0; i&N; i++) { scanf(&%d&, &score); /* 这里假定输入的成绩是有效的 */ n=score/10-5; /* n的取值范围为-5~5, 当n为5或4时对应的成绩为优 */ if (n&0) n=0; /* 当n取值为-5~0时对应的成绩不及格 */ c[n]++; /* c[n]为计数器 */ } printf(&优:%d 良:%d 中:%d 及格:%d 不及格:%d\n&, c[5]+c[4],c[3],c[2],c[1],c[0]);return 0; } 运行结果: 请输入8个百分制成绩(0~100): 71 64 82 47 83 76 95 78 优:1 良:2 中:3 及格:1 不及格:1第4章 数 组 第14页 上海师范大学 计算机系?日星期一 4.1.4 一维数组应用举例例4.5 输入一个正整数,输出它对应的二进制数。 分析:第1章中已介绍过,十进制正整数转换成对应的二进 制数的方法是“除2取余”,困难在于第一个余数要最后输 出,最后一个余数要第一个输出。如果不用数组,编程很困 难。而如果把所有的余数都存放到数组中,那么只要反序输 出数组元素的值就可以了。另外,本例中也充分说明了自增、 自减运算符前置运算和后置运算的区别和用处。 #include &stdio.h& int main()日星期一第4章 数组第15页上海师范大学 计算机系 4.1.4 一维数组应用举例{ int a,n,bits[64]; /* 正整数对应的二进制数最多64位 */ printf(&请输入一个正整数: &); scanf(&%d&, &a); n=0; /* n中存放对应的二进制数的位数 */ do { /* 因为对应的二进制数至少有1位,适合用do-while语句 */ bits[n++]=a%2; /* 必须用后置运算, 这样第一个余数才能放到下标0处 */ a /= 2; }while (a!=0); printf(&对应的二进制数为: &); while (--n&=0) /* 必须用前置运算, 如果n=2,这两位是放在下标1和0处 */ printf(&%d&, bits[n]); printf(&\n&); return 0; } ? 运行结果: 请输入一个正整数: 83对应的二进制数为: 1010011第4章 数 组 日星期一 第16页 上海师范大学 计算机系 4.1.4 一维数组应用举例例4.6 用“筛法”找出3~100之间的全部素数,每输出10个素 数后换行。 分析:上一章中在介绍break语句时,已经做过本题目,筛 法是公元前古希腊数学家Eratosthenes发明的一个更为高效 的求不超过某一个正整数N的全部素数的算法。为了方便解 释算法,假定N=30。(1) 将3~30之间的全部奇数组成一个集合(这个集合称为“筛”): {3,5,7,9,11,13,15,17,19,21,23,25,27,29} (2) 集合中的最小数3就是素数,把集合中3的倍数(6, 9, 12, …)全部去掉 得到新的集合: {3,5,7,9,11,13,15,17,19,21,23,25,27,29} (3) 集合中除了3以外的最小数5就是素数,把集合中5的倍数(10, 15, 20, …)全部去掉得到新的集合: {3,5,7,9,11,13,15,17,19,21,23,25,27,29}日星期一 第4章 数 组 第17页 上海师范大学 计算机系 4.1.4 一维数组应用举例(4) 集合中除了3,5以外的最小数7就是素数,把集合中7的倍数(14, 21, 28) 全部去掉得到新的集合: {3,5,7,9,11,13,15,17,19,21,23,25,27,29} (5) 这样一直进行下去,直到得到的新的素数大于 N 为止(因为7& 30 ,所 以(4)白做)。 请读者思考为什么得到的新的素数大于 N 就可以结束算法。 要实现这个最基本的筛法,关键是如何表示集合?由于C语言中没有集 合数据类型,因此想到是否可以用数组类型来实现?答案是可以的,设 有定义int a[N+1]; 则置a[i]=0表示数i不在集合中,而置a[i]=1表示数i在 集合中。本例主要说明如何用数组记录状态信息。 #define N 100 #include &stdio.h& #include &math.h& int main()日星期一第4章 数组第18页上海师范大学 计算机系 4.1.4 一维数组应用举例{ int i,j,k,c,a[N+1]={0}; for (i=3; i&N+1; i+=2) a[i]=1; /* 生成3~N之间全部奇数组成的集合 */ for (k=sqrt(N),i=3; i&=k; i+=2) if (a[i]) /* 若a[i]=1,则i是素数 */ for (j=2*i; j&N+1; j+=i) a[j]=0; /* 集合中i的倍数全部去掉 */ for (c=0,i=3; i&N+1; i+=2) if (a[i]) { printf(&%5d&,i); c++; /* 统计素数个数的计数器加1 */ if (c%10==0) putchar('\n'); /* 输出10个数后换行 */ } putchar('\n'); return 0; } 3 5 7 11 13 17 19 23 29 31 ? 运行结果: 37 41 43 47 53 59 61 67 71 7379日星期一838997组 第19页 上海师范大学 计算机系第4章 数 4.1.4 一维数组应用举例例4.7 输入8个整数,用“冒泡法”对这8个数从小到大排序。 分析:冒泡法排序的基本思想是将相邻两个数进行比较,使 小的数在前,大的数在后。设有N个数要从小到大排序,它 们存放在从下标1到下标N的数组a中,排序过程为:71 95 83 46 74 68 87 52 46 71 95 83 52 74 68 87 52 71 95 83 68 74 8768 71 95 83 74 8771 74 95 83 8774 83 95 8783 87 9587 95第1趟第2趟第3趟第4趟第5趟第6趟第7趟#define N 8 #include &stdio.h& int main()日星期一 第4章 数 组 第20页 上海师范大学 计算机系 4.1.4 一维数组应用举例{ int i,j,t,a[N+1]; /* a[0]不用 */ printf(&请输入%d个整数:\n&, N); for (i=1; i&N+1; i++) scanf(&%d&, &a[i]); for (i=1; i&N; i++) /* 共N-1趟冒泡排序 */ for (j=N-1; j&=i; j--) /* 下标在N~i范围内的数两两比较, 若逆序,则交换 */ if (a[j]&a[j+1]) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } printf(&排序后:\n&); for (i=1; i&N+1; i++) printf(&%d &, a[i]); putchar('\n');return 0; } 运行结果: 请输入8个整数: 71 95 83 46 74 68 87 52 排序后: 46 52 68 71 74 83 87 95第4章 数 组?思考题:如何修改程 序使得当第i次循环没 有发生交换时,提前 结束外循环?上海师范大学 计算机系日星期一第21页 4.1.4 一维数组应用举例例4.8 输入8个整数,用“选择法”对这8个数从小到大排序。 分析:选择法排序的基本思想是每趟选择一个最小数,把它 放到希望的位置上。设有N个数要从小到大排序,它们存放 在从下标1到下标N的数组a中,排序过程为:71 95 83 46 74 68 87 52 46 95 83 71 74 68 87 52 52 83 71 74 68 87 9568 71 74 83 87 9571 74 83 87 9574 83 87 9583 87 9587 95第1趟第2趟第3趟第4趟第5趟第6趟第7趟#define N 8 #include &stdio.h& int main()日星期一 第4章 数 组 第22页 上海师范大学 计算机系 4.1.4 一维数组应用举例{ int i,j,k,t,a[N+1]; /* a[0]不用 */ printf(&请输入%d个整数:\n&, N); for (i=1; i&N+1; i++) scanf(&%d&, &a[i]); for (i=1; i&N; i++) /* 共N-1趟选择排序 */ { k=i; /* 在下标为i~N的范围内找最小数,k中存放最小数的下标 */ for (j=i+1; j&=N; j++) if (a[j]&a[k]) k=j; if ( k!=i ) /* 若第i个最小数不在希望的下标i处,则交换 */ { t=a[i]; a[i]=a[k]; a[k]=t; } } printf(&排序后:\n&); for (i=1; i&N+1; i++) printf(&%d &, a[i]);putchar('\n');return 0; ? } 运行结果:请输入8个整数: 71 95 83 46 74 68 87 52 排序后: 46 52 68 71 74 83 87 95第4章 数 组 第23页 上海师范大学 计算机系日星期一 4.1.4 一维数组应用举例例4.9 输入一个整数,用“二分法”在有序的数据集中查找该 数是否存在。 分析:顺序查找法最大的缺点是效率太低,若数据集中有N 个数,最坏情况下要比较N次,假定N=109,可能就无法接 受了。二分法查找的速度很快,同样假定N=109,则比较的 次数不超过30次。设有序数据集从小到大排列存放在一维数 组a中,待查找的数为x,查找过程为:将数组的最小下标记作low,最大下标记作high,取它们的中间值 mid=(low+high)/2。若x=a[mid],则已找到;否则的话,若x&a[mid], 则low=mid+1;若x&a[mid],high=mid-1后再求mid=(low+high)/2。 如此循环可以很快确定是否可以找到其值为x的元素,若找不到会出现 low&high的现象。 #define N 8 #include &stdio.h& int main()日星期一第4章 数组第24页上海师范大学 计算机系 4.1.4 一维数组应用举例{ int a[N+1]={0,46,52,68,71,74,83,87,95}; /* a[0]不用 */ int low,high,mid,x; printf(&请输入要查找的整数: &); scanf(&%d&, &x); low=1; high=N; while (low&=high) { mid=(low+high)/2; if (x==a[mid]) else if (x&a[mid]) low=mid+1; else high=mid-1; } if (low&=high) printf(&数%d的位置是: %d\n&, x,mid); else printf(&数%d找不到\n&, x); return 0; }第4章 数 组 第25页 上海师范大学 计算机系日星期一 4.2.1 二维数组的定义? 二维数组定义的一般形式是:类型说明符 数组名[常量表达式1][常量表达式2] ; 其中常量表达式1和表达式2(都必须是整型)分别表 示第一维(即行)和第二维(即列)的长度。例如: int a[3][4]; 该数组共有3×4=12个元素,即: 概念上 第0列 第0行 a[0][0] 第1行 a[1][0] 第2行 a[2][0] 第1列 a[0][1] a[1][1] a[2][1] 第2列 第3列内存中a[0][0] a[0][1]a[0][2]a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0]a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3]? 二维数组在概念上是二维的,但是,实际的内存储器 却是按一维线性排列的。如何在一维存储器中存放二 维数组的元素?通常可有两种方式:一种是按行存放, 另一种是按列存放。在C语言中,二维数组采用的是 按行存放。例如:int a[3][4]; 该数组在内存中的存 放形式如右图所示。日星期一 第4章 数 组 第26页a[2][1]a[2][2] a[2][3]上海师范大学 计算机系 4.2.2 二维数组的初始化? 最后要说明的是,二维数组可以看作是由一维数组的嵌套而 构成的。设有二维数组a[3][4],它可分解为3个一维数组 (它们都有4个元素),其数组名分别为a[0]、a[1]和a[2]。 对这3个一维数组不需另作定义即可使用,例如:一维数组 a[0]的元素为a[0][0]、a[0][1]、a[0][2]和a[0][3]。关于这一 点后续章节还会继续讨论。 ? 二维数组也可以在定义时给各数组元素赋以初值。二维数组 的初始化有分行赋初值和顺序赋初值两种方法。 (1) 给二维数组所有元素赋初值,例如:int a[3][3]={ {80,75,92}, {85,63,70}, {66,77,82} }; /* 分行赋初值 */ 或 int a[3][3]={ 80, 75, 92, 85, 63, 70, 66, 77, 82 }; /* 顺序赋初值 */日星期一第4章 数组第27页上海师范大学 计算机系 4.2.2 二维数组的初始化(2) 如给二维数组的所有元素都赋了初值,则第一维的长度可以 省略,但第二维的长度不能省略。例如:int a[ ][3]={ {80,75,92}, {85,63,70}, {66,77,82} }; /* 有3行 */ 或 int a[ ][3]={ 80, 75, 92, 85, 63, 70, 66, 77, 82 }; /* 有3行 */(3) 可只对部分元素赋初值,未赋初值的元素自动取0值。例如:int a[3][3]={ {80}, {85}, {66} }; /* 只对每一行的第一列元素赋初值 */ int a[3][3]={ {80}, {85,63}, {66,77,82}}; /* 只对下三角部分元素赋初值 */ int a[3][3]={ {80,75,92}, {0,63,70}, {0,0,82}}; /* 只对上三角部分元素 赋初值 */ int a[3][3]={ {80}, {}, {0,0,82}}; /* 只对第一、三行部分元素赋初值 */ int a[3][3]={ {80,75,92}, {85,63} }; /* 只对第一、二行部分元素赋初值 */ int a[3][3]={ 80, 75, 92, 85, 63 }; /* 只对第一、二行部分元素赋初值 */ 其中最后二句定义的数组a的初值是完全相同的。日星期一 第4章 数 组 第28页 上海师范大学 计算机系 4.2.2 二维数组的初始化(4) 如只对部分元素赋初值,这时省略第一维的长度也是可以 的,但第二维的长度还是不能省略。例如:int a[ ][3]={ {80}, {}, {0,0,82}}; /* 有3行 */ int a[ ][3]={ {80,75,92}, {85,63} }; /* 有2行 */ int a[ ][3]={ 80, 75, 92, 85, 63 }; /* 有2行 */日星期一第4章数组第29页上海师范大学 计算机系 4.2.3 二维数组元素的引用对二维数组元素的引用形式如下:数组名[下标1][下标2] 其中,下标可以是整型常量或整型表达式,不能为小数。注 意:①a[1][2]不能写成a[1,2];②引用二维数组元素时其行 下标和列下标一定不能越界。对二维数组中的元素进行处理 时,常常需要通过循环嵌套来实现。 例4.10 输入一个3×4的矩阵,编程找出每一行中值最大的那 个元素并与第1列交换位置。#include &stdio.h& int main() { int a[3][4], i, j, p, printf(&请输入一个3×4的矩阵:\n&); for (i=0; i&3; i++) for (j=0; j&4; j++)scanf(&%d&, &a[i][j]);日星期一 第4章 数 组 第30页 上海师范大学 计算机系 4.2.3 二维数组元素的引用for (i=0; i&3; i++) { p=0; /* p中存放每行最大元素的列下标,先假定第1列是最大的 */ for (j=1; j&4; j++) if (a[i][j]&a[i][p]) p=j; if (p!=0) { t=a[i][0]; a[i][0]=a[i][p]; a[i][p]=t; } } printf(&最大值交换到第1列后的矩阵:\n&); for (i=0; i&3; i++) { for (j=0; j&4; j++) printf(&%4d&, a[i][j]); printf(&\n&); } return 0; }日星期一 第4章 数 组 第31页 上海师范大学 计算机系 4.2.4 二维数组应用举例例4.11 有一个3×4的矩阵,将其转置后放到另一个二维数组 中并输出转置后的矩阵。分析:原矩阵a为3行4列,那么它的转置矩阵b为4行3列,并且矩阵a的 第i行元素与矩阵b的第i列的元素相同。#include &stdio.h& int main() { int a[3][4]={ {80,75,92,62}, {46,85,63,70}, {52,66,77,82} }; int b[4][3], i, for (i=0; i&3; i++) for (j=0; j&4; j++) b[j][i]=a[i][j]; for (i=0; i&4; i++) { for (j=0; j&3; j++) printf(&%4d&, b[i][j]); 思考题:如何对一个 printf(&\n&); n阶方阵原地转置? } 所谓原地就是指程序 return 0; 中只能用一个数组。 }日星期一 第4章 数 组 第32页 上海师范大学 计算机系 4.2.4 二维数组应用举例例4.12 设有一个4人学习小组,每人有语文、数学、外语、物 理和化学五门课的考试成绩,求每个人的平均成绩。分析:可设一个二维数组a[4][5]存放4个人5门课的成绩,再设一个一维 数组ave[4]存放所求得的每个人的平均成绩。#include &stdio.h& int main() { int i,j,sum,a[4][5]={ {80,84,78,81,82}, {65,46,63,70,73}, {87,93,95,82,88}, {75,74,78,67,77} }; float ave[4]; for (i=0; i&4; i++) { for (sum=0,j=0; j&5; j++) /* 求每个人的总成绩之前,sum必须置0 */ sum += a[i][j]; ave[i]=sum/5.0; } for (i=0; i&4; i++) printf(&%8.2f&, ave[i]); printf(&\n&); return 0; }日星期一 第4章 数 组 第33页 上海师范大学 计算机系 4.2.4 二维数组应用举例例4.13 魔方阵是我国古代发明的一种数字游戏。n阶魔方阵是 指这样一种方阵,它的每一行、每一列以及对角线上的各数 之和为一个常数,这个常数是n(n2+1)/2,被称为魔方阵常数。 这里只考虑n为奇数的情况,下面是一个n=3的魔方阵:4 3 8 9 5 1 2 7 6 分析:对于n为奇数的魔方阵,我国的古人早已找到了求解的方法: (1) 魔方阵中的数由1~ n2的n2个整数组成。 (2) 第一个数1放在中间一行的最后一列。 (3) 下一个数放在何处取决于刚刚放的那个数是否是n的倍数。 (4) 若是n的倍数,则下一个数放在刚刚放的那个数的左边,即行标不变, 列标减1。 (5) 若不是n的倍数,则下一个数放在刚刚放的那个数的右下方,即行标和 列标均加1。若行标或列标加1后超界,则把它置1。 (6) 返回(3),重复上述过程,当最后一个数n2放好后,魔方阵就形成了。日星期一 第4章 数 组 第34页 上海师范大学 计算机系 4.2.4 二维数组应用举例#include &stdio.h& int main() { int a[16][16],n,i,j,k; /* 第0行第0列不用 */ do { /* 本循环保证输入的整数符合要求 */ printf(&请输入一个3~15的奇数: &); scanf(&%d&, &n); }while ( n%2==0 || !(3&=n && n&=15) ); i=(n+1)/2; j=n; /* 第一个数1放在中间一行的最后一列 */ for (k=1; k&=n*n; k++) { a[i][j]=k; if (k%n==0) j--; /* 若刚放的数k是n的倍数,则行标不变,列标减1 */ else { i=i%n+1; j=j%n+1; } /* 行标和列标加1,若超界,则置1 */ } /* 输出数组a中各个元素的值,方法参见例4.11 */ return 0; }日星期一 第4章 数 组 第35页 上海师范大学 计算机系 4.3.1 指针与指针变量? 利用指针变量能表示各种复杂的数据结构;能很方便、灵活 地使用数组和字符串;能像汇编语言一样处理内存地址;能 为实现函数间各类数据的传递提供简洁便利的方法;能编出 精练而高效的程序。能否正确理解和使用指针是检验是否全 面掌握C语言的一个标志。因此,指针也成为C语言学习中 最为困难的一部分。 1、指针的概念 ? 内存储器中每个存储单元都有一个唯一的编号,称为内存地 址。既然根据内存地址就可以准确定位到对应的内存单元, 因此,内存地址通常也称为“指针”。 ? 显然,内存单元的地址和内存单元的内容是两个不同的概念。 内存单元的地址即为该单元的唯一编号,其中存放的数据才 是该单元的内容。日星期一 第4章 数 组 第36页 上海师范大学 计算机系 4.3.1 指针与指针变量? 在C语言中,当定义一个变量时,系统根据它的数据类型为 它分配一定数量的一段连续的存储单元,这段连续的内存单 元的起始地址就是变量的地址,也就是变量的“指针”,而 这些内存单元中存放的数据也就是变量的“值”。 ? 例如,有变量定义int a=100; 并假定int数据类型占用2个字 节的内存空间,系统就为变量a分配2个字节的内存单元,并 将这2个单元的内容修改为100。内存地址变量名 a19980内存单元变量的地址2001变量的值日星期一第4章 数组第37页上海师范大学 计算机系 4.3.1 指针与指针变量2、指针变量 ? 指针是一种数据。在C语言中,允许用一个变量来存放这种 数据,这种变量就称为指针变量。一个指针变量的值就是某 个内存单元的地址,即某个内存单元的指针。 ? 指针变量的定义应包括三方面的内容:①指针类型说明,即 定义变量为一个指针变量;②指针变量名;③基类型,即指 针变量的值(即指针)所指向的变量的数据类型。其一般形 式为: 类型标识符 *变量名; 其中,*表示变量名是一个指针变量,类型标识符即基类型。 ? 例如:int *p1; 表示p1是一个指针变量,它可以用来存放 某个整型变量的地址,也可以说“p1是一个指向整型变量的 指针变量”,或“p1为整型指针变量”。至于p1究竟指向哪 一个整型变量,应由向p1赋予的地址来决定。日星期一 第4章 数 组 第38页 上海师范大学 计算机系 4.3.2 与指针有关的运算指针是一种数据类型,可以进行某些运算,但其运算的种类 是有限的。它只能进行赋值运算和部分算术运算及关系运算。 1、赋值运算 指针变量同普通变量一样,在使用之前不仅要定义,而且必 须赋予具体的值。未经赋值的指针变量不能使用,否则将造 成系统混乱。指针变量的赋值运算有以下几种形式: (1) 指针变量在定义时进行初始化赋值。例如: int a,*pa=&a; (2) 把一个变量的地址赋予基类型与它相同的指针变量。例如: int a,* pa=&a; (3) 两个基类型相同的指针变量可以相互赋值。例如: int a,*pa=&a,* pb=日星期一 第4章 数 组 第39页 上海师范大学 计算机系 4.3.2 与指针有关的运算(4) 把数组的首地址赋予基类型与数组元素类型相同的指针变量。 例如: int a[5],* pa=a; /* 或pa=&a[0]; */ 当然也可采取初始化赋值的方法:int a[5],*pa=a; (5) 把字符串常量的首地址赋予指向字符类型的指针变量。例如: char * pc=&C Language&; 或用初始化赋值的方法写为:char *pc=&C Language&; 上述赋值并不是把整个字符串放入指针变量,而是把存放该 字符串的内存单元的首地址放入指针变量。在后面还将详细 介绍。日星期一第4章 数组第40页上海师范大学 计算机系 4.3.2 与指针有关的运算在进行赋值操作时还应注意: (1) 赋予指针变量的指针值的基类型必须与指针变量的基类型相 同,否则,不能进行赋值操作。例如: int * pa=&a; 是错误的。 (2) 不能把一个整数赋予指针变量。例如: int *p; p=1000; 是错误的。 (3) 被赋值的指针变量前不能再加“*”,例如: int a,b,*pa=&a; *pa=&b; 是错误的。日星期一第4章 数组第41页上海师范大学 计算机系 4.3.2 与指针有关的运算2、运算符&和*(都单目运算符,其结合性都为自右至左) 1) 取地址运算符& ? 其一般形式为:&变量名; ? 其功能是取变量的地址。例如&a表示变量a的地址。 2) 取内容运算符* ? 用来表示指针变量所指的变量。在*运算符之后的操作对象 必须是指针类型的数据。例如: int a=100, b, *p=&a; b=*p; /* 注意:运算符*和定义中的*不是一回事 */ ? 运算符*根据变量p的值(即变量a的地址)去访问对应的存 储单元,也就是变量a。或者说,*p就是指针变量p所指的变 量,*p的数据类型就是指针变量p的基类型。 ? 取地址运算符“&”与取内容运算符“*”是一对逆运算符。 当指针变量p指向变量a后,&*p与p等价,同样*&a与a等价。日星期一 第4章 数 组 第42页 上海师范大学 计算机系 4.3.2 与指针有关的运算内存地址变量名 变量a的地址 变量名 变量b的地址19981999 a
: : 100 100内存单元变量a的值变量名 变量p的地址p 30002000 变量p的值图4.6 变量的间接访问日星期一 第4章 数 组 第43页 上海师范大学 计算机系 4.3.2 与指针有关的运算例4.14 变量的间接访问示例。#include &stdio.h& int main() { int a=100,b,*p=&a; printf(&a=%d *p=%d\n&, a,*p); b=*p; /* b=a; */ printf(&b=%d\n&, b); a=200; printf(&a=%d *p=%d\n&, a,*p); return 0; } ? 需要说明的是,在本例中,要把变量a的值赋给变量b,用赋值语句b=a; 就可以了,为什么要通过指针变量间接访问来赋值呢?本例中确实看不 出间接访问所带来的好处,到下一章函数中指针作函数的参数就能体会 到通过指针变量间接访问变量的作用了。日星期一 第4章 数 组 第44页 上海师范大学 计算机系 4.3.2 与指针有关的运算现在可以来解释上面所提到的两类错误的原因了: (1)int a,b,*pa=&a; *pa=&b; 错误的原因是,*pa的数据类型是 int,而&b是指针类型,两者类型不同,所以不能赋值。 (2)int * pa=&a; 错误的原因是,pa的基类型是int, *pa的数据类型是int。如果pa=&a 合法,则pa指向的是float 型数据,对于*pa系统还是按照int型数据的存储形式来访问 pa所指向的内存单元。由于float型数据与int型数据的存储 形式完全不同,所以这时*pa就不可能得到变量a的数值。日星期一第4章 数组第45页上海师范大学 计算机系 4.3.2 与指针有关的运算3、加减算术运算 1) 指针加或减一个整数 ? 从形式上看指向数组元素的指针变量和指向简单变量的指针 变量的定义是相同的。当指针变量指向数组元素时,可以加 上或减去一个整数n。若有变量定义int a[8], *pa=&a[4]; 则 pa+1、pa-1、pa+n、pa-n、pa++、pa-- 等运算都是合法的。 指针变量加或减一个整数n的意义是把指针指向的当前位置 (某个数组元素)向前或向后移动n个位置。 ? 需要说明的是,指针变量向前或向后移动一个位置和地址加 1或减1在概念上是不同的。如指针变量加1(即向后移动1个 位置)表示指针变量指向下一个数据元素的首地址,而不是 在原地址基础上加1。日星期一第4章 数组第46页上海师范大学 计算机系 4.3.2 与指针有关的运算例如: int a[8],*pa,*pb,* pa=&a[4]; /* pa指向a[4] */ a→ pb=pa+2; /* pb指向a[6] */ pc=pa-2; /* pc指向a[2] */ pc→ ? 一般来说,pa+n的值实际上是pa+n* 每个数组元素所占用的字节数。假定 pa→ int数据类型占用2个字节的内存空间, 数组元素a[4]的地址是2008,若有 pb→ pa=&a[4]; 则pb=pa+2; 后pb的值为 2012。再执行pc=pa-2; 后pc的值为 2004,见右图。2000a[0]200208 a[1]a[2] a[3] a[4] a[5] a[6]2014a[7]日星期一第4章 数组第47页上海师范大学 计算机系 4.3.2 与指针有关的运算? 需要注意的是: (1) 指针常量也可以加或减一个整数。若有int a[8]; 则a+2也是 合法的,它就是a[2]的地址。 (2)对指向简单变量的指针作加减运算是毫无意义的。 (3)要避免指针加或减一个整数后所指的数组元素根本不存在的 情况,例如,若有变量定义int a[8], *pa=a; 则pa-2(或a-2) 就没有意义。 2) 两指针相减 ? 只有指向同一个数组的两个指针之间才能进行相减运算,否 则运算毫无意义。两指针相减的意义是计算两个指针所指向 的数组元素之间相差的元素个数。这个差实际上就是两个指 针值(地址)相减之差再除以该数组元素的长度(字节数)。 很显然,两指针相减后的结果类型是整型。 ? 注意,两个指针不能进行加法运算。日星期一 第4章 数 组 第48页 上海师范大学 计算机系 4.3.2 与指针有关的运算4、关系运算 1) 两指针之间的关系运算 ? 指向同一个数组的两指针之间可进行关系运算,表示它们所 指的数组元素之间的前后关系。例如:若pf1==pf2 或 pf1&pf2 等。 2) 指针还可以与NULL比较 ? 设p为指针变量,若p==NULL成立,则表明p是空指针,它 不指向任何变量;若p!=NULL成立,表示p不是空指针。 ? 空指针是由对指针变量赋予NULL值而得到的。例如: int *p=NULL; /* NULL的定义在stdio.h文件中 */ 对指针变量赋NULL和不赋值是不同的。 ? 最后要说明的是,指针与NULL之间进行除了==和!=以外的 其他比较(如&比较)是没有意义的。日星期一 第4章 数 组 第49页 上海师范大学 计算机系 4.3.3 指针与一维数组? 设有:int a[8], *p;p=&a[0];或p=a; /*数组名是地址常量代 表数组的首地址 */p→a→a[0]? 观察右图,可以看出:(1) p+1,a+1,&a[1]均指向1号元素a[1]。类 推可知p+i,a+i,&a[i]均指向i号元素a[i]。 (2) *(p+i)或*(a+i)就是p+i或a+i指向的数组元 素a[i],所以有*(a+i)=a[i]。在C语言中, “[]” 是下标运算符,它表示a[i]=*(a+i)。 (3) 因为*(a+i)=a[i],所以*(p+i)=p[i],即指向 数组元素的指针变量也可以带下标,也就 是说指向数组元素的指针变量可以作为数 组名使用。日星期一 第4章 数 组p+1→ a+1→a[1]a[2] a[3]p+i→a+i→a[4] a[5] a[6]p+7→ a+7→a[7]第50页上海师范大学 计算机系 4.3.3 指针与一维数组? 引入指针变量后,就可以用下标法或指针法两种方法来访问数组元素了。 用指针法的好处是访问数组元素的效率较高,但可读性没有下标法好, 指针法适合对数组元素的顺序访问,常用于对字符数组中的字符串进行 各种操作。例4.15 指针法访问数组元素示例。#include &stdio.h& int main() { int a[8], *p; printf(&请输入8个整数:\n&); for (p=a; p&a+8; p++) scanf(&%d&, p); /* 这里不能写成&p,因为p本身就是地址 */ printf(&数组a中元素的值:\n&); for (p=a; p&a+8; p++) /* p的值已经改变,所以要重新进行p=a赋值 */ printf(&%d &, *p); /* 指针法访问数组元素 */ printf(&\n&); return 0; }日星期一 第4章 数 组 第51页 上海师范大学 计算机系 4.3.3 指针与一维数组? 对本例还有几点说明:(1) 上面的第二个for语句不能写成: for (p=a; a&(p+10); a++) /* 因为a是常量,a++非法 */ printf(&%d &,*a); (2) 上面的第二个for语句不要写成: for (p=a,i=0; i&10; i++) printf(&%d &,*(p+i)); 用*(p+i)或*(a+i)访问数组元素a[i]的方法称为地址法,但这种方法本质上 就是下标法。地址法访问数组元素的速度与下标法一样,但它又没有下 标法那样直观和简单,因此不建议使用该方法。 (3) 上面的第二个for语句也不要写成: for (p=a,i=0; i&10; i++,p++) /* 因为多用了一个变量i,没有必要 */ printf(&%d &,*p); (4) 上面的第二个for语句也可写成: for (p=a; p&(a+10); ) printf(&%d &,*p++);日星期一 第4章 数 组 第52页 上海师范大学 计算机系 4.3.3 指针与一维数组? 在C语言中,要注意能够区分以下几种运算:(1) *p++=*(p++) (2) *p++≠*(++p) (3) *p++≠(*p)++例4.16 指向数组元素的指针变量作为数组名使用示例。#include &stdio.h& int main() { int a[8]={80,75,92,62,46,85,63,70}, i, *p; printf(&数组a中元素的值:\n&); for (p=a,i=0; i&8; i++) printf(&%d &, p[i]); /*p=a后,p作为数组名使用 */ printf(&\n&); return 0; } ? 本例中确实看不出指向数组元素的指针变量作为数组名使用所带来的好 处,到下一章函数中数组名作函数的参数就能体会到作用了。日星期一 第4章 数 组 第53页 上海师范大学 计算机系 4.3.4 用typedef自定义类型? 要说明的是,typedef只是允许由用户为数据类型取一个 “别名”,而不能创建新的数据类型。使用typedef的一般 形式为: typedef 原类型名 新类型名; 其中原类型名中含有定义部分,新类型名一般用大写字母表 示,以便于区别。 ? typedef的作用主要体现在以下两个方面: (1) 为程序移植提供方便。例如: real a,b,c; (2) 用typedef定义数组、指针、结构体等类型将给编程带来很 大的方便,不仅使程序书写简单而且使意义更为明确,从而 增强了可读性。下面通过两个例子来说明:日星期一 第4章 数 组 第54页 上海师范大学 计算机系 4.3.4 用typedef自定义类型① typedef char STRING30[30]; STRING30 str[6], t,; 完全等价于 char str[6][30], t[30]; 本例充分说明了4.2.1中所述的“一维数组的每个元素都是一 个一维数组,就构成了二维数组。” ② typedef char *POINTER; 表示POINTER是指针类型,指向的是字符类型。然后可用 POINTER来定义变量,如: POINTER s, 完全等价于 char *s, *p; ? 尽管有时也可用宏定义#define来代替typedef的功能,像前 面的作用(1) ,更多的情况下是不能用宏定义来代替typedef 的功能,像前面的作用(2) 。日星期一第4章 数组第55页上海师范大学 计算机系 4.3.5 指针与二维数组1、二维数组的地址 ? 前面介绍过,二维数组可以看作是一个特殊的一维数组,此 一维数组的每一个元素又都是一个一维数组。所以整型二维 数组a[3][4]也可以用下列方法来定义: typedef int ARRAY1[4]; ARRAY1 a[3]; ? 那么,数组a就是一个一维数组,有3个元素a[0]、 a[1]和 a[2],这3个元素a[i](0≤i≤2)本身是一个一维数组,a[i]是 此数组的数组名,它有4个元素:a[i][0]、a[i][1]、a[i][2]和 a[i][3]。那么数组元素a[i][j] (0≤j≤3)的地址可以表示为 a[i]+j,它等价于*(a+i)+j。所以数组元素a[i][j]的值可以表示 为*(*(a+i)+j),即a[i][j]=*(*(a+i)+j) 。日星期一第4章 数组第56页上海师范大学 计算机系 4.3.5 指针与二维数组? 从下图知,a是二维数组(可以理解为一个一维数组)名,假定它的值为2000, a[0]和*(a+0) 的值也为2000。同理a+1、a[1]和*(a+1)的值都为2008,a+2、a[2] 和*(a+2)的值都为2016 。当然,a、a[0]和*(a+0)都是指针类型,因为它们的值 都是地址。注意,它们都是指针常量。 尽管它们的数值相等,但是指针的类型是不同的。a可以理解为一个一维数组,a 是指向它的元素的指针,即a是指向ARRAY1的指针。a[0]本身是一个一维数组, a[0]也是指向它的元素的指针,即a[0]是指向int的指针。常把a称为行指针,a[0] 称为列指针。从等式a[0]=*(a+0)可知这里的“*”不是取内容,而是起到了把行 指针转换成为列指针的作用。因为指针a与a[0]的基类型不同,所以a+1与a[0]+1 的数值是不同的。?a[0] ↓a04 2006a[1] ↓a+112 2014a[2] ↓a+220 2022↑↑↑↑↑第4章 数 组↑a[2]第57页 上海师范大学 计算机系a[0] a[0]+1 a[0]+2 a[0]+3 a[1]日星期一 4.3.5 指针与二维数组2、指向二维数组元素的指针变量 ? 指向二维数组元素的指针变量的定义形式与指向简单变量的 指针变量的定义形式是相同的,例如: int a[3][4], *p; ? 要说明的是,p=&a[0][0]合法,p=a[0]也是合法的。但p=a 不合法,因为指针变量p与指针常量a的基类型不同。日星期一第4章 数组第58页上海师范大学 计算机系 4.3.5 指针与二维数组例4.17 用地址法或指向二维数组元素的指针访问二维数组元素 示例。#include &stdio.h& int main() { int a[3][4]={80,75,92,62,46,85,63,70,52,66,77,82}, i, j, *p; printf(&用地址法得到的数组a中元素的值:\n&); for (i=0; i&3; i++) for (j=0; j&4; j++) printf(&%d &, *(*(a+i)+j));/* 地址法不建议使用,*(*(a+i)+j)=a[i][j] */ printf(&\n&); printf(&用指向int的指针得到的数组a中元素的值:\n&); for (p=a[0]; p&a[0]+12; p++) /* 二维数组元素在内存中是按行存放的 */ printf(&%d &, *p); /* 所以可以把它理解为有12个元素的一维数组 */ printf(“\n”); /* 除非有特殊原因,否则也不建议这样使用 */ return 0; }日星期一 第4章 数 组 第59页 上海师范大学 计算机系 4.3.5 指针与二维数组3、指向一维数组的指针变量 ? 前面已经介绍过,a、a+1和a+2都是行指针,即指向一维数 组ARRAY1的指针,而且都是常量。定义指向一维数组 ARRAY1的指针变量(即行指针变量)的方法如下: typedef int ARRAY1[4]; ARRAY1 *p; ? 不用自定义类型定义指向一维数组的指针变量的一般形式为: 类型标识符 (*变量名)[长度]; “*变量名”两边必须用圆括号括起来。例如:int (*p)[4]; ? 上面两种方法定义的指针变量p是完全一样的。若有定义int a[3][4]; 现在赋值p=a就合法了,因为这两个指针的基类型相 同。执行p=a后,a[i][j]也可以表示为p[i][j],即指向一维数 组的指针变量可以作为二维数组名使用。日星期一 第4章 数 组 第60页 上海师范大学 计算机系 4.3.5 指针与二维数组例4.18 指向一维数组的指针变量作为二维数组名使用示例。#include &stdio.h& int main() { int a[3][4]={80,75,92,62,46,85,63,70,52,66,77,82}; int i, j, (*p)[4]; printf(&数组a中元素的值:\n&); for (p=a,i=0; i&3; i++) { for (j=0; j&4; j++) printf(&%d &, p[i][j]); /* p=a后,p作为二维数组名使用 */ printf(&\n&); } return 0; } ? 本例中确实看不出指向一维数组的指针变量作为二维数组名使用所带来 的好处,到下一章函数中数组名作函数的参数就能体会到作用了。第4章 数 组 第61页 上海师范大学 计算机系日星期一 4.4.1 字符数组? 一维字符数组常用于存放一个字符串,二维字符数组常用于 存放多个字符串,可以看作是一维字符串数组。 ? 字符数组的定义、初始化,字符数组元素的引用与整型(或 实型)数组相似。 1、字符数组的定义? 例如:char s1[10]; /* 定义了有10个元素的字符数组s1 */ char s2[5][10]; /* 定义了有5×10个元素的二维字符数组s2 */ ? C语言中没有字符串类型,字符串变量是通过一维字符数组来实现的, 当把一个字符串常量(以下称为字符串)存入一个一维字符数组时,也 把结束标志‘\0?存入了该字符数组。 ? 要特别强调的是,字符串总是以'\0'作为结束标志,而字符数组并不要求 它的最后一个字符一定为'\0'。因此一个一维字符数组并不一定可以理解 为一个字符串变量,只有当字符数组中存放了一个字符串,或者说字符 数组中存入了字符串结束标志'\0'时,该字符数组才可以理解为字符串变 量。日星期一 第4章 数 组 第62页 上海师范大学 计算机系 4.4.1 字符数组2、字符数组的初始化(1) 以字符常量的形式对字符数组初始化。例如: char s1[ ]={ 'J','a','v','a'}; /* 数组长度为4 */ (2) 以字符串的形式对字符数组初始化。例如: char s1[ ]={ 'J','a','v','a','\0'}; 可简写为:char s1[ ]={&Java&}; 进一步简写为:char s1[ ]=&Java&; /* 数组长度为5 */ (3) 对二维字符数组作初始化赋值的方法。例如: char s2[2][3]={ {'s', 'u', 'n'}, {'b', 'o', 'y'} }; char s2[2][3]={'s', 'u', 'n', 'b', 'o', 'y'}; (4) 用字符串的形式对二维字符数组作初始化赋值(注意第2维长度加1)。 例如: char s2[2][4]={&sun&, &boy&}; (5) 当对全体元素赋初值时可省去第1维长度定义,但不可以省第2维的。例 如: char s2[ ][3]={'s', 'u', 'n', 'b', 'o', 'y'}; /* 有2行 */ char s2[ ][4]={&sun&, &boy&}; /* 有2行 */日星期一 第4章 数 组 第63页 上海师范大学 计算机系 4.4.1 字符数组3、字符数组的输入输出1) 逐个字符输入/输出。例如:下面的程序段可输出字符数组str中的字符: char str[ ]={'J','a','v','a'}; for (i=0; i&4; i++) printf(&%c&, str[i]); 注意:用scanf逐个读入字符结束后,不会在后面自动加‘\0? 。例如: char str[ ]={'J','a','v','a'}; for (i=0; i&3; i++) scanf(&%c&, &str[i]); 若输入C#&回车&,则str[0]= ?C?,str[1]= ?#?,str[2]= ?\n?,str[3]= ?a? 。 2) 整个字符串输入/输出。如果希望把一个字符串读入存放到字符数组,或 者希望把字符数组中存放的字符串输出,则可采用“%s”格式符来实现。日星期一第4章 数组第64页上海师范大学 计算机系 4.4.1 字符数组? 用“%s”格式符输出字符串时应注意: (1)字符串的结束标志'\0'不输出。 (2)若字符数组中存放的不是字符串,则 不能用“%s”格式符输出。例4.19 格式字符%s示例。#include &stdio.h& int main() { char str[ ]=&Programming&; /* 结束标志'\0'不输出 */ printf(&%s&, str); ? 用“%s”格式符读入字符串时应注意: printf(&请输入一个字符串:&); (1)数组名前不能加“&”运算符。 /* str前不能加& */ (2)读入完毕,会在字符串最后一个字符 scanf(&%s&, str); 的后面自动加结束标志'\0' 。 printf(&%s&, str); (3)系统不会检查字符数组是否有足够的 return 0; 空间来存放字符串和结束标志'\0' 。 }(4)在读入字符串时,遇到“回车”或 “空格”就停止读入(“回车”或 ? 运行结果: “空格”没有被读入,还在输入缓冲 Programming请输入一个字符串:C++ C# 区中)。C++日星期一 第4章 数 组 第65页 上海师范大学 计算机系 4.4.1 字符数组4、指向字符的指针与字符数组 ? 指向字符串的指针变量本质上就是一个指向字符类型的指针 变量(以下称为字符指针变量)。例如: ? char c, *p=&c; 表示p是一个指向字符的指针变量。 ? 而 char *ps=&I love China!&; 则表示ps是一个指向字符 串的指针变量并把字符串常量的首地址赋予ps。 ? 或 char str[]=“I love China!”, *ps= 则表示ps是一个 指向字符串的指针变量并把字符串变量(即字符数组str) 的首地址赋予ps。日星期一第4章 数组第66页上海师范大学 计算机系 4.4.1 字符数组? 初学者对字符指针变量和字符数组往往不能区分它们的不同 而混为一谈,经常造成程序的错误。两者的区别主要体现在:(1) 存储内容不同。字符指针变量存储的是字符串的首地址,不是字符串本 身;而字符数组存储的是字符串本身,数组名这个字符串的首地址。 (2) 字符指针变量的值可以改变;而字符数组名是一个地址常量,其值不能 改变。(3) 赋值方式不同。? 对字符指针变量 char *ps=&C#&; 可以写成:char * ps=&C#&; 注意,写成:char * *ps=&C#&; 是错误的。 ? 对字符数组 char str[3]=&C#&; 不能写成:char str[3]; str=&C#&;要将字符串“C#”存放到数组str中,只能对字符数组的各元素逐个赋 值,或者用strcpy函数。? 程序中常用字符指针变量来访问字符串中的字符从而实现对 字符串的处理,而字符数组主要用来存放字符串。日星期一 第4章 数 组 第67页 上海师范大学 计算机系 4.4.1 字符数组? 还要特别强调的是,当一个指针变量在赋值前就使用是非常 危险的,容易引起错误。例如: ? char str[10]; scanf(&%s&, str); 用法是正确的。 ? 但 char * scanf(&%s&, ps); 用法是错误的。 ? 而 char str[10], *ps= scanf(&%s&, ps); 用法也是正 确的。在不定义数组str的情况下,如何使ps指向确定的 空间,将在后续的章节中介绍。日星期一第4章 数组第68页上海师范大学 计算机系 4.4.2 常用字符串处理函数? 用于输入输出的字符串函数,在使用前 必须包含头文件“stdio.h”;使用其它 字符串函数,则必须包含头文件 “string.h”。 ? 首先要强调的是:只有当字符数组作为 字符串变量使用时,才能用与字符串有 关的处理函数。 1、puts()函数 ? 格式:puts(char *str) ? 注意:与printf不同的是,在用puts输出 字符串时,字符串结束标志‘\0?被转换 成为‘\n?后输出。 2、gets()函数 ? 格式:gets(char *str) ? 注意:函数并不检查字符数组是否有足 够的空间来存放字符串和结束标志'\0' 。 与scanf不同的是,gets函数并不以空 格作为字符串输入结束的标志,而只以 回车作为输入结束的标志。注意:回车 日星期一 第4章 数 组 符被读入并被转换为结束标志'\0' 。例4.20 puts和gets函数 使用示例。#include &stdio.h& int main() { char str[ ]=&Programming&; /* 结束标志'\0? 转换为'\n'后输出 */ printf(&请输入一个字符串:&); gets(str); /* str前不能加& */ puts(str); return 0; puts(str);} ? 运行结果: Programming 请输入一个字符串:C++ C# C++ C#第69页 上海师范大学 计算机系 4.4.2 常用字符串处理函数3、strlen()函数 ? 格式:strlen(char *str) ? 功能:统计str指定的字符串的长度(不包括‘\0?),并将其作为函数值 返回。例如:strlen(&Java&)的返回值为4。 4、strcat()函数 ? 格式:strcat(char *dst, char *src) ? 功能:把src指定的字符串连接到dst指定的字符串的后面(连接前删除 dst原指定的字符串的结束标志‘\0?)。本函数返回值就是dst中的指针 值。 ? 注意,dst指定的字符数组(或内存区域)应有足够的空间来存放被连接 的字符串src。例如:假设字符数组str中存放了一个空字符串,则执行 strcat(strcat(str,“Java”),“&C#”)后,str中的字符串为“Java&C#”。 5、strcpy()函数 ? 格式:strcpy(char *dst, char *src) ? 功能:把src指定的字符串复制到dst为起始地址的字符数组中,结束标 志‘\0?也一同复制。本函数返回值就是dst中的指针值。日星期一 第4章 数 组 第70页 上海师范大学 计算机系 4.4.2 常用字符串处理函数? 注意,dst指定的字符数组应有足够的空间来存放被复制的字符串src。 例如:假设str是字符数组,则执行strcat(strcpy(str,“Java”), “&C#”)后, str中的字符串为“Java&C#”。注意str=“Java”是非法的。例4.21 字符串处理函数使用示例。#include &stdio.h& #include &string.h& /* 因为用了strcpy等字符串处理函数 */ int main() { char name[10], str[30]; printf(&Input your name: &); gets(name); strcpy(str,&My name is &); strcat(str,name); puts(str); /* 本行也可改写为 puts(strcat(str,name)); */ printf(&Length of str: %d\n&, strlen(str)); return 0; Input your name: Mary } 运行结果: My name is MaryLength of str: 15日星期一 第4章 数 组 第71页 上海师范大学 计算机系 4.4.2 常用字符串处理函数6、strcmp()函数 ? 格式:strcmp(char *str1, char *str2) ? 功能:将str1,str2为起始地址的两个字符串进行比较,比 较的结果由返回值表示。 当str1字符串=str2字符串,返回值=0; 当str1字符串&str2字符串,返回值&0; 当str1字符串&str2字符串,返回值&0; ? 注意,字符串之间的比较规则。本函数可用于比较两个字符 串常量,或两个字符串变量,或一个常量与一个变量。例如:表达式 strcmp(“Java”, “C#”) 或 strcmp(str1,str2) 或 strcmp(str1, “Java”)都是合法的。 表达式 “Java”&“C#”,编译系统一般不报错,但不能达到目的,这一 点务必注意。日星期一 第4章 数 组 第72页 上海师范大学 计算机系 4.4.2 常用字符串处理函数例4.22 输入5个字符串,用“选择法”对这5个字符串从小到大排序。#define N 5 #include &stdio.h& #include &string.h& int main() { int i,j,k; char str[N+1][30],t[30]; /* str[0]不用 */ printf(&请输入%d个字符串:\n&, N); for (i=1; i&N+1; i++) gets(str[i]); /* 二维数组作为多个一维数组来使用 */ for (i=1; i&N; i++) { k=i; for (j=i+1; j&=N; j++) if (strcmp(str[j],str[k])&0) k=j; if (k!=i) { strcpy(t,str[i]); strcpy(str[i],str[k]); strcpy(str[k],t); } } printf(&排序后:\n&); for (i=1; i&N+1; i++) puts(str[i]); return 0; }日星期一 第4章 数 组 第73页 上海师范大学 计算机系 4.4.3 字符数组应用举例例4.23 输入一个正长整数,输出它对应的十六进制数。 分析:第1章中已介绍过,十进制正整数转换成对应的十六 进制数的方法是“除16取余”。与例4.5不同的是,必须把 余数10~15转换成字母A~F,如果把所有的余数都以字符的 形式存放到字符数组中,那么只要反序输出该数组元素的值 就可以了。#include &stdio.h& int main()日星期一第4章 数组第74页上海师范大学 计算机系 4.4.3 字符数组应用举例{ int b,n; char hex[9]; /* 正长整数对应的十六进制数最多8位 */ printf(&请输入一个正长整数: &); scanf(&%ld&, &a); n=0; do { b=a%16; hex[n++]=(b&10)?(b+'0'):(b-10+'A'); /* 余数转换成对应的字符 */ a /= 16; }while (a!=0); printf(&对应的十六进制数为: &); while (--n&=0) /* 反序输出字符数组元素的值 */ printf(&%c&, hex[n]); printf(&\n&); return 0;}日星期一 第4章 数 组 第75页 上海师范大学 计算机系 4.4.3 字符数组应用举例例4.24 编写一个程序实现字符串的复制,程序中不能使用 strcpy函数。方法一:下标法#include &stdio.h& int main() { char str1[81], str2[]=&iPad2 & Jobs&; for (i=0; str2[i]!='\0'; i++) str1[i]=str2[i]; str1[i]='\0'; /* 结束标志'\0'也一同复制 */puts(str1);return 0; }日星期一第4章 数组第76页上海师范大学 计算机系 4.4.3 字符数组应用举例例4.24 编写一个程序实现字符串的复制,程序中不能使用 strcpy函数。方法二:指针法 #include &stdio.h& int main() { char *p1, *p2, str1[81], str2[]=&iPad2 & Jobs&; for (p1=str1,p2=str2; *p2!='\0'; p1++,p2++) p1=str1; p2=str2; while (*p2!='\0') *p1=*p2; *p1++=*p2++; *p1='\0'; *p1='\0'; puts(str1); return 0; p1=str1; p2=str2; } while ( (*p1++=*p2++)!='\0' );日星期一第4章 数组第77页上海师范大学 计算机系 4.4.3 字符数组应用举例例4.25输入一行字符,统计其中有多少个单词(单词间以空格分隔)。例如,输 入“I am a student”,4个单词。 分析:单词的数目由空格出现的次数决定(连续出现的空格记为出现一次,每 行开头的空格不算)。用变量num表示单词数,其初值为0。引进一个标志变量 word,word=0表示前一字符为空格,word=1表示前一字符不是空格,word初 值为0。程序逐个检测每一个字符是否为空格,如果前一字符是空格,当前字符 不是空格,就说明出现新单词,num加1。 方法一:下标法 方法二:指针法 int main() int num, char *p, str[81]; { int i,num, char str[81]; puts(&请输入一行字符:&); gets(str); num=word=0; for (p= *p!='\0'; p++) for (i=0; str[i]!='\0'; i++) if (*p==' ') word=0; if (str[i]==' ') word=0; else if (word==0) { word=1; num++; } printf(&该行有%d个单词\n&, num); 请输入一行字符: return 0; I am a student } 运行结果: 该行有4个单词日星期一 第4章 数 组 第78页 上海师范大学 计算机系 4.4.3 字符数组应用举例? 下面的3个例题相对较难一点,可视情况选择讲解。例4.26 编写程序将用户输入的字符串中的每一个十进制数字字 符置换成所对应一个字符串(所有其他字符不变),然后将 置换后的结果显示在屏幕上,并同时输出每个数字字符被置 换的次数。例4.27 编写程序判断一个字符串中的括号{,[,(,),],}是否匹配, 只有左右括号成对出现,并且顺序正确,才叫做“匹配”。 例4.28 超长正整数的加法运算。日星期一第4章 数组第79页上海师范大学 计算机系 4.5.1 指针数组? 数组的元素均为指针类型数据,则称其为指针数组。指针数 组是一组指针变量的集合,这组指针变量的类型必须相同, 即这组指针变量的基类型必须相同。例如: typedef int *POINTER; POINTER p[3]; ? 不用自定义类型定义指针数组的一般形式为: 类型标识符 *数组名[数组长度] 其中类型标识符为指针值所指向的变量的类型,即指针的基 类型。例如:int *p[3]; ? 应该注意指针数组和指向一维数组的指针变量的区别。 int (*p)[3]; 表示p是一个指向一维整型数组的指针变量。 int *p[3]; 表示p是一个指针数组。 ? 显然,利用自定义类型定义指针数组和指向一维数组的指针 变量,可读性强,更容易理解两者的区别。日星期一 第4章 数 组 第80页 上海师范大学 计算机系 4.5.1 指针数组? 如果二维数组是字符型,每行存放了一个字符串,这时指针 数组的每个元素存放了每个字符串的首地址。使用指针数组 处理多个字符串比仅用字符数组更为方便和灵活并能提高运 行效率。 ? 指针数组也可以在定义时给各数组元素赋初值。例如:int a[3][4], *p[3]={ a[0], a[1], a[2] }; char *name[5]={ &Java&, &Pascal&, &C#&, &BASIC&, &FORTRAN&};例4.29 输入5个字符串,用“选择法”通过指针数组对这5个 字符串从小到大排序。#define N 5 #include &stdio.h& #include &string.h& int main() { char str[N+1][30]; char *p[N+1],*t; int i,j,k;日星期一/* str[0]不用 */第4章 数组第81页上海师范大学 计算机系 4.5.1 指针数组printf(&请输入%d个字符串:\n&, N); for (i=1; i&N+1; i++) { gets(str[i]); p[i]=str[i]; } /* p[i]中存放字符串的首地址 */ for (i=1; i&N; i++) { k=i; for (j=i+1; j&=N; j++) if (strcmp(p[j],p[k])&0) k=j; if (k!=i) { t=p[i]; p[i]=p[k]; p[k]=t; } /* 交换两指针 */ } printf(&排序后:\n&); for (i=1; i&N+1; i++) puts(p[i]); /* 下标法访问指针数组元素 */ return 0; }日星期一 第4章 数 组 第82页 上海师范大学 计算机系 4.5.1 指针数组? 本例中引进了指针数组,排序时交换的是指针,字符串本身 没有交换,所以字符数组str排序前后没有变化, 见下图。 而例4.22中,排序时要对字符串本身作交换。 ? 很显然,交换指针比交换字符串要快,特别是当字符串较长 时。当然本例要多用一点内存空间,是典型的以空间换时间。排序前p[0] p[1] p[2] p[3] p[4] Java Pascal C# BASIC str[0] str[1] str[2] str[3] str[4] p[0] p[1] p[2] p[3] p[4]排序后str[0] Java Pascal C# BASIC str[1] str[2] str[3] str[4]p[5]日星期一FORTRAN str[5]第4章 数 组p[5]第83页FORTRAN str[5]上海师范大学 计算机系 4.5.2 指向指针的指针? 如果一个指针变量存放的又是另一个指针变量的地址,则称 这个指针变量为指向指针的指针变量,也称为二级指针变量。 例如: typedef char *POINTER; POINTER * ? 不用自定义类型定义指向指针的指针变量的一般形式为: 类型标识符 **变量名; 其中的类型标识符是指针变量指向的指针变量的基类型。 ? 指针数组名是该数组的首地址,即0号元素的地址。由于0号 元素本身是指针类型,所以一维指针数组名是指向指针的指 针,当然它是常量。日星期一第4章 数组第84页上海师范大学 计算机系 4.5.2 指向指针的指针例4.30 指针法访问指针数组元素示例。#include &stdio.h& int main() { typedef char *POINTER; POINTER name[5]={ &Java&, &Pascal&, &C#&, &BASIC&, &FORTRAN&}; POINTER *p; for (p= p&name+5; p++) puts(*p); /* 指针法访问指针数组元素 */ return 0; }日星期一第4章 数组第85页上海师范大学 计算机系
上一篇: 下一篇:
All rights reserved Powered by
copyright &copyright 。文档资料库内容来自网络,如有侵犯请联系客服。

我要回帖

更多关于 php 输出数组 的文章

 

随机推荐