实训项目一 数的转换与计算 一、实训目的与要求 通过实训,能熟练使用 VC++集成开发环境,对数的按位分离及合并、数的进制转换、 素数、整除及奇偶判断等实际问题,能够理解相关问题的解决算法,能用 C 语言程序实现 相关算法,并能完成程序的编写、纠错、调试与测试。 实训过程中,要求养成良好的编程习惯,分析问题与解决问题的严谨务实,同时,积极 通过互联网、文献资料巩固和拓展所学知识。 二、实训内容 任务 1:数的按位分离及合并 ? 基础知识 1. 程序基本构成 1)一个 C 程序一般由预编译命令,自定义函数,主函数(即 main 函数)构成。预编译命令“#include”将有关的“头文件” 包括到用户源文件中; 2)一个 C 程序必须有且只能有一个 main 函数; 3)所有函数是平行关系,即一个函数内不能嵌套定义另一个 函数; 4)C 程序的执行从 main 函数开始,如在 main 函数中调用 其它函数,在调用结束后流程返回到 main 函数,在 main 函数中 结束整个程序的运行。 (a) C 程序基本构成 2. 函数定义的一般形式 1)无参数函数定义 类型标识符 函数名() { 声明部分 语句部分 } 2)有参数函数定义 类型标识符 函数名(形式参数列表) { 声明部分 语句部分 } 3. 通过函数返回或传回数据的方法 -1- 方法 1:通过 return 语句 #include int fun() { int x; x = 100; return (x); } main() { printf(“%d\n”,fun()); } 方法 2:通过指针形参 1) 如 果 定 义 i_pointer 为 指 针 变 量 , 则 ( *i_pointer)是 i_pointer 所指向的变量, “*”符号表示“指向” ; 2) 指针变量 i_pointer 内存放的是变量地址,(b) 图中,变量地址为 2000。 (*i_pointer)是地址为 2000 的变量,(b)图中,为 3。 3) 变量(*i_pointer)和变量 i 等价。 下面两个语句作用相同: (1) i = 3; (2) *i_pointer = 3; #include void fun(int *p)/*void 表示函数不带返回值,函数体中不得出现 return*/ { *p = 100; } main() { int x; /*声明部分,定义主函数中所用变量*/ fun(&x); /*&为取地址运算符*/ printf(“%d\n”,x); } ? 编程思路 /*将 100 赋给指针变量 p 所指的变量*/ /*主函数*/ /*调用自定义函数,并在显示器中显示 100*/ /*预编译命令*/ /*自定义函数*/ /*声明部分,定义自定义函数中所用变量*/ /*将 100 赋给变量 x*/ /*将 x 的值作为函数值带回到 main 函数*/ (b) 指针 数的按位分离 对于某个整数的各个位上数据处理,通常需要用到“%”取余运算和“/”除法运算。 ? 获取某个整数最后某位,使用 % 运算符 %10^n:获取最后 n 位 举例:假设 1234 和 10 都已被定义为 int 型 1234%10 = 4 1234%100 = 34 1234%1000 = 234 -2- ? 删除某个整数最后某位,使用 / 运算符 /10^n:删除最后 n 位 举例:1234/10 = 123 1234/100 = 12 1234/1000 = 1 数的合并 如三个数字 a=1,b=2,c=3,希望合并成一个整数 x 方法 1:x = a*100 + b*10 + c*1 方法 2: x = 0 x * 10 + a x * 10 + b x * 10 + c 易错点: 1. 自定义函数是 void 型时,不得使用 return 语句,需通过指针传回数据。 2. 花括号和小括号必须成对输入,切忌少或多半个括号。 ? 程序编制 程序 1: 将两个两位数的正整数 a、b 合并形成一个整数放在 c 中,合并的方式是:将 a 数的十 位和个位数依次放在 c 数的千位和十位上, b 数的十位和个位数依次放在 c 数的个位和百位 上。 例如,当 a=45,b=12。调用该函数后,c=4251。 #include void fun(int a,int b,long *c) { } main() { int a,b;long c; scanf("%d%d",&a,&b); fun(a,b,&c); printf("The result is:%ld\n",c); } 程序 2: 请编写一个函数 fun,它的功能是:将一个数字字符串转换为一个整数。 例如:若输入字符串"-1234",则函数把它转换为整数值-1234。 -3- #include long fun(char *p) { } main() { char s[6]; long n; gets(s); n=fun(s); printf("%ld\n",n); } 任务 2:素数问题 ? 编程思路 对于某个整数 m,在 2 ~ m-1 的范围内,如果有一个数可以被它整除,则 m 为非素数, 如果没有一个数可以被它整除,则 m 为素数(素数的条件:除了 1 和本身外,没有一个数 可以被它整除) 。 实际上,这个查询范围可以缩放到 2 ~ m/2,或 2 ~ m 的平方根。在实际编程中,判 断素数问题,可以变成穷举 2-->m-1, 2-->m/2, 2-->sqrt(m)范围内是否有该数的一 个因子。 方法 1: for(i=2; i<=m-1; i++) { if(m%i==0) break; } if(i>m-1) m 是素数 else m 不是素数 方法 2: for(i=2; i<=m-1; i++) { if(m%i==0) break; } if(i<=m-1) m 是非素数 else m 是素数 方法 3: -4- for(i=2; i<=m/2; i++) { if(m%i==0) break; } if(i>m/2) m 是素数 else m 不是素数 方法 4: for(i=2; i<=sqrt(m); i++) { if(m%i==0) break; } if(i>sqrt(m)) m 是素数 else m 不是素数 方法 5: k=sqrt(m); for(i=2; i<=k; i++) { if(m%i==0) break; } if(i>k) m 是素数 else m 不是素数 方法 6: k=sqrt(m); flag=1; for(i=2; i<=k; i++) { if(m%i==0) { flag=0; break;} } if(flag) m 是素数 else m 不是素数 方法 7: k=sqrt(m); flag=1; for(i=2; i<=k && flag; i++) { if(m%i==0) flag=0; } if(flag) m 是素数 else m 不是素数 易错点: 1. 使用 sqrt 函数时,预编译命令必须加上 include 。如果题目中预编 译命令没有 include ,则不能使用 sqrt 函数。 -5- 2. 记住整除数的范围必须从 2 开始,不能写成 1。 ? 程序编制 程序 1: 编写函数 fun,如果 m 是素数,则返回 1,否则返回 0。 #include #include int fun(int m) { } main() { int m,i,k; printf("\nPlease input a integer:"); scanf("%d",&m); if(fun(m)) printf("%d is a prime number!\n",m); else printf("%d is not a prime number!\n",m); } 程序 2: 编写函数 int fun(int lim,int aa[]),该函数的功能是求出小于 lim 的所有素 数并放在 aa 数组中,该函数返回求出素数的个数。 #include int fun(int lim,int aa[]) { } main() { int limit,i,sum; int aa[200]; printf("输入一个整数:"); -6- scanf("%d",&limit); sum=fun(limit,aa); for(i=0;i void fun(int m,int *k,int xx[]) { } main() { int m,n,zz[100]; printf("\nPlease enter an integer number between 10 and 100:"); scanf("%d",&n); fun(n,&m,zz); printf("\n\nThere are %d non-prime numbers less than %d:",m,n); for (n=0;n void fun(int m,int k,int xx[]) { -7- } main() { int m,n,zz[1000]; printf("\nPlease enter two integers:"); scanf("%d%d",&m,&n); fun(m,n,zz); for(m=0;m #define M 200 int aa[1000]; void fun(int *n) { } main() { int n,k; fun( &n); for(k=0;k void fun(int x,int pp[],int *n) { } main() { int x,aa[1000],n,i; printf("\nPlease enter an integer number:\n"); scanf("%d",&x); fun(x,aa,&n); for(i=0;i #include #include float fun(float x) -9- { } main() { float a; printf("Enter a: ");scanf("%f",&a); printf("The original data is: "); printf("%f \n\n",a); printf("The result: %f\n",fun(a)); } 三、参考代码 任务 1 程序 1: void fun(int a,int b,long *c) { int c1,c2,c3,c4; c1=a/10; c2=b%10; c3=a%10; c4=b/10; *c = c1*1000L + c2*100L + c3*10L + c4*1L; } 任务 1 程序 2: long fun(char *p) { long n; int sign; int i; if(p[0]=='-') sign=-1; else sign=1; if(p[0]=='-' || p[0]=='+') p++; n=0; for(i=0; p[i]!='\0'; i++) n=n*10+(p[i]-'0'); return sign * n; } 任务 2 程序 1: int fun(int m) { int i,k; k=sqrt(m); - 10 - for(i=2; i<=k; i++) { if(m%i==0) return 0; } return 1; } 任务 2 程序 2: int fun(int lim,int aa[]) { int i,m,k=0; for (m=2; m int fun(int t) { } main() { int n; n=1000; printf("n=%d,f=%d\n",n,fun(n)); } 程序 2: 请编写函数 fun, 函数的功能是: 利用一下所示的简单迭代方法求方程求方程: cos (x) -x=0 的一个实根。迭代步骤如下: (1)取 x1 的初值为 0.0; (2)x0=x1,把 x1 的值赋 给 x0; (3)x1=cos(x0) ,求出一个新的 x1; (4)若 x0-x1 的绝对值小于 0.000001 执行步骤(5)否则执行步骤(2) ; (5)所求 x1 就是方程 cos(x)-x=0 的一个实根作为 - 14 - 函数值返回。程序将输出结果为:Root=0.739085。 #include #include double fun() { } main() { printf("Root =%f\n", fun()); } 任务 2:级数求和 ? 编程思路 此类问题是一个累加的过程,需要掌握多项式求和累加的规律,一般引入一个 sum 作 为和的累积,通过 for 循环结构解决每项遍历问题,注意 sum 初值问题和边缘临界点的问 题。同时引入一个变量,存储正负的符号位。 举例:sum = 1+2+3+4+…+n; 可以改写为: sum sum sum sum …… sum = 0; += 1; += 2; += 3; += n; 改写成 for 语句为: for(i=0; i float fun(int n) { } main() { int n; float s; system("cls"); printf("\nPlease enter N:"); scanf("%d",&n); s=fun(n); printf("the result is:%f\n",s); } 程序 2: 编写函数 fun,其功能是:根据以下公式求 p 的值,结果由函数值带回。m 与 n 为两 个正整数且要求 m>n。 P ? m! n!(m ? n )! 例如:m=12,n=8 时,运行结果为 495.000000。 #include float fun(int m, int n) { } main() { printf("P=%f\n", fun (12,8)); } - 16 - 程序 3: 编写函数 fun,它的功能是计算: s ? ln(1) ? ln(2) ? ln(3) ? ...... ? ln(m) ,s 作为函 数值返回。在 C 语言中可调用 log(n)函数求 ln(n)。log 函数的引用说明是: double log(double x)。 例如,若 m 的值为:20,fun 函数值为:6.506583。 #include #include double fun( int m) { } main() { printf("%f\n",fun(20)); } 程序 4: 请编写一个函数 fun, 它的功能是: 根据以下公式求π 的值(要求满足精度 0.0005,即 某项小于 0.0005 时停止迭代): ? 1 1? 2 1? 2 ? 3 1 ? 2 ? 3 ? 4 1? 2 ? ... ? n ? 1? ? ? ? ? ...... ? 2 3 3? 5 3? 5? 7 3? 5 ? 7 ? 9 3 ? 5 ? ... ? (2n ? 1) 程序运行后,如果输入精度 0.0005,则程序输出为 3.140578。 #include #include double fun ( double { eps) } main( ) { double x; printf("Input eps:") ; scanf("%lf",&x); printf("\neps = %lf, PI=%lf\n", x, fun(x)); } - 17 - 三、参考代码 任务 1 程序 1: int fun(int t) { int x1=0,x2=1,temp=0; while (x2=0.000001) { x0=x1; x1=cos(x0); } return x1; } 任务 2 程序 1: float fun(int n) { int i; float sum=0.0,h=0.0; for(i=1;i<=n;i++) { h += i; /*h 为每一分式的除数,i 为前后相邻除数之间的增量*/ sum += 1.0/h; } return(sum); } 任务 2 程序 2: float fun(int m, int n) { float up = 1.0, down = 1.0; int i; for (i=1; i<=m; i++) - 18 - { up *= i; } for (i=1; i<=n; i++) { down *= i; } for (i=1; i<=(m-n); i++) { down *= i; } return (up/down); } 任务 2 程序 3: double fun( int m) { int i; double sum=0; for (i=1; i<=m; i++) { sum += log(i); } sum =sqrt(sum); return (sum); } 任务 2 程序 4: double fun ( double eps) { int n=0; double down=1,up=1; double one ,pi=0; one = (double)up/(double)down; while(one>=eps) /*通过循环语句判断公式中某项是否在精度范围之内*/ { pi+=one; n++; up=up*n; down=down*(2*n+1); one=(double)up/(double)down; } return pi*2; } /*求 s 的平方根*/ - 19 - 实训项目三 一维数组运算 一、实训目的与要求 1、理解数组的遍历 2、掌握一维数组作为函数参数的基本用法(本质是指针) 3、掌握排序、逆序、求最值、平移、删除等一维数组常规算法,能用 C 语言程序实现 相关算法,并能完成程序的编写、纠错、调试与测试。 二、实训内容 任务 1:数组中元素求和、平均数 ? 基础知识 1、一维数组作为函数参数 一维数组作为函数参数。形参本质为指针变量,实参为数组名,就是数组的首地址,是 一个地址常量。 下面三句代码等价: void fun(int a[5],int n); //a 的本质是指针,所以 sizeof(a)=4 void fun(int a[],int n); //a 的本质是指针,所以 sizeof(a)=4 void fun(int *a,int n); //a 的本质是指针,所以 sizeof(a)=4 2、普通数组的遍历 按照某种策略访问集合中所有元素,如顺序访问数组中的元素。 代码: void fun(int a[], int n) { int i; for(i=0; i #define N 20 fun( int *a,int n,int *odd,int *even) { } main() { int a[N]={1,9,2,3,11,6},i,n=6,odd,even; printf("The original data is:\n"); for (i=0;i float fun(float *a,int n) { } main() { float score[30]={90.5,72,80,61.5,55},aver; - 22 - aver=fun(score,5); printf("\nAverage score is: %5.2f\n",aver); } 任务 2:数组最值问题 ? 基础知识 1. 结构体类型变量的定义 基本类型的变量(如整型、实型、字符型变量等) ,是 C 语言内置类型,不需要定义。 数组中的各元素属于同一个类型, 也不需要定义。 但是有时需要将不同类型的数据组合成一 个整体,以便于引用,例如,一个学生的学号、姓名、成绩等(如(a)图) 。这时应当把这 些简单的变量组织成一个组合项,称为结构体。 (a) 结构体 声明一个结构体类型的一般形式(注意不要忽略最后的分号) : struct 结构体名 {成员表列}; 上图的结构体可定义为(假设结构体里含 10 组数据) : struct student { char num[10]; /*num 中可以存放 10 个字符串*/ char name[10]; /*name 中可以存放 10 个字符串*/ int s; }; typedef struct student STU; STU a[10]; 说明: (1) typedef 用 来 申 明 一 个 新 的 类 型 名 ”STU” 来 代 替 结 构 体 名 ”struct student”。 (2) STU a[10]代表 a 中可存放 10 条学生记录,其包含学号、姓名和成绩三 个成员。 2. 结构体变量的引用 引用结构体变量中成员的方式为 结构体变量名.成员名 在上例中: a[i].num:表示学生记录 a[i]中的 num 成员(即学号) ; a[i].name:表示学生记录 a[i]中的 name 成员(即姓名) ; a[i].s:表示学生记录 a[i]中的 s 成员(即成绩) 。 - 23 - ? 编程思路 默认第 1 个值为最值,从第 2 个值开始,每个数据依次与当前最值比较,如果比最大 值还大(比最小值还小) ,则更像当前最值。 一般思路: max = a; if(b > max) max = b; if(c > max) max = c; …… 改写为 for 语句: max = 第 1 个数字; for(第 2 个数字;最后一个数字;i++) { if(第 i 个数字 > max) max = 第 i 个数字; } 伪代码 1:求最值本身 int max=a[0]; for(i=1; i<10; i++) { if(a[i]>max) max=a[i]; } 最大值:max 伪代码 2:求最值所在下标 int k=0; for(i=1; i<10; i++) { if(a[i]>a[k]) k=i; } 最大值所在下标:k 最大值:a[k] 伪代码 3:求结构体数组中学生的最高分 struct student { char num[10]; int s; }; typedef struct student STU; STU a[10]; int k=0; for(i=1; i<10; i++) { if(a[i].s > a[k].s) } k=i; - 24 - 最高分的学生下标:k 最高分的学生记录:a[k] 最高分的学生分数:a[k].s ? 程序编制 程序 1 ,它的数据类型是结构体类型 ,它的类型是 int 要求程序的功能是:把 20 个随机数存入一个数组,然后输出该数组中的最小值。其中 确定最小值的下标的操作在 fun 函数中实现,请给出该函数的定义。 #include #define VSIZE 20 int vector[VSIZE]; int fun(int list[],int size) { } main() { int i; for (i=0;i int fun(int score[],int m,int below[]) { - 25 - } main() { int i,n,below[9]; int score[9]={10,20,30,40,50,60,70,80,90}; n=fun(score,9,below); printf("\nBelow the average score are:"); for(i=0;i #include #define N 10 typedef struct ss { char num[10]; int s;} STU; fun(STU a[],STU *s) { } main() { STU a[N]={{"A01",81},{"A02",89},{"A03",66},{"A04",87}, {"A05",77},{"A06",90},{"A07",79},{"A08",61}, {"A09",80},{"A10",71}},m; int i; printf("***** The original data *****\n"); for (i=0;i #define N 80 int fun(char *str) { } main() { char s[N] ; printf("Enter a string: ") ; gets(s) ; printf("\n\n") ; puts(s) ; if(fun(s)) printf(" YES\n") ; else printf(" NO\n") ; } - 27 - 任务 4:数组元素排序 ? 编程思路 (1) 选择排序 for(i=0; ia[j]) { t=a[i]; a[i]=a[j]; a[j]=t; } //n 个元素,处理 n-1 次 //前面一个元素 a[i],依次与后面所有元素 a[j]进行比较,小的交换到前 面,大的交换到后面 //一次处理完毕后,最小的一个数,到最上面 (2) 冒泡排序 for(i=0; ia[j+1]) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } //n 个元素,处理 n-1 次 //从第一个元素开始,依次相邻的两个元素(a[j] a[j+1])进行比较,小 的交换到前面,大的交换到后面 //一次处理完毕后,最大的一个数,沉底。 (3) 改良型的选择排序 for(i=0; i #define N 16 typedef struct { char num[10]; int s; } STREC; void fun( STREC a[] ) { } main() { STREC s[N]={{"GA005",85},{"GA003",76},{"GA002",69}, {"GA004",85},{"GA001",91},{"GA007",72},{"GA008",64}, {"GA006",87},{"GA015",85},{"GA013",91},{"GA012",64}, {"GA014",91},{"GA011",66},{"GA017",64},{"GA018",64}, {"GA016",72}}; int i;FILE *out ; fun( s ); printf("The data after sorted :\n"); for(i=0;i10 && a[i]<20)) a[j++]=a[i]; } *n=j; //很多人会忘记更新*n 的值 } (2) 字符数组,删除星号类的题目 void fun(char *s) { j=0; //j 赋初值 for(i=0; s[i]!='\0'; i++) { if(!(删除条件)) } s[j]='\0'; //很多人会忘记,新的字符串需要补充一个\0 } 易错点: (1) 字符串类型题目,结尾加’\0’; (2) 记得 j 赋初值。 ? 程序编制 程序 1 函数 fun 的功能是:将 s 所指字符串中下标为奇数、同时 ASCII 值也为奇数的字符删 除,串中剩余的字符形成一个新串放在 t 所指的数组中。 例如:若 s 所指串中的内容为:“ABCDEFG12345”,其中 C 的 ASCII 码值虽为奇数, 但在数组中的下标为偶数,因此不能删除,而字符 1 的 ASCII 码值为奇数,在数组中的下 标也为奇数, 因此应当删除, 其他依次类推。 最后, t 所指的数组中的内容是“ABCDEFG24”。 #include - 30 - s[j++]=s[i]; #include void fun(char *s,char t[]) { } main() { char s[100],t[100]; printf("\nPlease enter string S:"); scanf("%s",s); fun(s,t); printf("\nThe result is:%s\n",t); } 程序 2: 请编写函数 fun,函数的功能是,删去一维数组中所有相同的数,使之只剩一个。数组 中的数已按从小到大的顺序排序,函数返回删除后数组中数据的个数。 例如:一维数组中的数据是:2 2 2 3 4 4 5 6 6 6 6 7 7 8 9 9 10 10 10。删除后, 数组中的内容应该是:2 3 4 5 6 7 8 9 10。 #include #define N 80 int fun(int a[], int n) { } main() { int a[N]={2,2,2,3,4,4,5,6,6,6,6,7,7,8,9,9,10,10,10,10}; int i,n=20; printf("The original data :\n"); for(i=0; i #include #define N 80 void fun(char *w, int m) { } main() { char a[N]= "ABCDEFGHIJK"; int m; printf("The original string:\n");puts(a); printf("\n\nEnter m: ");scanf("%d",&m); fun(a,m); printf("\nThe string after moving:\n");puts(a); printf("\n\n"); } 左移两位的代码,右移可以变化成左移 三、参考代码 任务 1 程序 1: fun( int *a,int n,int *odd,int *even) { int i; int sumOdd=0,sumEven=0; for(i=0; i float fun(float *a,int n) { int i; float average; double sum=0; for(i=0;ilist[i]) x=i; return x; } 任务 2 程序 2: int fun(int score[],int m,int below[]) { int sum=0; double average=0; int i; int j=0;/*用于计算成绩低于平均分的学生的人数*/ for(i=0;i=j 右上半角: i<=j 例:将数组中所有右上半角的元素(包括对角线)乘以 m void fun(int a[][N],int m) { for(i=0; i #define N 5 fun ( int w[][N] ) { 理解矩阵中各个半角元素的条件。 } main() { int a[N][N],i,j; printf("****The array****\n"); - 38 - for (i=0;i #define N 5 fun ( int w[][N] ) { - 39 - } main() { int a[N][N],i,j; printf("****The array****\n"); for (i=0;i #define M 4 #define N 5 int fun (int a[M][N]) { } main() { int aa[M][N]={{1,3,5,7,9}, {2,9,9,9,4}, {6,9,9,9,8}, {1,3,5,7,0}}; int i,j,y; printf("The original data is:\n"); for (i=0;i #define M 3 #define N 4 void fun(int tt[M][N],int pp[N]) { } main() { int t[M][N]={{22,45,56,30}, {19,33,45,38}, {20,22,66,40}}; int p[N],i,j,k; printf("The original data is:\n"); for (i=0;i void fun(int (*s)[10], int *b, int *n, int mm, int nn) { } main() { int w[10][10] = {{33,33,33,33},{44,44,44,44}, {55,55,55,55}},i,j; int a[100] = {0}, n = 0 ; printf("The matrix:\n") ; for(i = 0 ; i < 3 ; i++) { for(j = 0 ; j < 4 ; j++) printf("%3d",w[i][j]) ; printf("\n") ; } fun(w, a, &n, 3, 4) ; printf("The A array:\n") ; for(i = 0 ; i < n ; i++) printf("%3d",a[i]);printf("\n\n") ; } - 42 - 拓展:如果按列的顺序转换,则程序只需要修改一句(k=j * mm +i ;) 。 任务 5:矩阵转置、加法运算 ? 编程思路 此类问题,只需将数组中 a[i][j]与 a[j][i]进行交换,但是注意只需要交换一次即 可,如果交换两次,相当于回到原始状态。 ? 程序编制 程序 1: 编写程序,实现矩阵(3 行 3 列)的转置(即行列互换) 。 例如,输入下面的矩阵: 100 200 300 400 500 600 700 800 900 程序输出: 100 400 700 200 500 800 300 600 900 #include void fun(int array[3][3]) { } main() { int i,j; int array[3][3]={{100,200,300}, {400,500,600}, {700,800,900}}; for (i=0;i<3;i++) { for (j=0;j<3;j++) printf("%7d",array[i][j]); printf("\n"); } fun(array); - 43 - printf("Converted array:\n"); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%7d",array[i][j]); printf("\n"); } } 程序 2: 请编写函数 fun,函数的功能是:实现 B=A+A',即把矩阵 A 加上 A 的转置,存放在 矩阵 B 中。计算结果在 main 函数中输出。 例如,输入下面的矩阵:其转置矩阵为: |1 2 3| |1 4 7| |4 5 6| |2 5 8| |7 8 9| |3 6 9| 程序输出: |2 6 10| |6 10 14| |10 14 18| #include void fun(int a[3][3],int b[3][3]) { } main() { int a[3][3]={{1,2,3},{4,5,6},{7,8,9}},t[3][3]; int i,j; fun(a,t); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%7d",t[i][j]); printf("\n"); } } - 44 - 三、参考代码 任务 1 程序 1: fun ( int w[][N] ) { int i, j; for(i=0; i=j) w[i][j] = 0; } } } 任务 2 程序 1: fun ( int w[][N] ) { int i, j; for(i=0; ij) { t= array[i][j]; array[i][j]=array[j][i]; array[j][i]=t; } } - 46 - 任务 5 程序 2: void fun(int a[3][3],int b[3][3]) { int i,j; for(i=0;i<3;i++) for (j=0;j<3;j++) b[i][j]=a[i][j]+a[j][i];/*求得矩阵与其转置的和*/ } - 47 - 实训项目五 字符串运算 一、实训目的与要求 通过字符串运算类的程序编制,熟悉和掌握 C 语言处理字符和字符串的相关技巧,重 点掌握指针和数组在此类问题的应用。 二、实训内容 任务 1:字符串遍历与字符处理 ? 基础知识 C 语言规定以字符’\0’作为字符串结束标识,但’\0’不会输出。对于字符串的处理, 重点掌握字符串的遍历。字符串遍历有几种写法: 数组法: for(i=0; s[i]; i++) { 访问 s[i] } for(i=0; s[i]!=0; i++) { 访问 s[i] } for(i=0; s[i]!='\0'; i++) { 访问 s[i] } 指针法 1: char *p=s; while(*p!='\0') { 访问*p p++; } 指针法 2: char *p=s; while(*p!=0) { 访问*p p++; } 指针法 3 char *p=s; while(*p) { 访问*p p++; } - 48 - ? 编程思路 (1) 大小写字母的转换关系,每一个小写字母比它相应的大写字母的 ASCII 码大 32。 大写字母 = 小写字母 - 32 或者 大写字母 = 小写字母 – ‘a’ + ‘A’ 小写字母 = 大写字母 – ‘A’ + ‘a’ (2) 将字符转换成数据 某个数字字符 - ’0’ = 某个数字 ? 程序编制 程序 1: 请编写一个函数 fun,它的功能是:将 ss 所指字符串中所有下标为奇数位置上的字母 转换成大写(若该位置上不是字母,则不转换) 。 #include void fun(char *ss) { } main() { char tt[81]; printf("\nPlease enter an string:\n"); gets(tt); printf("\n\nAfter changing,the string\n \"%s\"",tt); fun(tt); printf("\nbecomes\n \"%s\"\n",tt); } 任务 2:字符串常用操作实现 ? 编程思路 对于字符串拷贝、字符串连接、字符串长度、字符串比较四个函数是 C 语言函数库中 处理字符串最常用函数,实现方法也非常多,需要能够自行完成几种库函数的实现,同时熟 悉如何使用字符串指针。 ? 程序编制 - 49 - (1)字符串拷贝。 void mystrcpy(char *s1,char *s2) { while(*s1++ = *s2++); } (2)字符串连接。 void mystrcat(char *s1,char *s2) { while(*s1) s1++; while(*s1++ = *s2++); } (3)求字符串长度。 int mystrlen1(char *s) { char *p=s; while(*p) p++; return p-s; } int mystrlen2(char *s) { char *p=s; while(*p++); return p-s-1; } (4)字符串比较。 int mystrcmpy(char *s1,char *s2) { while(*s1 && *s2 && *s1++==*s2++); return *s1-*s2; } 程序 1: 学生的记录由学号和成绩组成,N 名学生的数据已在主函数中放入结构体数组 s 中,请 编写了函数 fun,它的功能是:函数返回指定学号的学生数据,指定的学生号在主函数中输 入,若没有找到指定学号,在结构体变量中给学号置空串,给成绩置-1,作为函数值返回。 (用于字符串比较的函数是 strcmp) 。 #include #include #define N 16 - 50 - typedef struct { char num[10]; int s; } STREC; STREC fun( STREC *a, char *b ) { } main() {STREC s[N]={{"GA005",85},{"GA003",76},{"GA002",69},{"GA004",85}, {"GA001",91},{"GA007",72},{"GA008",64},{"GA006",87}, {"GA015",85},{"GA013",91},{"GA012",64},{"GA014",91}, {"GA011",77},{"GA017",64},{"GA018",64},{"GA016",72}}; STREC h; char m[10]; int i; printf("The original data:\n"); for(i=0; i #include fun(char(*a)[10][81],int num,char **max) - 51 - { } main() { char ss[10][81],*ps; int n,i=0; printf("输入若干个字符串:"); gets(ss[i]); puts(ss[i]); while(!strcmp(ss[i],"****")==0) { i++; gets(ss[i]); puts(ss[i]); } n=i; fun(ss,n,&ps); printf("\nmax=%s\n",ps); } 程序 3: 编写一个函数 fun,它的功能是:实现两个字符串的连续(不使用库函数 strcat) , 即把 p2 所指的字符串连接到 p1 所指的字符串后。例如,分别输入下面两个字符串: FirstStringSecondString 程序输出: FirstString-SecondString #include void fun(char p1[], char p2[]) { - 52 - } main() { char s1[80], s2[40] ; printf("Enter s1 and s2:\n") ; scanf("%s%s", s1, s2) ; printf("s1=%s\n", s1) ; printf("s2=%s\n", s2) ; printf("Invoke fun(s1,s2):\n") ; fun(s1, s2) ; printf("After invoking:\n") ; printf("%s\n", s1) ; } 任务 3:子串匹配 ? 编程思路 将主串中的字符从第一个位置开始逐个与子串中的字符作比较,若子串出现在主串中, 次数加 1,主串中的指针移动到下一个位置继续与子串比较,反之,主串中的指针也同样移 动到下个位置,直至主串中的字符全部比较结束。 ? 程序编制 程序 1 编写一个函数,该函数可以统计一个长度为 2 的字符串在另一个字符串中出现的次数。 例如,假定输入的字符串为:asd asasdfg asd as zx67 ask mklo,子字符串为: as,则应输出 6。 #include int fun(char *str,char *substr) { } main() { char str[81],substr[3]; int n; - 53 - printf("输入主字符串:"); gets(str); printf("输入子字符串:"); gets(substr); puts(str); puts(substr); n=fun(str,substr); printf("n=%d\n",n); } 任务 4:字符串中字符删除 ? 编程思路 删除字符,即保留不要删除的字符。 ? 程序编制 程序 1 规定输入的字符串中只包含字母和*号。请编写函数 fun,它的功能是:将字符串前面 连续的*号全部删除,中间和尾部的*号不删除。 例如,字符串中的内容为:*******A*BC*DEF*G****,删除后,字符串中的内容应 当是:A*BC*DEF*G****。在编写函数时,不得使用 C 语言提供的字符串函数。 #include void fun( char a[] ) { } main() { char s[81]; printf("Enter a string:\n");gets(s); fun( s ); printf("The string after deleted:\n");puts(s); } 拓展:如果要求删除尾部的*号,程序该如何编写?如果要求删除中间的*号呢? - 54 - 三、参考代码 任务 1 程序 1: #include void fun(char *ss) { int i; for(i=1;ss[i];i++) { if(i%2==1 && ss[i]>='a' && ss[i]<='z') ss[i]=ss[i]-'a'+'A'; } } 任务 2 程序 1: STREC fun( STREC *a, char *b ) { STREC c; int i; c.num[0]='\0'; c.s=-1; for(i=0;imaxlen) { maxlen=strlen(a[i]); k=i; } } - 55 - *max=a[k]; } 任务 2 程序 3: void fun(char p1[], char p2[]) { char *p=p1; while (*p)p++; while (*p2)*p++=*p2++; *p=0; } 任务 3 程序 1: int fun(char *str,char *substr) { int i,j,k=0; for(i=0; str[i]; i++) { for(j=0; substr[j]; j++) if(str[i+j]!=substr[j]) break; if(substr[j]=='\0') k++; } return k; } 任务 4 程序 1: void fun( char a[] ) { int i,j; int x,y; //找到 A 的位置(下标) , (从第 1 个星号找到 A 的位置) x=0; while(a[x]=='*') x++; //找到 G 的位置(下标) //1 先到终点站\0 y=0; while(a[y]!='\0') y++; //2 从\0 到最后一个星号位置 y--; //3 从最后一个星号,找到 G 的位置 while(a[y]=='*') y--; - 56 - j=0; for(i=0; a[i]; i++) { if(!( a[i]=='*' && (iy”。如果要求删 除中间的*号,则改为”(i>x) && (i int fun(char *s) { } main() { char s[81]; gets(s); printf(”%d\n”,fun(s)); } - 58 - 任务 2:统计操作 ? 编程思路 对于某个整数的各个位提取,需要用到“/”除法和“%”取余运算。获取某个整数最 后一位,使用 % 运算符,删除某个整数最后一位,使用 / 运算符。 (1) 统计 26 个字母出现的频率 问:需要多少个计数器? 答:26 个。 (2) 统计 10 个数字出现的频率 问:需要多少个计数器? 答:10 个。 (3) 统计各个年龄段的年龄的人数 问:需要多少个计数器? 答:11 个。 (0~9;10~19;20~29……>=100) ? 程序编制 程序 1 统计 26 个字母出现的频率。 #include #include void fun(char *tt, int pp[]) { } main( ) { char aa[1000] ; int bb[26], k ; printf( "\nPlease enter a char string:" ) ; scanf("%s", aa) ; fun(aa, bb ) ; for ( k = 0 ; k < 26 ; k++ ) printf ("%d ", bb[k]) ; printf( "\n" ) ; } 程序 2 请编写函数 fun,函数的功能是,统计一行字符串中单词的个数,作为函数值返回。