12天学好C语言——记录我的C语言学习之路(Day 7)

12天学好C语言——记录我的C语言学习之路

Day 7:

昨天进行了一天的数组学习,今天大家可以先写几个昨天的程序热热身,回顾回顾,然后今天第一个新程序也是关于数组的,比较难,准备好就开始啦!

//输出奇数魔方阵,每一列、每一行以及对角线之和均相等(输入n为魔方阵的阶数,n为奇数)

//首先说明一下魔方阵的形成规律:①将元素1放在第一行中间一列;②依次将数字放在前一个数字的右上角,如果超过了魔方阵的范围,就拿另一侧的位置补齐,这个步骤需要想象成一个可以穿过边界到达另一头的贪吃蛇游戏;③如果另一侧补齐的位置处有元素在,则不考虑这个位置了,就直接把元素写在上一个元素的正下方的位置

//程序分析,我们是分了四部分来写这个方阵的形成规律。①右上角②第一行除右上角③最后一列除右上角④左下角剩下的所有元素(这些元素是最普通的,无特殊处理,顶多就是如果下一个元素位置上面不为0,那么就直接写在正下方)

/* 如下图是五阶魔方阵
 17  24  1   8   15
 23  5   7   14  16
 4   6   13  20  22
 10  12  19  21  3
 11  18  25  2   9
 */

/*//program 7.1
 #include "stdio.h"
 int main()   //这个程序是下标从0开始的
 {
 printf("请输入数字n,n代表魔方阵的阶数:\n");
 int a[20][20]={0},i,j,k,n;
 i=0;
 scanf(“%d",&n);   //输入魔方阵的维度n
 j=n/2;     // j是维度的一半取整,这里一定要注意,如果下标是从0开始的,那么3阶的时候元素1的位置就是(0,1),5阶的时候元素1的位置就是(0,2),可见元素的j坐标是n/2。如果下标从1开始的话,j=n/2+1。注意注意!!!!!
 a[i][j]=1;   //确定第一排的中间一个数为1
 for (k=2; k<=n*n; k++)   //从2开始,一直到n*n,按规律存放
 {
 i=i-1;   //正常情况下的走向是往右上角走,那么确定一个值的位置后(i,j),它的下一个值坐标正常情况下应该为(i-1,j+1)
 j=j+1;
 if(i<0&&j>n-1)   //最后的问题就是i<0的情况难道不就是i=-1吗?为什么不能用i=-1来代替i<0??? 这里说的很对,i<0的情况只有一个,就是i=-1,但是我们写判定条件的时候,要这样写if(i==-1&&j>n-1),也就是两种情况都可以。
 {   //如果该值已经在整个方阵的右上角(上图元素15的位置,第一行、第n列),那么放在这个值的正下方,又因为之前经过了行数-1,列数+1的变化,所以要变回原值的正下方,故得到下面两个变化。
 i=i+2;
 j=j-1;
 }
 if(i<0&&j<=n-1)
 {   //如果该值是处于第一行的位置(但是不包括上个条件排除的右上角的值),那么它的下一个值就应该处于最底行。
 i=n-1;
 }
 
 if(j>n-1)
 {   //如果该值是处于第n-1列(最后一列)的位置,那么它的下一个值一定处于第一列了
 j=0;
 }
 if (a[i][j]==0)
 {   //如果计算出来的位置上面还没有赋值,那么就将该数值赋给该位置
 a[i][j]=k;
 }
 else
 {   //如果计算出来的位置上面已经有数值存在了,那么也是将下一个数值放在其上一个数值的正下方
 i=i+2;
 j=j-1;   //这个地方其实也是是对变化过的i、j进行再操作
 a[i][j]=k;
 }
 }
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 printf("%-4d",a[i][j]);
 }
 printf("\n");
 }
 return 0;
 }
*/

上面那个程序的下标是从0开始的(第0行,第0列),可能有些刚打程序的读者有些别扭,那么下面我用下标从1开始写一下这个魔方阵程序,改了初始下标,希望读者能看出来程序哪里发生了实质上的改变。

/*//program 7.2
#include<stdio.h> //这个程序是下标从1开始的
 int main()
 {
 int a[20][20]={0},i,j,n;
 i=1;
 printf("请输入一个数");
 scanf("%d",&n);//输入魔方阵的维度n
 j=n/2+1;     // j是维度的一半加1.
 a[i][j]=1;   //确定第一排的中间一个数为1
 for(int k=2;k<=n*n;k++)//已经确定1的位置了,再循环确定2~n*n的位置
 {
 i=i-1;      //挪位,横坐标往上挪一位。
 j=j+1;      //挪位,纵坐标往右挪一位。
 if((i<=0)&&(j<=n))   //如果横坐标挪到顶,同时纵坐标还没有超过最右,横坐标就到从最下再继续。原位置是第一行 除了 右上角的
 i=n;
 if((i<=0)&&(j>n)) //如果横坐标挪到顶,同时纵坐标超过最右,横坐标往下挪两位,纵坐标排往左移一位。原位置是第一行右上角
 {
 i=i+2;
 j=j-1;
 }
 if(j>n)  //如果只有纵坐标超过最右,纵坐标挪到左边第一行。
 {
 j=1;
 }
 if(a[i][j]==0)
 a[i][j]=k;  //如果这个位置还没有赋值,那么赋值为k。
 else        //已经赋值过了。那么竖排往下挪两位,横排往左移一位,再赋值为k。
 {
 i=i+2;
 j=j-1;
 a[i][j]=k;
 }
 }
 for(i=1;i<=n;i++) //循环输出位置。
 {
 for(j=1;j<=n;j++)
 printf("%5d",a[i][j]);
 printf("\n");
 }
 }
*/

魔方阵程序不难,如果说读者一时消化不了,可能难点就在魔方阵的算法难理解,还有就是对临界点几个情况的分析。另外一旦下标初始值发生改变了,可能就单单改了一个从0开始还是从1开始,就又让人迷糊一阵子。这里慢慢琢磨总能琢磨出来的,现在有程序给大家参考,想起来还是比较方便的,可以先把程序拷下来运行一下,然后自己理解了这道题的含义在自己试着去敲。希望大家能牢牢的掌握这个程序。

下面这个程序是要输出一个平行四边形的。这个程序有一个地方我觉得初学者可能会犯错,给大家拿出来说一下。

*****     
 *****    
  *****   
   *****  
    *****
 
输出上面的图形。
         
/*//program 7.3
#include<stdio.h>
int main()
{
    int i,j;
    char a[10][10];
    for(i=0;i<10;i++)    //先把每一个数组中的元素都赋上空格~然后把需要替代的元素用'*'替代就好了
        for (j=0; j<10; j++) {
            a[i][j]=' ';
        }
    
    for (i=0; i<=4; i++) {
        for (j=i; j<=i+4; j++) {
            a[i][j]='*';
            // printf(“%c",a[i][j]);    //不要赋值一个就输出一个,你输出的只是你赋值的这些元素,而那些被初始化为空格的元素是没有输出的,所以就会出现输出一个长方形的现象(这就是读者需要注意的一个地方,在此我已经注释掉了)
        }
        //printf("\n");
    }
    for (i=0; i<10; i++) {
        for (j=0; j<10; j++) {
            printf(“%c",a[i][j]);    //把该赋值的都赋值完了,然后将所有元素输出,自然得到想要的结果了~
        }
        printf("\n");
    }
    return 0;
}
*/

数组方面的学习到此为止了,用了一天多点的时间,我觉得学习重在自己的理解和练习,只要是打够代码,一定能在短时间里有质的提升。下面我们开始函数的学习:

//   注意一下无参函数和有参函数的调用形式
//   abc(); 这是调用无参函数      c=def(a,c,v); 这是调用有参函数(注意把结果要赋给一个变量),当然函数调用本身并不一定非要有分号或者是把结果赋给一个变量,如:printf(“%d",max(a,b));

一个小程序(program 7.4)让大家感受一下函数。
对了,也不知道提醒没提醒过大家,max函数是自己人为写的,可没有什么头文件中含有这个函数的,不要直接就用,虽然这个函数作用很简单

/*//program 7.4
 #include "stdio.h"
 int main()
 {
 int max(int ab,int cd);    //ab、cd都是形参
 int a,b,k;     //这里是定义变量
 scanf("%d%d",&a,&b);
 k=max(a,b);    //a、b是实参,调用函数调用的是实参
 printf("%d",k);
 return 0;
 }
 int max(int x,int y){
 int c;
 c=(x>y)?x:y;
 return c;
 }
 */

下面我们来学习一下函数的嵌套,看程序 program 7.5

/*//program 7.5
//输入四个数,找出最大值,用函数的嵌套实现。
#include "stdio.h"
int max1(int a,int b,int c,int d);
int max2(int a,int b);
int temp;
int main()
{
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    a=max1(a,b,c,d);    //可以把最后的结果赋给a,都是形参
    printf("max is %d\n",a);
    return 0;
}
int max1(int f,int b,int c,int d)    //这里的f,b,c,d都是形参
{
    int m;
    m=max2(f,b);    //应用了函数的嵌套,从上到下进行读取执行
    m=max2(m,c);
    m=max2(m,d);
    return m;
}
int max2(int a,int b)
{
    if (a<b) {
        temp=a;
        a=b;
        b=temp;
    }
    return a;
}
*/

当然上面的方法感觉还是太过繁琐,我们还可以再优化一下:

/*//program 7.6
//对上题的改进。
#include <stdio.h>
int main()
{
    int max3(int,int);
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    printf(“%d",max3(max3(max3(a,b),c),d));    //多重嵌套,这样只需要写一个函数max3就可以了~简单明了
    return 0;
}
int max3(int a,int b)
{
    int temp;    //temp必须在这里声明,而不能在主函数中声明,两边不扯
    if (a<b) {
        temp=a;
        a=b;
        b=temp;
    }
    return a;
}
 */

在看这样一个题目,关于函数的 递归调用。

//有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?(program 7.7)

/*//program 7.7
#include <stdio.h>
int main()
{
    int a,n;
    scanf("%d",&n);
    int age(int n);
    a=age(n);
    printf("age=%d",a);
    return 0;
}
int age(int n)
{
    int c;   //注意,这里函数名和变量名不能重名
    if (n==1) {
        c=10;
    }
    else
    {
        c=age(n-1)+2;
    }
    return c;
}
*/
   
程序比较简单,读者耐心看一下就能看懂。

那么再做一个题目来加深一下今天学习过的递归问题。
 
//用递归方法求n!

/*//program 7.8
#include <stdio.h>
int main()
{
    int n,a;
    scanf("%d",&n);
    int mul(int n);
    a=mul(n);
    printf("n!=%d",a);
    return 0;
}
int mul(int n)
{
    int m;
    if (n==1||n==0) {
        m=1;//不管n多大,n都肯定要慢慢减少最终等于1的,而最后n=1时,m是1,这个m是mul(1),而不是取代了之前算出来的m的值,递归的意义就在此。也可以这么想,最后的m=1是最内层的m,最内层的m求出来了,然后逐渐扩大到最外层的也就是最终的结果了
    }
    else
    {
        m=n*mul(n-1);
    }
    return m;
}
 */

最后一个程序结束今天的学习,这个题目比较的抽象,也是递归题目里面必做的一道题,那就是Hanoi塔问题,让我们一起来尝试一下吧。

/*//program 7.9
//Hanoi塔问题
#include <stdio.h>
int main()
{
    int n;
    scanf("%d",&n);
    void Hanoi(int n,char a,char b,char c);   //把m个盘子从 圆柱a 上通过 圆柱b 移至 圆柱c
    Hanoi(n,'A','B','C');
    return 0;
}
void Hanoi(int n,char a,char b,char c)
{
    void move1(char a,char b);    //Hanoi函数中需要用到Move1函数,所以Move1函数要在Hanoi函数中声明一下
    
    if(n==1)
    {
        move1(a,c);
    }
    else
    {
        Hanoi(n-1, a, c, b);    //想到这里的时候,一定得想到递归的逻辑是什么,做递归的题目,不要带入数进行验证,只要把递归到最底层的值写出来之后,剩下的就是n到n-1之间的递归,我认为此时可以在脑海里念着怎么移动,用通俗的语句来表示这复杂的代码
        move1(a, c);
        Hanoi(n-1, b, a, c);    //这句话就可以这样理解“将n-1个盘子从b通过a移动到c上”
    }
}
void move1(char a,char b)    //这里就不用解释了吧,将这个程序分解开来其实简单不过了
{
    printf("将一个盘子由%c移至%c\n",a,b);
}
*/

好了,第七天的学习结束了,不知道大家掌握的怎么样,希望今天的学习大家也能够牢牢的记在心里,一定要多做题,一道题再简单敲一遍是不够的,多多敲几遍,你会有不同的收获!
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值