Introduction
Today we’re gonna learn about C’s control structures. We will analyze the if statement, its cousin switch statement and the dreaded goto. We will also learn how to pass arguments to a C program and how to work with them in code.
So without further ado, let’s dive straight into it!
If, else and if-else
You probably know if-statements from other languages. In case you don’t, it is a basic control structure that branches the code depending on the condition. Its structure looks like this:
if (CONDITION) {
CODE;
} else if (CONDITION) {
CODE;
} else {
CODE;
}If you’re coming from more modern languages, you might expect the boolean values true and false. While the C if-statement uses the idea of true and false to do the branching, there are is no true boolean type. Instead, an integer that is 0 is false, and anything else is true. This is a good example of C being closer to how computers work internally since true and false values are just 1 and 0 integers to a computer.
In case you are not familiar with if-statements. The program processes the if-statements sequentially, first checking the first if, then else-if and so on. If there is an else-statement at the end and no condition evaluated as true before, that block of code is run.
There are 3 things you should keep an eye out for C if-statements:
- The CONDITION part is false when it evaluates to 0, otherwise it’s true.
- The if-statement needs to be encapsulated in parentheses. Some other languages allow you to skip it, C does not.
- The { } braces are not needed if the CODE is just one statement. This is usually looked upon as bad practice, if you need to change the CODE to more lines, you need to add the extra braces anyway. The braces also make it clear where one branch starts and ends. Use this at your own risk, annoying errors can grow from it.
Logical operators: &&, || and !
If you want to make complex conditions using the logical and, or, not, you need to use &&, ||, ! respectively.
if (CON_1 && CON_2) {
// Both conditions evaluated as true.
} else if (CON_1 || CON_2) {
// Either CON_1 or CON_2 evaluated as true.
} else if (!(CON_1 || CON_2)) {
// None of the conditions evaluated as true.
} else if (!CON_1 && !CON_2) {
// None of the conditions evaluated as true.
// Can also be written like this.
}Exercise
Before showing you the exercise, let’s talk about passing arguments to a C program. To pass the arguments, you simply write words separated by spaces after the path to the binary. Example:
$ ./program arg1 arg2 arg3So with that, let’s jump into our excercise, you will get the hang of how the arguments are passed when looking at the code.
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("That's too little arguments.\n");
} else if (argc > 2 && argc < 5) {
printf("That's the perfect amount of arguments :)\n");
printf("Good job!\n");
} else {
printf("That's just too many arguments now, mate.\n");
printf("You're overdoing it!\n");
}
return 0;
}The main function now has two variables inside its parantheses. These are called parameters of a function (described in future lessons). The main function either accepts 0 or 2 parameters. These being the parameters into which arguments of the program are passed.
int argc– number of arguments passed to a program, if no arguments are passed, the value is one because the first argument is always the name of the program.- char *argv[] – This is an array of pointers to char, which in more human language means array of strings. Here is stored the actual string representation of arguments. (We will go over arrays of strings in upcoming lessons)
We will only work with argc in today’s lesson and argv in the next one. Let’s analyze the code a little bit. (L3 = line number 3)
- L3: main function decleration with two parameters
- L4-5: execute this block if one or no arguments has been passed to the program
- L6-8: execute this block if two or three arguments has been passed
- L9-12: If any other number of arguments has been passed, execute this block
Try running the program with different arguments. You’ve got an interactive program now, depending on how many arguments you pass to it, it reacts differently 😊 Here are some examples:
$ ./ex1 1
That's too little arguments.
$ ./ex1 hello world
That's the perfect amount of arguments :)
Good job!
$ ./ex1 to be or not to be
That's just too many arguments now, mate.
You're overdoing it!
$ ./ex1 who am i
That's the perfect amount of arguments :)
Good job!Switch statement
In other languages, the switch-statement is just a syntax alternative to an if-statement that works the same internally. In C however, only integer values can be passed to the individual cases and the condition itself must result in an integer (or ‘char’ since they’re stored as integers). This way the switch acts more likea goto with its own jump table—thus making it more efficient.
switch (CONDITION) {
case CONSTANT_1:
CODE;
break;
case CONSTANT_2:
CODE;
break;
default:
CODE;
break;
}Individual cases include constants to which the code jumps if it matches the condition’s result. When there is no case constant that matches the result, default case is chosen instead. If there is no break; the code continues sequentially (until it hits a break), thus acting like a goto.
Try rewriting our previous program with switch-statement 😊 Really try it before looking at my solution.
.
.
.
Here it is!
#include <stdio.h>
int main(int argc, char *argv[]) {
switch (argc) {
case 1:
case 2:
printf("That's too little arguments.\n");
break;
case 3:
case 4:
printf("That's the perfect amount of arguments :)\n");
printf("Good job!\n");
break;
default:
printf("That's just too many arguments now, mate.\n");
printf("You're overdoing it!\n");
break;
return 0;
}We can take advantage of the fall through until break statement is encountered and group cases 1 and 2 together. The same code will be run for these two cases. Even though this is not the best example of a switch-statement I hope you can see how the structure works. We query the argc variable and depending on its value we branch out the code using cases.
GOTO
goto is one of programming’s controversial topics. It jumps to a label defined in code. This goes against structured programming using if-else constructs and loops as we know it, the code soon becomes hard to maintain and devolves to spaghetti.
if (TEST_ERROR) {
goto error;
}
...
error:
CODE;In C however, it’s got its uses for error handling and exiting out of nested loops. These are quite special cases though and are only appropriate for larger programs.
Once again, try rewriting our piece of code using gotos. We will still need if-statements so this is not an ideal example to present, but try moving the printing logic using gotos. If you don’t know how to proceed, just look below.
.
.
.
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 3) {
goto little;
} else if (argc > 2 && argc < 5) {
goto good;
} else {
goto end;
}
little:
printf("That's too little arguments.\n");
goto end;
good:
printf("That's the perfect amount of arguments :)\n");
printf("Good job!\n");
goto end;
many:
printf("That's just too many arguments now, mate.\n");
printf("You're overdoing it!\n");
end:
return 0;
}As you can see the code really starts to look like a mess. And this is just a simple example. Apart from a label for each if-branch, we need an end label, so the printing logic does not cover multiple branches. I hope you can see the logic behind goto now.
If you already know how functions work from other languages, you can see that these goto cases could easily be replaced by a function call.
Looping using goto
Since I will be covering loops in the next lesson, I would like to show you an example from programming history on how to use loop logic without any loop structures (like it used to be done decades ago), just by using goto. A loop is a piece of code that is repeated until a certain condition is met. Let’s print numbers starting from 0 to 9.
#include <stdio.h>
int main() {
int i = 0;
again:
printf("%d ", i);
i++;
if (i < 10) {
goto again;
}
printf("\n");
return 0;
}Let’s analyze it:
- L4: define the variable
i, which is usually used to count the number of iterations - L5: define
againlabel - L6: print the current value of
i - L7: increment
iby one, can be rewritten toi += 1, which isi = i + 1 - L8-10: if
iis less than 10, loopagain
Try running the above program, I’m sure you understand it, this is the basics of looping which I will introduce next time. Now you know how to create a loop using goto and you can flex on others 😁.
Conclusion
This is it for today. In the next lesson we will continue with the C’s control structures—continuing with loops—as I promised.
See you until then! 😁