More Logic

More Logic

So far we’ve just about explained how the if/then/else works, and how the Return command works. There are more commands that you need to understand before you can use C to its fullest.

For Next Loops

These are sooooo widely used it’s unbelievable. The basic structure is really easy. The idea is to have a tightly controlled loop. Here’s a real basic example

int         x;

for( x = 0; x < 100; x++)
{
blah;
}

What we see here is that there is going to be a loop run 100 times, with the variable x as the controlling mechanism. After each loop x is incremented. Note, we have to declare the integer we are using as the controller.

The syntax here breaks down into three parts.

The first is the expression after the brackets – x = 0; This is where we set up the initialization of the for loop. We zero out the controller variable so we know the conditions of the loop. The second part is the decision maker itself, the part that says “Shall we continue this loop?”. That’s the part that says x < 100;.
The content of this part of the command is exactly the same as inside of an if statement. You can get as fancy as you want, with brackets and or/and statements all over the place. The last part if the x++. This continues the loop, and will eventually bring it to an end.

Now some notes on the For/Next loop idea. All the code it executes is within the curly brackets. As with if statements, if you are only running one line, you don’t actually need the curly brackets. I would still recommend using them though, for reasons I went into earlier.
Since the decision maker on the loop is ABOVE the code to be executed, if the decision maker fails on the first try, then the code will never run. For instance if instead of setting x to 0 in the initialization we set it to 200, the loop would drop immediately, since x is greater than 100 on the first check.
You CAN change the main check variable inside of the loop if you want to prematurely end a for/next look. As you can see in the next example, we are modifying x by ourselves instead of letting the loop doing it. If we wanted to exit early, we could just set x to 100 and we’d drop out.
Also, you don’t actually HAVE to have either initialization or increments inside the loop expression. For example

int         x = 0;

for ( ; x< 100; {
blah;
x++;
}

is just as legal as the original example. Sometimes in fact you don’t want the initialization to take place since you may be using a variable that has been modified above where the for/next loop takes place.

One last thing. You can do multiple variable initializations and increments inside of the loop definition. For example

int         x, y;

for (x = 0, y = 100; x<100; x++, y–)
{
blah;
}

would initialize x and y (notice they are separated by commas, not semi colons), do the normal decision maker, then increment x and decrement y. At the end of the loop x = 99 and y = 1;

While loops

While loops are pretty similar to for/next loops, except they are much more open ended. An example

int         x = 0;

while (x < 100)
{
blah;
x++;
}

This pretty much does the same as the For/Next loop, with the same caveat that if we set x to 100 before the loop is encountered, the loop code will never be executed. So if it’s the same, why use them at all? Well, the example is a bit misleading, since for this situation you’d never use the while loop at all. You use the while loop for situations when you have no idea of the number of loops you are going to want to do. In the example above we KNOW we want to do 100 loops, hence the check for when 100 is reached. What if we are reading a file, but we have no idea of where the end is? In that case we’d code something like

{
}

Using a For next loop under these circumstances is less efficient and more messy than using the while loop for what it’s intended for – open ended looping.

Note -  you may find routines that are intended to get into an endless loop that use this command. For instance

While(1)
{
main loop of game;
}

This ensures that we just keep looping, and never drop out.

Do while Loops

Do While loops are similar to normal while loops, except they vary the syntax a bit so that you are guaranteed that you get at least one execution of the loop code. For example

Int         x = 0;

Do
{
blah;
x++;
} while (x < 100);

will give you the same result as the straight while loop example above. However, if we set the variable x to 200 when it’s created, we will still get on execution of the loop before it decides it doesn’t want to do any more. A subtle but important difference.

Switch / Case statements

Sometimes you find yourself in a situation where you are doing repeated if/then tests on the same variable. For instance, a token comes in and it could mean many different things, and you need to perform a different function dependent on it’s value. This is where there the switch/case statement comes in.
For example

Switch ( token)
{
case VALUE_A:
function_a();
printf(“Function a performed\n”);

case VALUE_B:
function_b();
printf(“Function b performed\n”);

case VALUE_C:
function_c();
printf(“Function c performed\n”);
}

What we’ve got going on here is that the switch statement itself specifies the variable we are doing the tests on, in this case its token. Inside it’s curly brackets we are seeing the case statements, which basically mean “If token is equal to this, then do this code.”. Notice there are no curly brackets required around the code for each case statement, but there ARE ordinary colons at the end of the case specifier.
Incidentally this is a perfect place to use that #define or enumeration stuff we talked about in the variables lesson – you can see I’ve used #define variables for the switch comparisons, since they are upper case.

There are some other things to know about case statements. The first is, don’t modify the token being used in mid case. This can lead to some weird results. The way that case statements work is that they are the equivalent of many if/then statements. Not if/then/else. There is a difference.
If you did this

If (token == VALUE_A)
{
function_a();
printf(“Function a performed\n”;
token = VALUE_B;
}

if (token == VALUE_B)
{
function_b();
printf(“Function b performed\n”;
token = VALUE_B;
}

then you’d expect both function_a and function_b to be performed right? Well, if you modified the variable token in the case statement for VALUE_A, then the next case statement would be hit as well. While this is a possible thing, often it’s not desirable, so be careful coding these.

One other thing to mention is that if you want to do the same code for more than one case value, you can stack the case tests on each other. For example

case VALUE_A:
case VALUE_D:
function_a();
printf(“Function a or d performed\n”);

will hit function_a if token is either VALUE_A or VALUE_B.

But what if in the first switch example we had a value of token that was equivalent to VALUE_D? It’s not catered for, so what happens? Well, in this example, nothing. Since token didn’t match any of the current case statements, the code will just drop out without doing anything.

If you want a catchall for un-catered to possibilities, then you need to use the default command.
For example.

Switch ( token)
{
case VALUE_A:
function_a();
printf(“Function a performed\n”);

case VALUE_B:
function_b();
printf(“Function b performed\n”);

case VALUE_C:
function_c();
printf(“Function c performed\n”);

default:
printf(“Unknown variable value encountered. %d\n”, token);
}

will mean that if we have a token value of anything other than VALUE_A, VALUE_B or VALUE_C we will get an error message. Be aware that the default statement should go at the end of the switch statement, or it will get hit when it shouldn’t. If we put it right after the test for VALUE_A, then it would hit even if the token value was VALUE_B or VALUE_C; default just grabs anything that hasn’t already been hit.

But what if we hit VALUE_A and we don’t want to go any further? How do we do that? Aha. I thought you’d never ask. That leads us nicely into…

Break / Continue

Break pretty much exits whatever looping command you are in, and continue makes you jump directly to the next loop test.
That’s it. Some examples.

int         x;

for( x = 0; x < 100; x++)
{
if (array_value[x] > 100)
{
continue;
}
if (array_value[x] == -1)
{
break;
}
function_a(x);
}

n this instance, if the array_value[x] under test is greater than 100 then we will simply bypass all the other code until the close curly bracket is hit. The we just re-run the loop like we would if we had processed everything normally.
If the array_value[x] under test is a –1, then we will jump to the close brackets, like a continue would do, but we will exit the loop no matter what the value of x is. This is a way of forcing your way out.

An example within the switch/case statement.

Switch ( token)
{
case VALUE_A:
case VALUE_D:
function_a();
printf(“Function a performed\n”);
break;
case VALUE_B:
function_b();
printf(“Function b performed\n”);
break;
case VALUE_C:
function_c();
printf(“Function c performed\n”);
break;
default:
printf(“Unknown variable value encountered. %d\n”, token);
}

What we see here is that if any of the VALUE_ tests are hit, we will exit the switch case immediately that their code is performed. This is handy to stop further testing, since that could lead to some weird results, and plus it’s just processing we don’t need to do .
One thing to note about break is that it will only exit the current loop your in. If you’ve nested two for/next loops then break will only get you out of the one you are in.

For example

int         x, z;
for( x = 0; x < 100; x++)
{
if (array_value[x] > 100)
{
continue;
}
if (array_value[x] == -1)
{
break;
}
for (z = 0; z<10; z++)
{
if (function_a(x, z))
{
break;
}
}
}

if you get a non zero return from the function_a then the for/next loop using the variable z will exit, but not the for/next loop with the x variable as the decision maker.   Goto / Labels   These are bad. Repeat after me “I don’t use Goto’s”.

Again.

Now again.

Now write it out a 100 times. Get the idea?

However, in the interests of completeness, I’ll explain what it is and how to use it. If you want to get to a specific line of code within a procedure quickly, you can do it using a goto. Goto’s work by jumping to labels in the code directly. If you are inside of loops then sometimes bad things can happen.
Goto’s completely negate the point of organized code, but unfortunately there are sometimes no other alternative.

An example
{
goto exit;
}
do other processing here
return;

exit:
{"ft_lang_label":"__label__en","ft_lang_prob":0.8877749,"math_prob":0.9439083,"size":10855,"snap":"2022-05-2022-21","text_gpt3_token_len":2601,"char_repetition_ratio":0.1356557,"word_repetition_ratio":0.05909091,"special_character_ratio":0.25140488,"punctuation_ratio":0.12010559,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9722715,"pos_list":[0,1,2,3,4],"im_url_duplicate_count":[null,null,null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-01-26T09:10:11Z\",\"WARC-Record-ID\":\"<urn:uuid:880932bd-a11f-4b8b-aa3e-68dabb41133d>\",\"Content-Length\":\"40996\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:0a2b3b14-d258-4ca5-903d-7763948e3a36>\",\"WARC-Concurrent-To\":\"<urn:uuid:66ea7d38-8f63-4aa9-a726-69e12136f791>\",\"WARC-IP-Address\":\"216.197.109.61\",\"WARC-Target-URI\":\"http://jakeworld.org/JakeWorld/index.php/the-c-tutorials/1754-2/\",\"WARC-Payload-Digest\":\"sha1:GX5OTT5A7JSDNZTYSEQYCFJT3OQND43W\",\"WARC-Block-Digest\":\"sha1:YSRMT54YBMUPOILPBMWRI25G5OV2HM3I\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-05/CC-MAIN-2022-05_segments_1642320304928.27_warc_CC-MAIN-20220126071320-20220126101320-00427.warc.gz\"}"}