12天学好C语言——记录我的C语言学习之路
Day 8:
从今天开始,我们获得了C语言中很有力的一个工具,那就是函数。函数的魅力不仅于此,一个程序到最后都是由众多函数组成的,我们一定要用好函数,用熟练。函数掌握了,就会对你的编程水平有不小的提升。
还是以一个简单的程序开始今天的学习:
//输入10个数字,要求输出最大值和该值是数组中第几个元素(当然要用到函数思想)
/*//program 8.1
#include "stdio.h"
int main()
{
int a[11];
int i,n=1;
for (i=1; i<=10; i++) {//为了方便辨识,a[1]就认为是第一个元素,所以我们把i设为从1开始的
scanf("%d",&a[i]);
}
int max(int a,int b);
int m=a[1];
for(int i=2;i<=10;i++)
{
if(max(m,a[i])>m)//如果m与a[i]之间的最大值比m大,才交换,交换即将a[i]的下标i赋给n,用n来记录第几个数组元素是最大的。当然n初始化为1,因为如果第一个数最大的话,不需要交换,所以n也不用变化了
{
m=max(m,a[i]);
n=i;
}
}
printf("No.%d is max,max is %d",n,m);
return 0;
}
int max(int a,int b)
{
return(a>b?a:b);
}
*/
//用score[10]来存放10个学生的成绩并输出其平均值,要求用函数去做
/*//program 8.2
#include "stdio.h"
int main()
{
int i;
double aver1,score[10];
double aver(double score[10]); //声明一个函数aver,里面传入一个有10个元素的数组
for (i=0; i<10; i++) {
scanf("%lf",&score[i]);
}
aver1=aver(score); //调用的时候,是将数组名作为参数传入到函数中的,此时传递的是数组首个元素的地址,这里一定要知道,你要处理求平均值的是整个数组的所有元素,而不是单单一个元素,所以必须传入数组名
printf("average = %lf",aver1);
return 0;
}
double aver(double score[10])
{
double sum=0,aver2;
int i;
for(i=0;i<10;i++)
{
sum+=score[i];
}
aver2=sum/i;
return aver2;
}
*/
//上个题目规定了传入函数的数组长度,那么现在我们自己定义两个不一样长度的数组,然后用一个函数分别求两个数组元素的平均值。
/*//program 8.3
#include "stdio.h"
int main()
{
double a1[15]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
double a2[10]={1,2,3,4,5,6,7,8,9,10};
double aver(double b[],int n); //这样就已经理解了,定义这个函数,我们可以知道,是传入一个长度为n,类型是double型的数组,而后面b[],只是体现了这是一个没有声明长度数组,函数名也是形参,传入实参数组的时候可以变化。
double p,q;
p=aver(a1,15); //调用的时候切记前面是函数名,不用加中括号了
q=aver(a2,10);
printf("数组a1的平均值为%lf\n数组a2的平均值为%lf",p,q);
return 0;
}
double aver(double b[],int n) //函数定义时的函数首部只比函数声明少一个分号,无论是传入的什么形式的参数都这样,不要弄错~
{
double sum=0;
double aver1;
for (int i=0; i<n; i++) {
sum+=b[i];
}
aver1=sum/n;
return aver1;
}
*/
下面这个程序又带领大家复习了一下选择排序法,其实归根结底还是考差大家对函数的应用是不是熟练
//将一个数组作为参数传入函数中,此函数为选择排序法排序。(由大到小)
//选择排序,i是趟数也是该趟需要往下比较的元素的下标。j从i的下一个下标(i+1)开始,与k比较并将符合条件的下标赋给k,直到循环结束,k得到最终的下标,然后再和i交换。整个比较的过程i是不参与的(除了限制循环次数的时候用到),其余全部交给k和j来操作。而交换的时候,是i与k的操作,j不参与。最后输出,是i操作,j、k没有价值了。
/*//program 8.4
#include <stdio.h>
int main()
{
int a[10];
for(int i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
void sequence(int a[],int n);
sequence(a,10);
return 0;
}
void sequence(int a[],int n)
{
int i,j,k,temp;
for (i=0; i<=n-2; i++) {//
k=i;//看到选择排序法就要清楚,选择排序法最多进行n-1次交换,所以说,我们就清楚,需要找一个变量暂时储存较大值的下标k,然后最后交换关键的一次。这样才能交换的尽可能的少。
for (j=i+1; j<n; j++) {//记住,j表示每一趟的a[i]需要和哪些值比较。自然是和 a[i+1]~a[n-1] 之间的值比较
if(a[k]<a[j])//a[i]是当前趟数需要往下挨个比较的那一个元素,让k去替代i,然后用k和j比较,将较大的值的下标赋给k,k不断变化,变化的不能再大的时候,k也就是当前趟数比较得出的最大值的下标,然后a[k]就是当前趟数的最大值,最后再和下标i所代表的元素交换。
{
k=j;
}
}
temp=a[k];
a[k]=a[i];
a[i]=temp;
}
for (i=0; i<10; i++) {
printf("a[%d]=%d\n",i,a[i]);
}
}
*/
//多维数组做函数参数。
//有一个3*4的矩阵,求里面元素的最大值。
//用多维数组作为函数形参的时候,要记住,一维大小可以省略不填,但是二维大小一定要填上,而且还得和传入的实参数组二维大小一样。
//函数是很灵活的,函数里面的参数可以按需求定义~
/*//program 8.5
#include <stdio.h>
int main()
{
int a[3][4]={{1,2,3,9},{2,4,5,6},{1,2,1,8}};
int b[5][4]={{1,2,3,9},{2,4,5,6},{1,2,1,8},{1,2},{10,2,19}};
void max(int a[][4],int x);//x表示的一维大小,这里可以变化,只要是二维大小和声明的函数中保持一直就可以
max(a,3);
max(b,5);
return 0;
}
void max(int a[][4],int x)
{
int i=0,j=0,max2=a[0][0];
int x1=0,y1=0;
for (i=0; i<x; i++) {
for (j=0; j<4; j++) {
if(max2<a[i][j])
{
max2=a[i][j];
x1=i;
y1=j;
}
}
}
printf("max is [%d][%d]=%d\n",x1,y1,max2);
}
*/
//在函数内(或者复合语句内)声明的变量是局部变量,只在该函数内(或者复合语句内)作用。
//在函数外声明的变量是全局变量(也称外部变量),但是他们的作用范围不同,作用范围是从定义变量的位置开始到本源文件结束
//这个程序是错误的,因为输出的时候i已经被程序释放了。i是在for循环中定义的,随着for循环结束而释放。
/*//program 8.6
#include <stdio.h>
int main()
{
int sum=0;
for(int i=0;i<3;i++)
{
sum+=i;
}
printf(“sum=%d,i=%d",sum,i); //会显示i没有被定义
return 0;
}
*/
/*//program 8.7
//用一个一维数组存放10个学生的成绩,写一个函数,当主函数调用这个函数的时候,能求出平均分,最高分,最低分
#include "stdio.h"
float MAX,MIN,aver;//定义全局变量
int main()
{
int a[10]={80,81,82,83,84,85,86,87,88,89};
void abc(int b[10]);
abc(a);
return 0;
}
void abc(int b[10])
{
MAX=b[0];
MIN=b[0];
float sum=0;
for (int i=0; i<10; i++) {
if(MAX<b[i])
{
MAX=b[i];
}
if(MIN>b[i])
{
MIN=b[i];
}
sum=sum+b[i];
aver=sum/10;
}
printf(“MAX=%f,MIN=%f,aver=%f",MAX,MIN,aver); //aver没有定义成全局变量的时候会有警告,请读者分析一下为什么是这样。
}
*/
//在C中,每一个 变量 和 函数 都有两个属性,一个是数据类型(如:int,char等),另一个是数据的存储类别(如:静态存储和动态存储)。
//C的存储类别包括4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
//①自动变量(auto变量):auto存储类别属于 动态 存储方式,在程序中 大多数 变量都属于auto变量。关键字auto一般省略,在函数中定义的变量,其实都隐含指定为自动变量
//②静态局部变量(static局部变量):函数调用结束后不消失而继续保留原值,即占用的存储单元不释放。比如下面的程序:
/*//program 8.8
#include "stdio.h"
int main()
{
int f(int a);
int a=2,i;
for(i=0;i<3;i++)
{
printf("%d\n",f(a));
}
return 0;
}
int f(int a)
{
auto int b=0;
static int c=3;
b=b+1;
c=c+1;
printf("c=%d\n",c);
return(a+b+c);
}
*/
//运行的结果,输出:c=4,7,c=5,8,c=6,9 我们可以看出,c的值是不断增加的,因为c是不随着一次函数结束而释放的,他一直存在,所以每次使用c都是上一次函数调用完之后c的值,而运行结果也只是随着c的变化而变化,这是因为b是不变化的,函数调用完毕,b释放,所以b永远是从0开始去执行b=b+1的。
//输出n!,要求用静态变量。
/*//program 8.9
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
int f(int n);
printf("%d",f(n));
return 0;
}
int f(int n)
{
static int f=1;
while(n>=1)
{
f=f*n;
n--;
}
return f;
}
*/
//③寄存器变量(register):适用于大次数循环,直接将变量存储到CPU中的寄存器中,这样的存取速度远远高于对内存的存取速度。
//④外部变量(extern):可以给其他文件引用
//写出两个函数,分别求最大公约数和最小公倍数,用主函数调用这两个函数,整数a、b由键盘输入。
/*//program 8.10
#include <stdio.h>
int main()
{
printf("请输入两个数字:\n");
int yue(int x,int y);
int bei(int x,int y);
int a,b;
//int c,d;
scanf("%d%d",&a,&b);
//c=yue(a,b);
//d=bei(a,b);
//printf("%d %d",c,d);
printf("%d\n",yue(a,b));//这样输出或者是上面的先把值赋给变量再输出都行。
printf("%d\n",bei(a,b));
return 0;
}
int yue(int x,int y)
{
int temp,yueshu;
if(x>y)
{
temp=x;
x=y;
y=temp;
}
for(int i=x;i>=1;i--)
{
if(x%i==0&&y%i==0)
{
yueshu=i;
break;
}
}
return yueshu;
}
int bei(int x,int y)
{
int temp,beishu;
if(x>y)
{
temp=x;
x=y;
y=temp;
}
for(int i=y;i<=x*y;i++)//i是循环的变量,x、y只是控制i循环的次数。前面的i不要写成别的。
{
if(i%x==0&&i%y==0)
{
beishu=i;
break;
}
}
return beishu;
}
*/
//输入一个4位数字,要求在每两个数之间加一个空格输出
/*//program 8.11
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
void ab(int n);
ab(n);
return 0;
}
void ab(int n)
{
int g,s,b,q;
q=n/1000;
b=n%1000/100;
s=n%100/10;
g=n%10;
char cc[4]={'0'+q,'0'+b,'0'+s,'0'+g};//将数字转化为相对应的字符型的妙招,要知道一个数字字符('0'~'9')和字符'0'之间的距离正好是这个数字字符所代表的数字的大小。当然这个地方用整型输出也一样~ = =
for (int i=0; i<4; i++) {
printf("%c ",cc[i]);
}
}
*/
//将一个整数n转化为字符串n,n的位数不确定。
/*//program 8.12
#include "stdio.h"
int main()
{
int n;
printf("请输入一个整数:\n");
scanf("%d",&n);
void dc(int n);//int→char型的函数
dc(n);
return 0;
}
void dc(int n)
{
void d(int n);
if (n==0) {
char a=0+'0';
printf("%c",a);
}
else
{
d(n);
}
}
void d(int n)
{
int a[100],i=0;
while(n>0)
{
a[i]=n%10;
n=n/10;
i++;
}
int k=i;
char c[k];
for (i=0; i<k; i++) {
c[i]=a[k-i-1]+'0';//一般由整型的数字转化为字符型的该数字(如 5 转化成 '5'),转化的时候可以在整型后面加一个字符'0',那么表示的就是和字符'0'相差该数字长度的字符了,正好就是该数字字符。 相反的,如果是字符型的数字转化为整型的该数字(如 '5' 转化成 5),可以减去'0',表示的是该数字字符与字符'0'之间的距离,这个距离所表示的数值也正好是该数字。
}
printf("%s",c);
}
*/
//一些小验证
/*//program 8.13
#include "stdio.h"
int main()
{
int a=1%10;//结果为1
int b=1/10;//结果为0
int x=98,y=99,z=100;
char c[3]={x,y,z};//直接把整型的数字赋给字符型数组,那么输出的字符型数组中的元素 并不是 这三个数字字符,而是在ASCII码表中数字代表的字符。
printf("%d %d\n",a,b);
for(int i=0;i<3;i++)
{
printf("c[%d]=%c\n",i,c[i]);
}
return 0;
}
*/
//n个人报数,报123,报到3的出去,剩下的人再报数,问最后剩下几号?
/*//program 8.14
#include<stdio.h>
int main()
{
int i=0;
int n=0;
int out=0;//已经退出了out个人
int num=0;//报数的号码
int a[1000]={0};//a [i]=0表示该序号的人退出,等于1留下
printf("请输入n:\n");
scanf("%d",&n);
for (i=0; i<n; i++) {
a[i]=1;
}
i=0;
while (out!=n-1) {//n为1时不执行while语句
if(a[i]==1)//如果是1,就将报数的序号+1;
{
num++;
}
if(num==3)//序号一旦到3,序号就清零,继续从1开始报数,此时要把这一项的值设为0,也就是踢出去这一项
{
a[i]=0;
num=0;
out++;//排除一个就让out++ 让out来计算人数是不是还大于1个人 一个人的时候不执行while语句
}
i++;//每判断一项,都要让数组元素的下标+1,为什么写在这个地方,因为i对out(while语句是否结束)和num++(报数)都有影响,每改变一次i值,需要让这两个相关项都执行完毕后再让i++,所以说i++应该放在num和out的改变之后。(当然第一次刚进入while循环的时候i是有初始值的,这时直接进行num和out的变化就可以了)
if(i==n)//如果第一次所有人的循环到头了,比如说一共四个人,第三个人踢出去了,num=0,那么第四个人( a[3] )的num=1,然后i再加变成4,没有a[4]这一项,所以要将i变为0,再从头报数,不过这时候num没变还是1,所以下一个a[0]的num就是2了
{
i=0;//从始至终,原定a[i]的下标是没有改变的,这里让i=0,是i超了范围才改变的,改变完正好是第一个元素,报数也应该到了第一个元素了,所以说i==n(下标越界)应该放在最后,一旦越界,下标i立马变为一,再从第一个元素报数起
}
}
for (i=0; i<n; i++) {
if(a[i]==1)
{
printf("留下的人是%d号",i+1);
}
}
return 0;
}
*/
//求100~200之间的所有素数(用2~sqrt(n)去整除即可),这样判断的次数会大大降低。
/*//program 8.15
#include "stdio.h"
#include "math.h"
int main()
{
int i,j;
for(i=101;i<=200;i=i+2)//要从101 开始,依次加2判断,因为偶数肯定不是素数,不要从100开始
{
for(j=2;j<=sqrt(i);j++)
{
if(i%j==0)
break;
}
if(j>sqrt(i)) //如果在2~sqrt(i)之间都没有可以整除j的,那么j执行完最后一次j++后就将跳出内层for循环,这时我们就可以判断i是素数了,然后输出即可
printf("%d是素数\n",i);
}
return 0;
}
*/
今天我们主要是写了几个经典函数程序,然后我又对之前一些问题做了说明,今天学习的程序比较多,希望大家能按时掌握,越到后面越困难,大家一定要挺住!!!加油!!!
版权声明:本文为博主原创文章,未经博主允许不得转载。