c - 这个 C for 循环如何打印文本艺术金字塔?

标签 c for-loop

这是我第一次在这里发帖,希望我做对了。

基本上我需要帮助试图找出我使用 C 为类编写的一些代码。该程序的目的是向用户询问 0 到 23 之间的数字。然后,根据用户输入的数字,半金字塔将被打印出来(就像老式马里奥游戏中的那些)。我是编程的初学者,仅靠运气就得到了我的代码的答案,但现在我真的不知道我的 for 循环是如何提供金字塔图的。

#include <stdio.h>

int main ( void )
{
    int user_i;
    printf ( "Hello there and welcome to the pyramid creator program\n" );
    printf ( "Please enter a non negative INTEGER from 0 to 23\n" );
    scanf ( "%d", &user_i );

    while ( user_i < 0 || user_i > 23 )
    {
        scanf ( "%d", &user_i );
    }

    for ( int tall = 0; tall < user_i; tall++ )
    {
        // this are the two for loops that happened by pure magic, I am still
        // trying to figure out why are they working they way they are
        for ( int space = 0; space <= user_i - tall; space++ )
        {
            printf ( " " );
        }
        for ( int hash = 0; hash <= tall; hash++ )
        {
            printf ( "#" );
        }
        // We need to specify the printf("\n"); statement here
        printf ( "\n" );
    }

    return 0;
}

作为编程新手,我遵循了我对伪代码知之甚少的知识,我似乎无法理解为什么 for 循环部分的工作方式如此。我完全理解 while 循环(尽管欢迎更正和最佳实践),但 for 循环逻辑仍然让我难以理解,我想在继续之前完全理解这一点。任何帮助将不胜感激。

最佳答案

我将解释我如何理解这段代码的过程,直到我自己可以舒服地使用它。我会假装没有读你的描述,所以我从头开始。该过程分为几个阶段,我将在进行时编号。我的目标是提供一些使程序更易于阅读的通用技术。

第 1 阶段:了解粗略结构

第一步是大致了解程序的作用,而不会陷入细节的困境。让我们开始阅读 main 函数的主体。

int main(void) {
    int user_i;
    printf("Hello there and welcome to the pyramid creator program\n");
    printf("Please enter a non negative INTEGER from 0 to 23\n");
    scanf("%d", &user_i);

到目前为止,我们已经声明了整数,并告诉用户输入一个数字,然后使用 scanf函数将整数设置为等于用户输入的内容。不幸的是,从提示或代码中不清楚整数的用途是什么。让我们继续阅读。
    while (user_i < 0 || user_i > 23) {
        scanf("%d", &user_i);
    }

这里我们可能会要求用户输入额外的整数。根据提示判断,这条语句的目的是确保我们的整数在适当的范围内,这似乎是一个很好的猜测,这很容易通过检查代码来检查。让我们看看下一行
     for (int tall = 0; tall < user_i; tall++) {

这是外部 for 循环。我们的神秘整数 user_i再次出现,我们得到另一个整数 tall介于 0 之间和 user_i .让我们再看一些代码。
        for (int space = 0; space <= user_i - tall; space++) {
            printf(" ");
        }

这是第一个内部 for 循环。让我们不要纠结于这个新整数 space 发生了什么的细节。或者为什么我们有 user_i - tall出现,但让我们注意, foo 循环的主体只是打印一个空格。所以这个 for 循环只是有打印一堆空格的效果。让我们看看下一个内部 for 循环。
        for (int hash = 0; hash <= tall; hash++) {
            printf("#");
        }

这个看起来很像。它只是打印一堆散列。接下来我们有
        printf("\n");

这将打印一个新行。接下来是
    }

    return 0;
}

这意味着外部 for 循环结束,在外部 for 循环结束后,程序结束。

请注意,我们发现了代码的两个主要部分。第一部分是 user_i 的值获得,第二个部分,外层 for 循环,必须是这个值用来绘制金字塔的地方。接下来让我们试着弄清楚 user_i方法。

第二阶段:发现user_i的含义

现在,由于外循环的每次迭代都会打印一个新行,而神秘的 user_i控制有多少外循环迭代,因此打印多少新行,看起来 user_i控制创建的金字塔的高度。为了获得确切的关系,让我们假设 user_i有值 3 ,然后 tall将采用值 0、1 和 2,因此循环将执行 3 次,金字塔的高度将为 3。另请注意,如果 user_i将增加一,然后循环将再次执行,金字塔将高一。这意味着 user_i必须是金字塔的高度。让我们将变量重命名为 pyramidHeight在我们忘记之前。我们的主要功能现在看起来像这样:
int main(void) {
    int pyramidHeight;
    printf("Hello there and welcome to the pyramid creator program\n");
    printf("Please enter a non negative INTEGER from 0 to 23\n");
    scanf("%d", &pyramidHeight);
    while (pyramidHeight < 0 || pyramidHeight > 23) {
        scanf("%d", &pyramidHeight);
    }

    for (int tall = 0; tall < pyramidHeight; tall++) {
        for (int space = 0; space <= pyramidHeight - tall; space++) {
            printf(" ");
        }
        for (int hash = 0; hash <= tall; hash++) {
            printf("#");
        }
        printf("\n");
    }

    return 0;
}

第 3 阶段:创建一个获取金字塔高度的函数

既然我们理解了代码的第一部分,我们就可以把它移到一个函数中,不再去想它。这将使代码更易于查看。由于这部分代码负责获取有效的高度,所以我们调用函数getValidHeight .这样做后,注意金字塔高度在 main 中不会改变。方法,因此我们可以将其声明为 const int .我们的代码现在看起来像这样:
#include <stdio.h>

const int getValidHeight() {
    int pyramidHeight;
    printf("Hello there and welcome to the pyramid creator program\n");
    printf("Please enter a non negative INTEGER from 0 to 23\n");
    scanf("%d", &pyramidHeight);
    while (pyramidHeight < 0 || pyramidHeight > 23) {
        scanf("%d", &pyramidHeight);
    }
    return pyramidHeight;
}

int main(void) {
    const int pyramidHeight = getValidHeight();
    for (int tall = 0; tall < pyramidHeight; tall++) {
        for (int space = 0; space <= pyramidHeight - tall; space++) {
            printf(" ");
        }
        for (int hash = 0; hash <= tall; hash++) {
            printf("#");
        }
        printf("\n");
    }

    return 0;
}

第 4 阶段:了解内部 for 循环。

我们知道内部 for 循环会重复打印一个字符,但是有多少次呢?让我们考虑第一个内部 for 循环。打印了多少个空格?您可能认为通过与外部 for 循环类比,有 pyramidHeight - tall空格,但这里我们有 space <= pyramidHeight - tall真正类似的情况是 space < pyramidHeight - tall .因为我们有 <=而不是 < ,我们得到一个额外的迭代,其中 space等于 pyramidHeight - tall .因此我们看到实际上pyramidHeight - tall + 1打印空格。同样tall + 1散列被打印。

第 5 阶段:将多个字符的打印移动到它们自己的功能中。

由于多次打印一个字符很容易理解,我们可以将这段代码移到它们自己的函数中。现在让我们看看我们的代码是什么样的。
#include <stdio.h>

const int getValidHeight() {
    int pyramidHeight;
    printf("Hello there and welcome to the pyramid creator program\n");
    printf("Please enter a non negative INTEGER from 0 to 23\n");
    scanf("%d", &pyramidHeight);
    while (pyramidHeight < 0 || pyramidHeight > 23) {
        scanf("%d", &pyramidHeight);
    }
    return pyramidHeight;
}

void printSpaces(const int numSpaces) {
    for (int i = 0; i < numSpaces; i++) {
        printf(" ");
    }
}

void printHashes(const int numHashes) {
    for (int i = 0; i < numHashes; i++) {
        printf("#");
    }
}

int main(void) {
    const int pyramidHeight = getValidHeight();
    for (int tall = 0; tall < pyramidHeight; tall++) {
        printSpaces(pyramidHeight - tall + 1);
        printHashes(tall + 1);
        printf("\n");
    }

    return 0;
}

现在,当我查看 main 时功能,我不用担心细节如何printSpaces实际上打印空格。我已经忘记它是否使用 for循环或 while环形。这让我的大脑腾出时间去思考其他事情。

第 6 阶段:引入变量并为变量取好名字

我们的 main功能现在易于阅读。我们已经准备好开始考虑它的实际作用了。 for 循环的每次迭代都会打印一定数量的空格,然后是一定数量的散列,然后是新行。由于空格是先打印的,所以它们都会在左边,这就是我们想要得到它给我们的图片。

由于新行打印在终端上的旧行下方,因此 tall 的值为零对应于金字塔的顶行。

考虑到这些,让我们引入两个新变量,numSpacesnumHashes用于在迭代中打印的空格和哈希数。由于这些变量的值在一次迭代中不会改变,我们可以将它们设为常量。也让我们更改名称 tall (这是一个形容词,因此对于整数来说是个坏名字)到 distanceFromTop .我们新的 main 方法看起来像这样
int main(void) {
    const int pyramidHeight = getValidHeight();

    for (int distanceFromTop = 0; distanceFromTop < pyramidHeight; distanceFromTop++) {
        const int numSpaces = pyramidHeight - distanceFromTop + 1;
        const int numHashes = distanceFromTop + 1;
        printSpaces(numSpaces);
        printHashes(numHashes);
        printf("\n");
    }

    return 0;
}

阶段 7:为什么是 numSpacesnumHashes它们是什么?

现在一切都在一起了。唯一需要弄清楚的是给出 numSpaces 的公式和 numHashes .

让我们从 numHashes 开始因为它更容易理解。我们要 numHashes当与顶部的距离为零时为 1,我们希望 numHashes距离顶部的距离增加一,所以正确的公式是 numHashes = distanceFromTop + 1 .

现在为 numSpaces .我们知道,每次与顶部的距离增加,一个空格就会变成一个散列,因此就少一个空格。因此 numSpaces 的表达式应该有一个 -distanceFromTop在里面。但是顶行应该有多少个空格?由于第一行已经有一个哈希值,所以有 pyramidHeight - 1需要做的散列,所以必须至少有 pyramidHeight - 1空格,以便它们可以转换为哈希值。在代码中我们选择了 pyramidHeight + 1顶行中的空格,比 pyramidHeight - 1 多两个,因此具有将整个图片向右移动两个空格的效果。

结论

你只是问两个内部循环是如何工作的,但我给出了一个很长的答案。这是因为我认为真正的问题不在于您没有充分理解 for 循环如何工作,而是您的代码难以阅读,因此很难说出正在做什么。所以我向你展示了我将如何编写程序,希望你会认为它更容易阅读,这样你就能更清楚地看到发生了什么,并希望你能学会自己编写更清晰的代码。

我是如何更改代码的?我更改了变量的名称,以便清楚每个变量的作用;我引入了新变量并尝试给它们取个好名字;我将一些涉及输入和输出以及打印字符一定次数的逻辑的低级代码移到了它们自己的方法中。最后的更改大大减少了 main 中的行数功能
,摆脱了 main 中 for 循环的嵌套功能,并使程序的关键逻辑一目了然。

关于c - 这个 C for 循环如何打印文本艺术金字塔?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21211205/

相关文章:

javascript - for循环 react

c - 库利 FFT 的实现问题

c - 错误: expected ')' before numeric constant (fwrite)

c - 在 freertos API 中使用队列

python - 引用python中的列表容器理解for循环

scala - 为什么scala中for循环的每次迭代参数是val而不是var

c - 未定义对 'mysql_get_client_info' Eclipse Centos 6 的引用

c - malloc 错误,我无法理解使用具有单独链接的哈希表

objective-c - 如何在 Objective-C 中创建一个空数组,并为它一个一个赋值?

c - 我不明白我的代码中发生了什么