This is my first time posting in here, hopefully I am doing it right.
Basically I need help trying to figure out some code that I wrote for class using C. The purpose o
for ( int tall = 0; tall < user_i; tall++ ) { ... }
I think of this in natural language like this:
And with nice indentation in your code now it's much easier to see how the for loops are nested. The inner loops are going to be run for every iteration of the outer loop.
The simplest answer to why that is happening is because one loop prints spaces like this represented by -.
----------
---------
--------
-------
------
-----
and so on. The hashes are printed like this
------#
-----##
----###
---####
--#####
-######
since hash printing loop at second stage needs to print equal no of hashes more to complete the pyramid it can be solved by two methods one by copying and pasting hash loop twice or by making the loop run twice next time by following modification
for ( int hash = 0; hash <= tall*2; hash++ )
{
printf ( "#" );
}
The logic to build such loops is simple the outermost loop prints one line feed to seperate loops,the inner loops are responsible for each lines contents. The space loop puts spaces and hash loop appends hash at end of spaces. [My answer can be redundant because i did not read other answers so much carefully,they were long] Result:
#
###
#####
#######
#########
###########
This type of small programs are the one which kept fascinating me in my earlier days. I think they play a vital role in building logics and understand how, when, where and in which situation which loop will be perfect one.
The best way one can understand what happening is to manually debug each and every statement.
But to understand better lets understand how to build the logic for that, I am making some minor changes so that we can understand it better,
n
is no of lines to print in pyramid n =5
' '
with '-'
(dash symbol) Now pyramid will look something like,
----#
---##
--###
-####
#####
Now steps to design the loop,
n
lines i.e. 5 lines so first loop will be running 5
times.for (int rowNo = 0; rowNo < n; rowNo++ )
the Row number rowNo
is similar to tall
in your loop5
characters but such that we get our desired figure, if we closely look at what logic is there,rowNo=0
(Which is our first row) we have 4
dashes and 1
hashrowNo=1
we have 3
dashes and 2
hashrowNo=2
we have 2
dashes and 3
hashrowNo=3
we have 1
dashes and 4
hashrowNo=4
we have 0
dashes and 5
hashrowNo
we have to print n - rowNo - 1
dashes -
and rowNo + 1
hashes #
,for
loop we have to have two loops, one to print dashes and one to print hashes.for (int dashes= 0; dashes < n - rowNo - 1; dashes ++ )
, here dashes
is similar to space
in your original programfor (int hash = 0; hash < rowNo + 1; dashes ++ )
,Hope, the above explanation provides a clear understanding how the for loops that you have written will be formulated.
In your program there are only minor changes then my explanation, in my loops I have used less then <
operator and you have used <=
operator so it makes difference of one iteration.
I will explain the process of how I would come to understand this code to the point where I would be comfortable using it myself. I will pretend that I did not read you description, so I am starting from scratch. The process is divided into stages which I will number as I go. My goal will be to give some general techniques which will make programs easier to read.
The first step will be to understand in general terms what the program does without getting bogged down in details. Let's start reading the body of the main function.
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);
So far, we have declared in integer, and told the user to enter a number, and then used the scanf
function to set the integer equal to what the user entered. Unfortunately it is unclear from the prompt or the code what the purpose of the integer is. Let's keep reading.
while (user_i < 0 || user_i > 23) {
scanf("%d", &user_i);
}
Here we possibly ask the user to enter additional integers. Judging by the prompt, it seems like a good guess that the purpose of this statement is to make sure that our integer is in the appropriate range and this is easy to check by examining the code. Let's look at the next line
for (int tall = 0; tall < user_i; tall++) {
This is the outer for loop. Our enigmatic integer user_i
appears again, and we have another integer tall
which is going between 0
and user_i
. Let's look at some more code.
for (int space = 0; space <= user_i - tall; space++) {
printf(" ");
}
This is the first inner for loop. Let's not get bogged down in the details of what is going on with this new integer space
or why we have user_i - tall
appearing, but let's just note that the body of the foor loop just prints a space. So this for loop just has the effect of printing a bunch of spaces. Let's look at the next inner for loop.
for (int hash = 0; hash <= tall; hash++) {
printf("#");
}
This one looks similar. It just prints a bunch of hashes. Next we have
printf("\n");
This prints a new line. Next is
}
return 0;
}
This means that the outer for loop ends, and after the outer for loop ends, the program ends.
Notice we have found two major pieces to the code. The first piece is where a value to user_i
is obtained, and the second piece, the outer for loop, must be where this value is used to draw the pyramid. Next let's try to figure out what user_i
means.
user_i
Now since a new line is printed for every iteration of the outer loop, and the enigmatic user_i
controls how many iterations of the outer loop there are, and therefore how many new lines are printed, it would seem that user_i
controls the height of the pyramid that is created. To get the exact relationship, lets assume that user_i
had the value 3
, then tall
would take on the values 0,1, and 2, and so the loop would execute three times and the height of the pyramid would be three. Notice also that if user_i
would increase by one, then the loop would execute once more and the pyramid would be higher by one. This means that user_i
must be the height of the pyramid. Let's rename the variable to pyramidHeight
before we forget. Our main function now looks like this:
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;
}
Since we understand the first part of the code, we can move it into a function and not think about it anymore. This will make the code easier to look at. Since this part of the code is responsible for obtaining a valid height, let's call the funcion getValidHeight
. After doing this, notice the pyramid height will not change in the main
method, so we can declare it as a const int
. Our code now looks like this:
#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;
}
We know the inner for loops print a character repeatedly, but how many times? Let's consider the first inner for loop. How many spaces are printed? You might think that by analogy with the outer for loop there are pyramidHeight - tall
spaces, but here we have space <= pyramidHeight - tall
where the truly analogous situation would be space < pyramidHeight - tall
. Since we have <=
instead of <
, we get an extra iteration where space
equals pyramidHeight - tall
. Thus we see that in fact pyramidHeight - tall + 1
spaces are printed. Similarly tall + 1
hashes are printed.
Since printing a character multiple times is easy to understand, we can move this code into their own functions. Let's see what our code looks like now.
#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;
}
Now when I look at the main
function, I don't have to worry about the details of how printSpaces
actually prints the spaces. I have already forgotten if it uses a for
loop or a while
loop. This frees my brain up to think about other things.
Our main
function is now easy to read. We are ready to start thinking about what it actually does. Each iteration of the for loop prints a certain number of spaces followed by a certain number of hashes followed by a new line. Since the spaces are printed first, they will all be on the left, which is what we want to get the picture it gives us.
Since new lines are printed below old lines on the terminal, a value of zero for tall
corresponds to the top row of the pyramid.
With these things in mind, let's introduce two new variables, numSpaces
and numHashes
for the number of spaces and hashes to be printed in an iteration. Since the value of these variables does not change in a single iteration, we can make them constants. Also let's change the name of tall
(which is an adjective and hence a bad name for an integer) to distanceFromTop
. Our new main method looks like this
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;
}
numSpaces
and numHashes
what they are?Everything is coming together now. The only thing left to figure out is the formulas that give numSpaces
and numHashes
.
Let's start with numHashes
because it is easier to understand. We want numHashes
to be one when the distance from the top is zero, and we want numHashes
to increase by one whenever the distance from the top does, so the correct formula is numHashes = distanceFromTop + 1
.
Now for numSpaces
. We know that every time the distance from the top increases, a space turns into a hash, and so there is one less space. Thus the expression for numSpaces
should have a -distanceFromTop
in it. But how many spaces should the top row have? Since the top row already has a hash, there are pyramidHeight - 1
hashes that need to be made, so there must be at least pyramidHeight - 1
spaces so they can be turned into hashes. In the code we have chosen pyramidHeight + 1
spaces in the top row, which is two more than pyramidHeight - 1
, and so has the effect of moving the whole picture right by two spaces.
You were only asking how the two inner loops worked, but I gave a very long answer. This is because I thought the real problem was not that you didn't understand how for loops work sufficiently well, but rather that your code was difficult to read and so it was hard to tell what anything was doing. So I showed you how I would have written the program, hoping that you would think it is easier to read, so you would be able to see what is going on more clearly, and hopefully so you could learn to write clearer code yourself.
How did I change the code? I changed the names of the variables so it was clear what the role of each variable was; I introduced new variables and tried to give them good names as well; and I moved some of the lower level code involving input and output and the logic of printing characters a certain number of times into their own methods. This last change greatly decreased the number of lines in the main
function
, got rid of the nesting of for loops in the main
function, and made the key logic of the program easy to see.
A few things:
Consider "bench checking" this. That is, trace through the loops yourself and draw out the spaces and hash marks. Consider using graph paper for this. I've been doing this for 15 years and I still trace things out on paper from time to time when they're hairy.
The magic in this is the value "user_i - tall" and "hash <= tall". Those are the conditions on the two inner for loops as the middle values in the parenthesis. Note what they are doing:
Because tall is "going up" from the outer-most loop, by subtracting it from user_i, the loop that prints the spaces is "going down". That is, printing fewer and fewer spaces as it goes.
Because tall is "going up", and because the hash loop is just basically using it as-is, it's going up too. That is, printing more hash marks as you go.
So really ignore most of this code. It's generic: the outer loop just counts up, and most of the inner loops just do basic initialization (i.e. space = 0 and hash = 0), or basic incrementation (space++ and hash++).
It is only the center parts of the inner loops that matter, and they use the movement of tall from the outermost loop to increment themselves down and up respectively, as noted above, thus making the combination of spaces and hash marks needed to make a half-pyramid. Hope this helps!
Analyzing your loops:
The first loop
for ( int tall = 0; tall < user_i; tall++ ){...}
is controlling the row. The second loop
for ( int space = 0; space <= user_i - tall; space++ ){...}
for the column to be filled by spaces.
For each row , it will fill all the user_i - tall
columns with spaces.
Now the remaining columns are filled by #
by the loop
for ( int hash = 0; hash <= tall; hash++ ){...}