[C语言] 数组的实际应用三则

0.前言

1.上一篇文章中,我们重点讲述了:如何main函数的各个模块转化为函数,使得main函数简介合理,利于阅读、整理。
2.今天,则主要讲解c语言中数组的知识及其应用(包括进制转换以及两个有趣的游戏

1.文章目的:

  • 阐述数组的语法、特点等基础知识

  • 通过例子来探究c语言中数组的使用方法、使用思路、注意事项

2.本文主要提及的技术

2.1数组

2.1.1数组基本概念

数组能够开辟多个连续的空间,每个存储空间都能存放一个类型相同的元素
 
注意事项:

(1)此概念仅针对c语言,在java等语言中,同一个数组可以存放不同类型的元素
(2)数组分配的内存空间是连续的,所以如果数组分配空间较大,可能会失败
(3)静态数组定义时必须明确知道数组的大小

2.1.2数组的优缺点

(1)数组的语法定义较为简单
(2)由于有索引值,因此“查找”操作较为轻松
(3)删除数组中央的某个元素较为困难

2.1.3数组的定义

数组的定义方式有三种:
(1)初始化里面确定数组大小

int score[] = {29,13,23,11};

(2)在定义时,明确指定数组大小

int temp[5]; //没有立刻分配空间,int默认元素为0

(3)在定义时明确指定数组大小,且对数组进行一定的初始化

int temp2[5] = {1,2};

注意:

  • 静态数组定义时,不能使用变量
int a[m] = {};//这是错误的写法


2.1.4数组的其他重要知识

(1)数组名,这个变量所占用的内存空间中,存放着数组首地址(同时也是第一个元素的地址)

printf("%p\n", &score[0]);
printf("%p\n", score);
这两句话的效果相同,其中%p专门用来打印地址,而“&”则是代表取变量的地址

(2)数组与循环的关系较为密切

①一般情况下, 对于将某些元素逐个装入数组中的过程,会使用数组+循环的组合
②另外,如果是两个字符串的对比,实际上也是将字符串放入数组中,依靠循环进行比较(比如下文中会提到的猜数字游戏,就是这个道理)


3.技术的具体应用

接下来主要谈一谈标题所提到的数组的实际应用的思路,具体实现会放在下一部分

3.1 应用1——进制转换

(1)数组的主要应用:记录计算结果,并输出

(2)程序思路:
该程序的目的是将任意的十进制数,转换为其他进制数,并输出
如十进制中的数字20,转换为二进制形式,为10100
具体算法根据如下:

十进制转化为二进制方法.jpg

由图可见,转换结果为10100

我们要做的,就是把这个10100放入数组中。
但是按照这个算法得到数字的顺序是00101,(即数组的第一个元素放的是数字的最后一位)因此输出的时候必须倒过来输出(如何倒过来输出后面再说)

3.2 应用2——游戏1·最后谁留下来

效果如图:


image.png

image.png

(1)数组的主要应用部分:记录每个人的编号、是否被淘汰
(2)游戏过程:

先输入一个淘汰号码,每个人从1开始按顺序依次喊出号码,喊出淘汰号码的人便会被淘汰,下一个人从1开始重新喊
该程序的作用便是能够通过不断循环遍历数组,逐次找出被淘汰的编号,以得出最后的生还者

(3)代码思路:

①将每个人的编号记录在一个数组中,然后设置两个变量,一个记录数组下标,一个记录喊出的号码
②两个数同时增加,当喊出的号码等于淘汰号码时,将对应的编号设置为' * '(星号),然后重置喊出的号码(赋值为1),
③重复上述内容,当检测到数组中内容为星号时,跳过该次循环(因>为星号代表已经被淘汰)

3.3 应用3——游戏2·猜数字

先放效果图:
image.png

(1)游戏规则:

①系统会随机生成四个不同的数字,玩家需要猜测分别是什么
②玩家允许对正确答案进行猜测,对于玩家的猜测,系统会给予一定的反馈
③反馈格式为:mA,nB
其中m为A的个数,n为B的个数,A表示位置和数字都同时猜对的数字个数,B表示数字猜对了但是位置不对的数字个数
④玩家一共有10次机会,需要不断根据反馈调整自己的答案,以找出正确的序列

(2)数组的主要应用:
数组在这个程序中,主要是用来存放两个序列(正确序列与猜测序列),然后比较两个序列中的值,并返回A与B的个数

4.实际应用(具体实现步骤)

三个例子,我们一个个分析

4.1进制转换的实现

(1)代码细节:

    int result[20] = {};
    int i = 0;//从第一个元素开始,而且最后i可以反映数组中有多少个元素

逐步分析代码:
①首先定义一个数组result[20]以及变量“i”,这个变量i十分重要,不仅可以在下面展示while循环中起到记录下标,其最终结果,还能展现出进制转换后的数字的位数(因为我们不知道转化后的数字有多少位,可以靠i来获取)

    //开始将转换后的数字按照逆序放入数组中
    while (num != 0) {
        result[i] = num % system;//把余数依次放在数组中
        num /= system;//被除数要更新为商
        i++;
    }

这个while循环是由辗转相除法得来的,system指的是进制数,num为待转换的数
result[i]依次装入num对system取余的结果

//开始输出
    printf("该数字的%d进制为",system);
    for (i--; i >= 0; i--) {
        if (result[i]>=10) {
            printf("%c", result[i]+'A'-10);
        }

        else {
            //0到9的数字直接输出即可
            printf("%d", result[i]);
        }
    }
    printf("\n");

最后输出即可,需要注意的是,由于数组中是按照逆序存储的最终结果,因此得倒过来输出
而最终结果的长度,就可以看上文所说的变量i

  • for循环中的第一个i--是因为上面额代码i多++了一次
  • if(result[i]>=10)主要是针对10以上的进制,如十六进制,这些进制会出现10以上的一些数字,并用大写字母代替,而printf("")中的result[i]+'A'-10,则是将数组中大于等于10的数字,转化为对应的英文大写字符(根据ASCII码)

4.2游戏1·最后谁留下来

(1)代码细节:

int nowNum = 1;//当前喊出来的号码
    int lastNum = 7;//剩余人数
    int totalNum = 7;
    int i = 0;

    //1.固定7个人游戏,每个人编号分别是1到7
    char order[7];
    for (int i = 0; i < 7; i++) {
        order[i] = i + '1';
        //printf("%c ", order[i]);
    }

①先定义一些变量,然后定义一个char类型的长度为7的数组,并逐个赋值'1','2',‘3‘ .......‘7’
使用char类型的主要原因是后面想要通过*星号来代表被淘汰的人(当然用int类型数组,然后用0表示淘汰也行)

②然后就是对结果进行验算:

//2.对结果进行验算
    while (lastNum > 1) {
        //此时喊出号码,并判断是否为死亡号码
        if (i == totalNum) {
            //如果已经到头了,回到开头
            i = 0;
        }
        if (order[i] == '*') {
            //已经死亡了,直接下一个
            i++;
            continue;
        }
        else if (nowNum == dieNum) {
            order[i] = '*';
            lastNum--;//剩余人数减1
            nowNum = 1;

            //淘汰一个人就输出一次
            for (int j = 0; j < 7; j++) {
                printf("%c ", order[j]);
            }
            printf("\n");
        }
        else {
            //否则继续喊出号码
            nowNum++;
        }
        i++;
        

    }

③其中lastNum表示剩余人数,totalNum表示总人数(这里其实是数组的长度,不会变化,该变量主要用于下标到6之后,能够通过if语句重新回到0)

④nowNum指的是当前喊出的号码,dieNum表示淘汰号码,当二者相同时,表明该选手被淘汰,则有:

if (nowNum == dieNum) {
            order[i] = '*';
            lastNum--;//剩余人数减1
            nowNum = 1;

            //淘汰一个人就输出一次
            for (int j = 0; j < 7; j++) {
                printf("%c ", order[j]);
            }
            printf("\n");
        }

被淘汰的人用星号表示,下一次星号,则只能下标++,nowNum(喊出的号码)不会变化,即:

else {
            //否则继续喊出号码
            nowNum++;
        }

另外,淘汰号码可以通过手动输入的方式进行更改:

printf("请输入淘汰号码:");
scanf_s("%d", &dieNum);
whoDie(dieNum);//淘汰游戏函数

4.3游戏2·猜数字

(1)代码细节:

int correctOrder[4];//放正确答案
    int guessOrder[4];//放猜测的
    srand((unsigned)time(NULL));//用来生成随机数的种子
    int num = 0;
    int numA = 0;
    int numB = 0;
    int totalTime = 10;//总共10次机会

①先定义变量
②然后下面开始制作正确的序列:

//1.准备好正确的数组序列
    for (int i = 0; i < 4; i++) {
        num = rand() % 10;//0到9随机取一个
        for (int j = 0; j < i; ) {//保证四个数字不重复
            if (num == correctOrder[j]) {
                num = rand() % 10;
                j = 0;
            }
            else {
                j++;
            }
        }
        correctOrder[i] = num;
        //printf("%d ", num);//测试用,打印看一下

    }

其中

 for (int j = 0; j < i; ) {//保证四个数字不重复
            if (num == correctOrder[j]) {
                num = rand() % 10;
                j = 0;
            }
            else {
                j++;
            }
        }

该for循坏主要效果是,将前面已经定好的数字与这次随机数产生的数字进行比较,如果有相同的,则重新去随机数

③获取猜测序列:

//3.输入猜测序列
        printf("输入你的猜测序列:\n");
        while (site != 4) {
            scanf_s("%d", &num);
            guessOrder[site] = num;

            site++;
        }

这里虽然是循环4次,每次只获取1个,但是可以一次性输入四个(中间要有一个空格)

④计算A和B的数量:

numA = numB = 0;//重新从零计算
        for (int m = 0, j = 0; m < 4; m++) {
            if (correctOrder[m] == guessOrder[m]) {
                //看看有没有A
                numA++;
            }
            else {
                //看看有没有B
                j = 0;//重新从头比较
                for (; j < 4; j++) {
                    if (m == j) {
                        //没有A,所以i和j相同的时候跳过
                        continue;
                    }
                    else if (correctOrder[m] == guessOrder[j]) {
                        numB++;
                        break;//B数目+1之后就退出循环
                    }
                }
            }
        }
        printf("%dA,%dB\n\n", numA, numB);

计算思路为:
将两个序列(正确的与猜测的)对齐,然后先看第一个下标的元素,将正确的元素与猜测的相比,如果正确,则numA++
如果不正确,则开始找有没有B,方法就是讲正确的第一个下标元素,以此与猜测序列后面的数字相比较,有相同的则numB++并停止循环

后面的同理,先比较相同位置,看有无A,没有的话再看有无B

⑤最后判断是否达成结束游戏的条件

//5.判断是否结束游戏
        if (numA != 4) {
            totalTime--;
            if (totalTime == 0) {
                printf("机会已经用光\n");
                exit(EXIT_FAILURE);
            }
            else {
                //机会还没有用光,但是还没有正确
                printf("还有%d次机会,请继续", totalTime);
            }

        }

先用if判断numA有没有4个(有就证明已经猜对了)
然后在让totalTime--,并判断机会用光了没有


从第③步到第⑤步,是个循环(毕竟有多次机会),需要用while套在外面,循环条件则是numA != 4

while (numA != 4) {
        site = 0;//每次重新赋值

        //3.输入猜测序列
        printf("输入你的猜测序列:\n");
        while (site != 4) {
            scanf_s("%d", &num);
            guessOrder[site] = num;

            site++;
        }

        //4.下面开始计算A和B的个数
        numA = numB = 0;//重新从零计算
        for (int m = 0, j = 0; m < 4; m++) {
            if (correctOrder[m] == guessOrder[m]) {
                //看看有没有A
                numA++;
            }
            else {
                //看看有没有B
                j = 0;//重新从头比较
                for (; j < 4; j++) {
                    if (m == j) {
                        //没有A,所以i和j相同的时候跳过
                        continue;
                    }
                    else if (correctOrder[m] == guessOrder[j]) {
                        numB++;
                        break;//B数目+1之后就退出循环
                    }
                }
            }
        }
        printf("%dA,%dB\n\n", numA, numB);

        //5.判断是否结束游戏
        if (numA != 4) {
            totalTime--;
            if (totalTime == 0) {
                printf("机会已经用光\n");
                exit(EXIT_FAILURE);
            }
            else {
                //机会还没有用光,但是还没有正确
                printf("还有%d次机会,请继续", totalTime);
            }

        }
    }
    printf("恭喜你猜对了!\n");

5.总结

(1)这次对于数组的三个应用练习,使得我对于数组的运用更加熟练,同时也使我能变得更好地把控函数的书写,以及如何搭建main函数中的逻辑构架
(2)而关于上文代码中需要注意的是,如果想要更改第一个游戏中的总游玩人数(如从键盘手动输入),需要用到动态数组,以及指针,如果有兴趣的可以自行修改,本文就布详细说明了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • HTML 5 HTML5概述 因特网上的信息是以网页的形式展示给用户的,因此网页是网络信息传递的载体。网页文件是用...
    阿啊阿吖丁阅读 3,887评论 0 0
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,744评论 0 10
  • 第四天 数组【悟空教程】 第04天 Java基础 第1章数组 1.1数组概念 软件的基本功能是处理数据,而在处理数...
    Java帮帮阅读 1,598评论 0 9
  • 像每一个晚饭后的时光一样,刘东又跟苏妍有一搭没一搭的聊着,说实话,刘东并不是一个很好的聊天对象,开头第一个...
    瑾沐阅读 1,417评论 0 0