C程序设计_第五讲:程序设计方法(三)复杂数据结构设计_第1页
C程序设计_第五讲:程序设计方法(三)复杂数据结构设计_第2页
C程序设计_第五讲:程序设计方法(三)复杂数据结构设计_第3页
C程序设计_第五讲:程序设计方法(三)复杂数据结构设计_第4页
C程序设计_第五讲:程序设计方法(三)复杂数据结构设计_第5页
已阅读5页,还剩189页未读 继续免费阅读

下载本文档

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

文档简介

1、高级语言程序设计(一)(C Programming)第五讲:程序设计方法(三)复杂数据结构设计本章目标熟悉二维(多维)数组的使用;掌握指针说明与指针运算;掌握指针与数组的关系;掌握指针作为函数参数;掌握指针数组;掌握结构的定义和使用;了解自引用结构。例5.1求小岛面积用一个二维方阵(最小为5X5,最大为20X20)表示一片海域。方阵中的元素只由0和1组成。1表示海岸线。计算由海岸线围起来的小岛面积(即:由1围起来的区域中0的个数)。如下图所示6X6方阵表示的小岛面积为4:0 0 0 0 0 00 0 1 1 0 00 1 0 0 1 00 1 0 0 1 00 0 1 1 0 00 0 0 0

2、 0 0方阵的最外围都有0组成,不会出现1。【输入形式】先从标准输入中输入方阵的阶数,然后从下一行开始输入方阵的元素(只会输入0或1),各元素之间以一个空格分隔,每行最后一个元素后没有空格,但会有回车换行符。【输出形式】在标准输出上输出用整数表示的小岛面积。【输入样例】60 0 0 0 0 00 0 1 1 0 00 1 0 0 1 00 1 0 0 1 00 0 1 1 0 00 0 0 0 0 0例:求小岛面积100 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 00 0 1 1 1 1 1 0 0 00 1 0 0 0 0 0 1 0 00 0 1 0 0 0 0

3、 1 0 00 0 0 1 0 0 0 1 0 00 0 0 1 0 0 1 0 0 00 0 0 0 1 1 0 0 0 00 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0例:求小岛面积算法1:对于方阵中的任意一个元素0,如果其位于同一行上的两个1之间,并且位于同一列上的两个1之间,则该元素可以算作水面面积。对于阶数为n的方阵sea中的任一元素seaij,若该元素为0,则查找: 左方是否有1:seaik,k从j-1到0 右方是否有1:seaik,k从j+1到n-1 上方是否有1:seakj,k从i-1到0 下方是否有1:seakj,k从i+1到n-1例:求小岛面积

4、#include int main() int sea99; int n,i,j,k,found,area; scanf(%d,&n); for(i=0;in;i+)for(j=0;jn;j+) scanf(%d,&seaij); area=0; for(i=0;in;i+)for(j=0;j=0;k-)if(seaik=1)found+;break;if(!found)continue;for(k=j+1;k=0;k-)if(seakj=1)found+;break;if(found!=3)continue;for(k=i+1;k=0),并且seai-1j=0,则将其进行标记; 同样若下方、

5、左方、右方有元素,并且为0,也将它们进行标记。例:求小岛面积#include int n;void mark(int 50, int , int );int main() int island5050,i,j,area; scanf(%d,&n); for(i=0;in;i+)for(j=0;jn;j+) scanf(%d,&islandij); mark(island,0,0); area=0; for(i=0;in;i+)for(j=0;j0) & islandi-1j=0)mark(island,i-1,j); if( (i+10) & islandij-1=0)mark(island,

6、i,j-1); if( (j+1n) & islandij+1=0)mark(island,i,j+1);问题5.2:旋转矩阵【问题描述】输入一个自然数(2N9),要求输出如下的旋转矩阵,即边长为N*N,元素取值为1至N*N,1在左上角,呈顺时针方向依次放置各元素。N=3时: 1 2 3 8 9 4 7 6 5【输入形式】从标准输入读取一个整数N。【输出形式】向标准输出打印结果。输出符合要求的方阵,每个数字占5个字符宽度,向右对齐,在每一行末均输出一个回车符。【输入样例】 4【输出样例】1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7问题5.2:问题分析显然要用一个

7、 9 x 9的二维整数数组来存放生成的旋转矩阵。问题5.2:算法设计12341213145111615610987若N为所输入的整数(矩阵的阶),则旋转的层数:L= N/2 ABCD设m为当前层(从0开始),num(从1开始)为要填充的数字,则填充方法为:Afor(i=m; iN-m-1; i+) arraymi = num+;Bfor(i=m; iN-m-1; i+) arrayiN-m-1 = num+;Cfor(i=m; iN-m-1; i+) arrayN-m-1N-i-1 = num+;Dfor(i=m; iN-m-1; i+) arrayN-i-1m = num+;注意:当N为奇数

8、时,如N=3,L为1,则只填了一圈数字,中心数字(即最后一个数字)未填。因此,在填完所有层后有:if(N%2 != 0) arrayN/2N/2 = N*N;6x64x42x2N=65x53x31x1N=5问题5.2:算法设计设array99用于存放旋转矩阵,n为旋转矩阵的阶,m为当前填写的层数,初值为0;读入一个整数到n;for(m=0; mn/2; m+)填充当前层(即分别填充A,B,C,D四段);若n为奇数,则填充最后一个数字;问题5.2:代码实现/* c5_1.c */#include#define SIZE 9int main() int arraySIZESIZE;int n,m,

9、 num, i,j;num = 1;scanf(%d,&n);for (m=0;mn/2;m+) for (i=m;in-m-1;i+) arraymi = num+;for (i=m;in-m-1;i+) arrayin-m-1 = num+;for (i=m;in-m-1;i+) arrayn-m-1n-i-1 = num+;for (i=m;in-m-1;i+) arrayn-i-1m = num+;if (n%2)arrayn/2n/2 = num;for (i=0;i n;i+) for (j=0;jn;j+)printf(%5d,arrayij);printf(n);return

10、0;测试应考虑:N=3(正常)N=4(正常)N=2(边界)N=9(边界)问题5.2:常见问题分析本问题一个常见的错误就是数组下标表达式出错,这也是应用数组时常犯的错误。如,本题在调试过程中出现如下问题:Cfor(i=m; iN-m-1; i+) arrayN-m-1N-m-i-1 = num+;Dfor(i=m; iN-m-1; i+) arrayN-m-i-1m = num+;没有考虑到N为奇数的情况(观察下面程序,当输入N=3时的现象)。/* c5_1b.c */#include#define SIZE 9int main() int arraySIZESIZE;int n,m, num,

11、 i,j;num = 1;scanf(%d,&n);for (m=0;mn/2;m+) for (i=m;in-m-1;i+) arraymi = num+;for (i=m;in-m-1;i+) arrayin-m-1 = num+;for (i=m;in-m-1;i+) arrayn-m-1n-i-1 = num+;for (i=m;in-m-1;i+) arrayn-i-1m = num+;for (i=0;i n;i+) for (j=0;jn;j+)printf(%5d,arrayij);printf(n);return 0;问题5.2:另一种解题思路/* c5_1a.c*/#inc

12、lude#define SIZE 9int main() int arraySIZESIZE;int n,m, num, i,j;num = 1;scanf(%d,&n);for (m=0;mn/2;m+) for (i=m;in-m-1;i+) arraymi = num+;for (j=m;jm) arrayji- = num+;while (jm) arrayj-m = num+;if (n%2)arrayn/2n/2 = num;for (i=0;i n;i+) for (j=0;jn;j+)printf(%5d,arrayij);printf(n);return 0;12341213

13、145111615610987ABCD观察每层(圈)填充数据时A,B,C和D段数组下标变化规律,会发现什么?其它方法?例:写一函数交换两个整数的值并返回void swap ( int x, int y)int temp;temp = x;x = y;y = temp;intmain( )int a = 2, b = 3;swap(a, b);return 0;请问a和b是否交换?不能!232332调用swap后调用swap(a,b)如何通过函数调用改变参数的值将在后续章节中介绍。拷贝abxyxy指针指针是一种数据类型;指针变量:存放的是所指对象的地址例如:int *pi;double *pd;

14、char *pc;pi是指向一整数的指针在C语言中,允许指针指向任何类型的对象(可指向基本类型、构造类型),甚至可指向其它指针或指向函数。 为指针赋初值:注意:使用任何指针变量之前必须先让指针指向一个合法的具体对象。通过&(取地址运算符)使指针指向某个对象例:int i = 100;int *pi;pi = &i;100i0 x0100pi0 x0100为指针赋初值(续):例:double i, *pi, *pj;i = 10.24;pi = &i;pj = pi;通过指向同一数据类型的指针赋值i0 x010fpi0 x010f10.24pj0 x010f示例:1)int *pi = 0;in

15、t *pj = 1024;2)char *string;scanf(“%s”, string);3)char *string;strcpy(string, “Hello”);唯一可以赋给指针的整数值:0,表示空指针,一般写成常量NULLNULL;例:4)int i = 1024;int * pi = &i;double * pj = pi;5)int i=10, y=20;int *pi;pi = &i;pi = &y;指针可以在程序运行的不同时刻指向不同的对象期中考试分析公式计算:/2=1+1!/3+2!/(35)+3!/(357)+(n-1)!/(357(2n-1)sin x = x -

16、x3/3! + x5/5! - x7/7! + . + (-1)n-1x2n-1/(2n-1)!cos(x)=x0/0!-x2/2!+x4/4!-x6/6!+(-1)nx2n/(2n)!)集合:5 1 4 32 8 7 9 -65 2 87 10 1 6作业举例:字符串替换【问题描述】 编写程序将一个指定文件中某一字符串替换为另一个字符串。要求:(1)被替换字符串若有多个,均要被替换;(2)指定的被替换字符串,大小写无关。【输入形式】 给定文件名为filein.txt。从控制台输入两行字符串(不含空格,行末尾都有回车换行符),分别表示被替换的字符串和替换字符串。【输出形式】 将替换后的结果输出

17、到文件fileout.txt中。作业举例:字符串替换(续)【样例输入】从控制台输入两行字符串:inout文件filein.txt的内容为:#include void main()FILE * IN;if(IN=fopen(in.txt,r)=NULL)printf(Cant open in.txt!);return;fclose(IN);【样例输出】文件fileout.txt的内容应为:#outclude void maout()FILE * out;if(out=fopen(out.txt,r)=NULL)prouttf(Cant open out.txt!);return;fclose(o

18、ut);作业举例:字符串替换(问题分析)替换一个文件中的字符串?大小写无关?先考虑大小写相关,假如s1字符串要替换成s2字符串;从文件读入一行字符串line;将line中的s1替换成s2?在line中查找到所有s1字符串?在line中查找s1字符串首次出现位置?作业举例:字符串替换(算法分析)文件0120line01给定串01给定串i=0;while(linei != 0) for(j=i,k=0; s1k != 0; j+,k+) 若 linej != s1k 则退出循环; 若 s1k=0 ,则找到s1; else i+;在line中查找s1的首次出现:作业举例:字符串替换(算法分析)在li

19、ne中查找s1的多次出现:i=0;while(linei != 0) for(j=i,k=0; s1k != 0; j+,k+) 若 linej != s1k 则退出循环; 若 s1k=0 则:找到s1; i = j; else i+;作业举例:字符串替换(算法分析)将line中的s1替换为s2输出:i=0;while(linei != 0) for(j=i,k=0; linej!=0&s1k != 0; j+,k+) 若 linej != s1k 则退出循环; 若 s1k=0 , 则:找到s1; 输出s2; i = j; else 输出linei; i+;如何取得指针所指向的数据值?通过 *

20、 一元运算符(解寻址或解引用运算符)例:int i = 10, y = 20, *pi;pi = &i;y = *pi;pi所指的对象10200 x1000 x100pi=&ipiy10y=*pii当pi指向i时,*pi就等同于i例:(1)int x = 1;int *pi;*pi = x;(2)int x = 1,y=2;int *pi = &y;*pi = x;当pi指向具体对象y时,*pi为pi所指的对象,以后凡是对y的引用,都可用*pi来代替。例:写一函数交换两个整数的值并返回void swap ( int x, int y)int temp;temp = x;x = y;y = te

21、mp;intmain( )int a = 2, b = 3;swap(a, b);return 0;请问a和b是否交换?不能!232332调用swap后调用swap(a,b)如何通过函数调用改变参数的值将在后续章节中介绍。拷贝abxyxy指针作为函数参数在C中函数参数传递方式为“传值”。这种方式的最大好处是函数调用不会改变实参变量的值。如何通过函数调用来改变原有变量的值?如通过函数swap(a,b)来交换两个变量的内容。可以通过将指针作为函数参数来改变多个变量的数据。例:写一函数交换两个整数的值并返回问题分析:函数头部:函数名:swap形参:返回类型:函数体:交换px和py所指的整数int *

22、px, int *pyvoid通过函数swap交换变量a和b,正确的做法应为:void swap ( int *px, int *py)int temp;temp = *px; *px = *py;*py = temp;main( )int a =2, b = 3;swap ( &a, &b); void swap ( int *px, int *py) int *temp;temp = px; px = py;py = temp;例:代码实现23&apx&bpy形参定义为指针实参传递的是变量的地址只交换了指针,而没有交换所指向的数据指针作为函数参数(续)提示:这也是为什么用scanf读int

23、, char, double类型数据时要取变量地址。因为需要改变变量内容。因此,在一定要改变变量内容时,应把函数的形参显式地说明为指向变量(类型)的指针,相应地调用时应该用变量的地址值作为实参。尽管C的函数和函数返回值一般应为基本类型,但它们却可以是指向任何类型(包括复杂的结构类型,甚至其它函数)的指针,这就大大扩充了C的功能和应用范围。指针说明例如:int *px;char *pc;char *acp10;char (*pac)10;int f( );int * fpi( );/* 指向整型的指针 */* 指向字符型的指针 */* 由指向字符的指针构成的数组,即指针数组 */* 指向字符数组

24、的指针,即数组指针 */* 返回值为整型量的函数 */* 返回值为指向整型量的指针的函数,指针函数 */无小括号时:右结合指针和地址如何使一个指针指向一个具体对象:通过&运算符指向某个对象。如:p = &n;将另一个同类型的指针赋给它以获得值。如,px = py;使用malloc或calloc等函数给指针分配一个具体空间。如: p = (char *)malloc(strlen(s)+1);动态内存管理(malloc与free)*在C中可以使用标准库函数malloc动态为指针变量申请一块内存空间(初始化指针变量)。void * malloc ( unsigned int size );使用ma

25、lloc初始化指针变量的常见用法:char *s, p101; int *intptr;s = (char *)malloc(32); /* s指向大小为32个字节(字符)的空间*/gets(p);s = (char *)malloc(strlen(p)+1); /* s指向能正好存放字符串p的空间*/intptr = (int *)malloc(sizeof(int)*10);/* ptr指向能存放10个整型元素的空间*/使用malloc申请到的动态空间在不用时应使用函数free释放。如,free(s);使用malloc和free函数要用:#include 运算符sizeof用来计算所在系统

26、中某种类型或类型变量所占的长度(以字节为单位)。如:sizeof(int),sizeof(n),sizeof(double)具体值取决于系统,通常int或int变量长度为4,double为8动态内存管理(malloc与free)*#include #include #include int main()char line1001;char * pl;gets(line);pl= (char *)malloc(strlen(line)+1);strcpy(pl,line);puts(pl);free(pl);return 0;问题5.3问题:输出输入行中的最长行主算法设计设最长行保存在maxSt

27、r中,其长度为maxLen;读入一行,假如存放在curStr中;求curStr的长度curLen;如果curLenmaxLen,则将curStr保存在maxStr中,maxLen=curLen;返回至,直到读入结束;打印maxStr。定义两个字符数组curStr和maxStr,其字符长度分别为:curLen=maxLen=0;while (还有新行存入curStr)curLen=curStr的长度;if(curLenmaxLen)将curStr保存到maxStr;maxLen=curLen;if(maxLen0)打印maxStr;问题5.3:算法细化问题5.3:算法设计需要计算字符串长度函数s

28、tr_len(char s )i=0;while (si != 0) i+;需要拷贝字符串函数str_copy(char s , char t )i=0;while (ti!= 0) si=ti; i+;为si添加结束符;问题5.3:代码实现int str_len(char s ) int i = 0; while(si != 0) i+; return i;void str_copy(char s , char t ) int i = 0; while(si =ti )!= 0) i+; 问题5.2:代码实现(续)/* c5_3.c */#include #define MAXLINE102

29、4int str_len(char s );void str_copy(char s , char t );int main( )/* find longest line */int len;/* current line length */int max;/* maximum length seen so far */char lineMAXLINE;/* current input line */char saveMAXLINE;/* longest line saved */max = 0;while( gets(line) != NULL ) len = str_len(line);i

30、f( len max ) max = len;str_copy(save, line);if( max 0)printf(“%s”, save); return 0;char* gets(char s )从标准输入中读入一行到数组s中,但换行符不读入,数组以0结束。若输入结束或发生错误,则返回NULL问题5.3:(另外方法用指针方式)可用指针方式实现问题5.2(输出输入行中的最长行)。算法设计:设指针变量Curptr和Saveptr分别指向当前行(新行)和当前最长行While(还有新输入行Curptr)If(Curptr所指向的行比Saveptr所指向的行长) 交换Curptr和Saveptr

31、指针并保存新行长度;输出Saveptr所指内容CurptrSaveptr当前读入的行当前所保存的最长行#include #define MAXLINE1024int str_len(char s);int main( )/* find longest line */int len, max;/* current length and maximum length seen so far */char *curptr, *saveptr,*tmp; /* current line pointer and longest line pointer saved */curptr = (char *)

32、malloc(MAXLEN);saveptr= (char *)malloc(MAXLEN); max = 0;while( gets(curptr) != NULL ) len = str_len(curptr);if( len max ) max = len; tmp = curptr; curptr = saveptr; saveptr = tmp; if( max 0)printf(“%s”, saveptr); free(curptr); free(saveptr); return 0;初始化指针使其分别指针一块空间取得新行长度交换指向当前行和所保存行的指针#include #def

33、ine MAXLINE1024int str_len(char s );void str_copy(char s , char t );int main( )/* find longest line */int len;/* current line length */int max;/* maximum length seen so far */char lineMAXLINE;/* current input line */char saveMAXLINE;/* longest line saved */max = 0;while( gets(line) != NULL ) len = s

34、tr_len(line);if( len max ) max = len;str_copy(save, line);if( max 0)printf(“%s”, save); return 0; 数组方式问题5.3:代码实现(用指针方式)(续)与数组实现方式相比,指针实现方式减少了每当发现新的更长行时所进行的字符数组拷贝(通过调用函数str_copy)。显然指针实现方式代码执行速度要快。问题5.3:常见问题分析一个错误的str_copy函数实现案例:void str_copy(char s, char t) int i = 0; while(ti != 0) si = ti; i+; 错误原因

35、:字符串结束符(0)没有拷贝到字符串s中。构造类型 数组和指针50常用标准字符串库函数#include int strlen(char s );char *strcpy(char s , char t );char *strcat(char s , char t );int strcmp(char s , char t );使用strcpy、strcat函数之前,必须保证s有足够的空间容纳操作后的字符串!strcpy和strlwr的使用问题strcpy (des, sourse); char a1000,b1000,*d; gets(a); gets(b); while (d=strstr(a

36、,b)!=NULL) strcpy(a+strlen(a)-strlen(d),a+strlen(a)-strlen(d)+strlen(b);若des和sourse在同一个数组中,则结果不确定。strlwr该函数不是标准C规定的库函数,只适用于windows平台。指针指针变量是用来存放所指对象地址的变量。在C语言中,允许指针指向任何类型的对象(可指向基本类型、构造类型),甚至可指向其它指针或指向函数。指针应具有非零(无符号整数)值,如将0(通常#define NULL 0)赋给予指针,则该指针没有指向任何具体对象,即空指针。在C语言里,当对象本身不能被直接传送的情况下,往往可以通过指针来进行

37、传递。函数的参数或返回结果通常是基本类型,但也可以是指向任何构造类型的指针。指针和数组在C语言中,数组的名字就是指向该数组第一个元素(下标为0)的指针,即该数组第一个元素的地址,也即数组的首地址。a0int a10=1,2,3,4,5,6,7,8,9,10;int *pi;pi0 x01000 x0100 或者pi = a;pi 指向数组第一个元素?pi 指向数组下标为i的元素?pi = &ai;这时*pi为a0这时*pi为aipi = a+i;pi+;pi = &a0;指针运算当指针指向某一数组或动态分配的连续存储空间时:1) 指针和整数可以进行加减。 若p为指针,则p+n和p-n是合法的,

38、同样p+也是合法的,它们的结果同指针所指对象类型相关。a0pi0 x01000 x0100pi = a;pi+; 这时pi指向a1,*pi为a1pi+=6;这时pi指向a7,*pi为a7指针运算(续)*int a10;int *pi=a;char str10;char *pc=str;a0pi0 x0100str0pc0 x02000 x01000 x0200pi+;pc+;/*假如int占4个字节,这时pi为0 x0104*/*假如char占1个字节,这时pc为0 x0201*/指针运算(续)两个指向同一类型的指针,可进行= = , , 等关系运算,其实就是地址的比较。3) 两个指向同一数组

39、成员的指针可进行相减。 如, pj-pi表示数组的长度4)当P1,和P2指向同一类型时,可以进行赋值。 如:py = px,则px,py指向同一对象。a0pia9pjif ( pi=pj )用来判断pi是否超出了数组表示的范围a10指针运算(续)注意:两指针不能相加。如右图,计算中间指针:mid = (low + high ) /2错!正确方法是:mid = low + (high low)/2 lowmidhigh指针运算(续)int a100, n, i, *pa;scanf(%d,&n);pa=a;for(i=0;in;i+)scanf(%d, pa);pa+;指针运算(续)#inclu

40、de #include int main( )int n, *pa;scanf(%d,&n);pa=(int*)malloc(sizeof(int)*n);while(n0)scanf(%d, pa);pa+;n-;free(pa);int n, *pa, *head;scanf(%d,&n);head=pa=(int*)malloc(sizeof(int)*n);while(n0)scanf(%d,pa);pa+;n-;free(head);指针运算(续)int n, *pa, *head;scanf(%d,&n);head=pa=(int*)malloc(sizeof(int)*n);wh

41、ile(pahead+n)scanf(%d,pa);pa+;free(head); 0 1 2 3 4 a0pi0 x01000 x0100int a5 = 0, 1, 2, 3, 4;int *pi;pi = a;pi+; 这时pi指向a1,*pi为a1, 即1pi+=2;这时pi指向a3,*pi为a3, 即3指针运算(续)a0pia8pj for ( pi=a, pj=&aN-1; pi=pj; pi+ ) 用来遍历一个数组a9指针运算(续)指针运算(续)指针运算分析: p+和p+1的区别; y = *px + 1和y= *(px + 1)的区别; y = (*px)+和y = *px +

42、的区别;指针运算(续)p+结果为p指向下一元素;p+1结果为下一元素的指针,但p本身不变。*px+1为取px所指对象内容加1 ;*(px+1)为px指针加1,并取结果指针所指对象内容;如右图:y= *px+1y= *(px+1)(*px)+为先取px所指对象内容进行运算,然后对其加1;*px+为先取px所指对象内容进行运算,然后指针px加1。如对下图:pxpx+1100200px100px101100pxY=(*px)+Y=*px+= 101= 200=100= 100指针和数组在C语言中,数组的名字就是指向该数组第一个元素(下标为0)的指针,即该数组第一个元素的地址,也即数组的首地址。指针和

43、数组(续)例如:int a10, x;int *pa;若:pa =a;一般有:ai *(pa+i)*(a+i) 代表同一数据但特别注意:数组名和指针(变量)是有区别的,前者是常量,而后者是变量。因此,尽管我们可写pa =a; 但决不能写:a = pa ; a+; 等。 pai ?指针和数组(续)假设:int values100, *intptr = values, i;表:指针与数组的关系表达式值&values0valuesintptr指向values数组第一个元素的指针values0*values*intptrvalues数组的第一个元素&valuesivalues+iintptr+i指向v

44、alues数组第i+1个元素的指针valusei*(values+i)*(intptr+i), intptrivalues数组的第i+1个元素指针和数组(续)例:用指针和数组两种方式实现strlen函数1) 数组方式int str_len( char s )int n = 0;while(sn != 0)+n;return n;2) 指针方式int str_len(char *s)int n;for(n=0; *s != 0; s+)n+;return n;指针和数组(续)例:用指针和数组两种方式实现strlen函数1) 数组方式int str_len( char s )int n = 0;w

45、hile(sn != 0)+n;return (n);2) 指针方式int str_len(char *s)int n;for(n=0; *s != 0; s+)n+;return (n);main( )char st100;scanf(“%s”, st);printf(“%dn”, str_len(st);或main( )char *st;int l;st = “C Language”;l = str_len(st);printf(“length=%dn”, l);在函数定义中形参形式char s 和char *s完全等价,即指向某类型的指针与该类型没有指明长度的数组是同一回事。用哪个取决于

46、在函数里表达式的写法。 指针和数组(续)例:用指针和数组两种方式实现strcpy函数1) 数组方式void strcpy(char s , char t )int i = 0;while(si = ti) != 0)i+;2) 指针方式void strcpy(char *s, char *t)while(*s = *t) != 0) s+; t+;或void strcpy(char *s, char *t) while(*s+ = *t+) ;例:学生成绩排序(排序函数用指针实现)void sortArray(int array, int n) int i,j,tmp, index; for(

47、i=0; in; i+) index = i; for (j=i+1; jn; j+) if(arrayindex arrayj) index = j; tmp = arrayi; arrayi = arrayindex; arrayindex = tmp; void sortArray(int *array, int n) int tmp, *index, *p, *q; for(p=array; parray+n; p+) index = p; for (q=p+1; qarray+n; q+) if(*index *q) index = q; tmp = *p; *p = *index;

48、 *index = tmp; 指针和数组(续)数组名可作为参数进行传递。当将数组名传给函数时,实际上所传递的是数组的开始地址。(即数组第一个元素的地址)为什么要使用指针?扩展了语言的功能,如通过传递指针来修改实参变量、或通过返回指针来返回一组数据的首地址等; 能够更方便的组织和操作数据,如,离散数据的组织和访问(链表,树等);典型错误案例分析(续)#include char *insert(char *string,char c) int i; char s50; for(i=0;*stringc;i+) si=*string+; si+=c; for(;*string!=0;i+) si=*

49、string+; return s;void main() char s150,c; scanf(%sn,s1); scanf(%c,&c); printf(%s,insert(s1,c);定义了一个局部数组该循环没有复制0。字符数组s没有0不能返回一个局部数组。因为它的生存期为当前函数。修改正确后:char *insert(char *string,char c) int i; char *s; s = (char *)malloc(50); for(i=0;*stringc;i+) si=*string+; si+=c; for(;(si=*string+)!=0;i+) ; return

50、 s;或:char *insert(char *string,char c) int i; char s50, *s1=string; for(i=0;*s1c;i+) si=*s1+; si+=c; for(;(si=*s1+)!=0;i+) ; for(i=0;(stringi=si)!=0;i+) ; return string;指针和数组(续)对于字符串常量,可以把它看成一个无名字符数组,C编译程序会自动为它分配一个空间来存放这个常量,字符串常量的值是指向这个无名数组的第一个字符的指针,其类型是字符指针。所以,printf(“a constant character stringn”)

51、; 传递给函数的是一个无名数组第一个字符的指针。注意:字符数组和字符指针使用时容易混淆。例:char *char_ptr, word20;char_ptr = “point to me”;word = “you can not do this”;正确, 把字符串常量第一个字符指针赋给变量。错误, word是常量正确做法为:strcpy(word, “”);指针数组指针数组就是由指针组成的数组,即该数组的每一个元素都是指向某一对象的指针。例:inta10 = 9, 0, 12, 48, 5;int *pa10;a0a19012485pa0 pa1指针数组(续)指针数组与二维数组的区别:1) 二维

52、数组:char days710 = “Sunday”, “Monday”, “Tuesday”, “Wednesday”,“Thursday”, “Friday”, “Saturday”;存贮形式:指针数组(续)2)指针数组char *days7 = “Sunday”, “Monday”, “Tuesday”, “Wednesday”,“Thursday”, “Friday”, “Saturday”;存贮形式:Sunday0Monday0Tuesday0Wednesday0Thursday0Friday0Saturday0days0days1days2days3days4days5days6c

53、har *days7指针数组(续)比较上面两个例子,可以看出尽管二维字符数组与字符指针数组在存储形式上不同,但它们在初始化形式以及访问元素方式上却是相同的。例如,无论是指针数组,还是二维数组,下面两种形式访问的都是同一个元素,结果都是字符串”Friday”中的字符y。*(days5+5) days55 使用指针数组来存放不同长度的字符串可以节省存贮空间。例如,如果要保存从标准输入或文件中读入的行,字符指针数组是一个好的选择。因为读入的行可能长短差异很大。 下面程序片段即为保存从标准输入中读入多行:指针数组(续)使用二维字符数组保存一篇文章/* read lines from input */#

54、define MAXLENGTH512#define MAXLINES1000char lines MAXLINESMAXLENGTH, buf MAXLENGTH;int i;i = 0;while(gets(buf) != NULL) strcpy(linesi, buf); i+;或while( gets ( linesi ) != NULL ) i+;指针数组(续)使用二维字符数组将文章排序输出n=i;for(i=0;in;i+)min=i;for(j=i+1;j 0 )min=j;if(min!=i)strcpy(buf, linesmin);strcpy(linesmin,line

55、si);strcpy(linesi,buf);for(i=0;in;i+)puts(linesi);指针数组(续)使用指针数组保存一篇文章/* read lines from input */#define MAXLENGTH512#define MAXLINES1000char *lineptrMAXLINES, bufMAXLENGTH;int i;i = 0;while(gets(buf) != NULL) lineptri = (char *)malloc(strlen(buf)+1); strcpy(lineptri, buf); i+;指针数组(续)使用指针数组将文章排序输出n=i

56、;for(i=0;in;i+)min=i;for(j=i+1;j 0 )min=j;if(min!=i)strcpy(buf, lineptrmin);strcpy(lineptrmin, lineptri);strcpy(lineptri,buf);for(i=0;in;i+)puts(linesi);指针数组(续)使用指针数组将文章排序输出n=i;for(i=0;in;i+)min=i;for(j=i+1;j0)min=j;if(min!=i)pc = lineptrmin;lineptrmin = lineptri;lineptri = pc;for(i=0;in;i+)puts(lin

57、eptri);free(lineptri);二维数组指针运算二维数组指针运算的理解:例:#include char a45 = “abcd”, “efgh”, “ijkl”, “mnop” ;main( ) printf(“a=%x, a0=%x, &a00=%xn”, a, a0, &a00); printf(“a+1=%x, a0+1=%x, &a01=%xn”, a+1, a0+1, &a01); printf(“*(a+1)=%c, *(a0+1)=%cn”, *(a+1), *(a0+1); 一次运行结果:a= 0 x194, a0= 0 x194, &a00= 0 x194a+1=

58、 0 x199, a0+1= 0 x195, &a01= 0 x195*(a+1)= e, *(a0+1) =b从该例中可以看出,a, a0, &a00虽然值相同,但含义却不一样,a+1指向数组的下一行(即组成二维数组的一维数组的下一个元素),而a0+1指向下一个元素。指针数组(续)例:将数字表示的月分转换成英文表示的月分(指针数组的初始化)。char *month_name(int n)static char *name = “illegal month”,“January”,“February”,“March”,“April”,“May”,“June”,“July”,“August”,“S

59、eptember”,“October”,“November”,“December”;return (n12) ? name0 : namen);指针数组(续)命令行参数在C语言中,主函数main还可以带有参数,形式如下:int main( int argc, char *argv )或int main( int argc, char *argv)其中:- argc包含命令本身在内的参数个数- argv指针数组,数组元素为指向各参数(包含命令本身)的指针。 许多命令在执行时除了提供命令名之外,还要给出一定的参数,如DOS命令:Ccopy file1 file2 在此,file1和file2被称为

60、命令行参数。在实际应用时,经常会需要编写带命令行参数的程序。命令名字本身第一个参数第二个参数第argc-1个参数argv0argv1argv2argvargc-1命令名字和参数都是一个个字符串问题5.4问题:实现一个命令echo,其将命令后的正文串显示在屏幕上,如:C echo hello world屏幕输出:hello world问题5.4:算法分析从右图可知,使用下面循环就可输出所有命令行参数:for(i=1; iargc; i+) printf(“%s “, argvi);“echo”第一个参数第二个参数第argc-1个参数argv0argv1argv2argvargc-1“echo”“

温馨提示

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

评论

0/150

提交评论