The C Programming Language

Conditional Statements

Preface

In this article, the first part about conditional statements, we'll discuss the basics; conditional statements, relational, equality and logical operators, the ternary operator, and switch statements.
Disclaimer: In the examples provided in the article, I use scanf. I recommend not using since it's problematic. Its use in here assumes input is correct.

Conditional Statements

In procedural programming, conditional statements (conditionals) control the flow of the program, allowing specific blocks of code to be executed only under the correct circumstances; only if certain conditions are met.

If and Else Statements

Let's take a look at the following code, can you guess what it does?

#include <stdio.h>

#define NOT_SO_SECRET_NUM 5321


int main(){

 int input = -1;
 scanf("%d", &input);
 if(input == NOT_SO_SECRET_NUM){
  printf("Welcome!");
 }
 else{
  printf("This is just a vending machine, nothing to see here!");
 }
 return 0;
}

Surely you have inferred from the context that this code takes an input, and compares it with a specific number, if the input and the number are equal, it executes a specific block, else, it executes another block instead.
The syntax of an if statement is very clear:

if(YOUR_EXPRESSION_HERE){
 // BLOCK OF CODE;
}

It checks an expression, YOUR_EXPRESSION_HERE, and executes a block of code. An expression can be anything that evaluates to a value. An expression can use relational, equality, and logical operators to define the evaluation, and thus, you can decide the conditions a variable has to fulfill. The if statement doesn't have to be a block of code, it can also be a single code statement (one line of code):

if(YOUR_EXPRESSION_HERE)
 // SINGLE CODE STATEMENT;

Of course indentation is cosmetic.
You can also add an else statement afterwards.

if(YOUR_EXPRESSION_HERE){
 // BLOCK OF CODE;
}
else{
 // ANOTHER BLOCK OF CODE;
}

If YOUR_EXPRESSION_HERE is true, the first block of code will be executed, else, meaning it was false, the other block of code will be executed. For clarity, if the first EXPRESSION was true the other block of code won't be executed.
But what if I want more than a binary flow of code? let's say I have 3 different conditions? Well, you can combine if and else statements to structure any type of flow, let's adjust our code so a neighboring "vending machine" owner won't get angry with us:

#include <stdio.h>

#define NOT_SO_SECRET_NUM 5321
#define A_DIFFERENT_SEC_NUM 1111


int main(){

 int input = -1;
 scanf("%d", &input);
 if(input == NOT_SO_SECRET_NUM){
  printf("Welcome!");
 }
 else if(input == A_DIFFERENT_SEC_NUM){
  printf("This is not the vending machine you're looking for!");
 }
 else{
  printf("This is just a vending machine, nothing to see here!");
 }
 return 0;
}

Only one of the blocks of code will be executed, the flow begins from the first statement, goes over the second, then ends with the else statement. You can add as many else ifs, but only a single else statement. In fact, this is actually just a single if statement, and a single else statement, only that the else statement executes a single code statement, that code statement being the other if statement, which has the actual else statement following it. This isn't important to remember to be frank, but it's a neat thing to know.

But what are the "true" and "false" mentioned above? They're intuitively understood to the programmer, but what are they to the compiler? Basically, "true" is any non-zero value, be it an integer's, or a double's*, and "false" is just 0. Note that in other programming languages we use bool with keywords true and false. Basic C has _Bool without the keywords true and false, and in stdbool there's bool with the keywords true and false. I prefer to refrain from using both, as I deem them as impractical.

*A lot of problems can arise from comparing doubles due to floating point representation, more on that in a later article.

Relational Operators

Relational operators are crucial parts of conditional statements, they're used to compare values. Here's a list of them:

Equality Operators

Yes, there is a distinction between relational and equality. Although both compare values, the difference is the relational expressions get evaluated before equality expressions. Here's the "list" of them:

Logical Operators

What if I want a block of code or a statement to execute if one of multiple conditions are met? Using multiple if statements with duplicated blocks/statements of code is inefficient and bad programming, remember: Avoid code duplication. For that, we have logical operators, Here's a list:

Example

Let's combine what we've learned until now and write a simple program:

#include <stdio.h>

#define NOT_SO_SECRET_NUM 5321
#define A_DIFFERENT_SEC_NUM 1111


int main(){

 int temperature = -1;
 int raining = -1;
 int work = -1;
 printf("What is the temperature?\n");
 scanf("%d", &temperature);
 printf("Is it raining? (0 or 1)\n");
 scanf("%d", &raining);
 printf("Do you have work? (0 or 1)\n");
 scanf("%d", &work);
 if(!work && !raining && temperature >= 22 && temperature < 26){
  printf("I'm going for a walk!");
 }
 else{
  printf("Guess I can't got for a walk right now...");
 }
 return 0;
}

Here we can see all the criteria that need to be met for taking a walk. Remember to name your variable meaningful names so as to have readable code. If you want to run this code for yourself it's at the end of the article.

Lazy Evaluation

In the previous example, the expression inside the if statement is a chain of && between 4 different expressions. If the first one was false, the rest aren't checked. That would be because of lazy evaluation. In cases like these, if any expression is false, the program will not check whether the rest are true or false, given the fact that it won't matter anyway.

Ternary Operator

The ternary operator is neat and useful when you want to assign different values based on a condition being met or not. Let's look at this example:

if(units == 'c'){
 x = x - 1;
}
else{
 x = x + 1.8;
}

We want to add a singular unit of temperature, but we don't know if it's in Celsius or Fahrenheit, without converting back and forth everytime we want to adjust the temperature. Sure, there's a way to do this without using any conditional statement, but for the sake of the example, we can replace the code snippet above with the following:

x = units == 'c' ? x - 1 : x + 1.8;

If the expression is true, x gets assigned the first value, x + 1. If the expression is false, x gets assigned the second value, x + 1.8.
The syntax in general is:

EXPRESSION ? VAL_IF_TRUE : VAL_IF_FALSE

This entire statement evaluates to VAL_IF_TRUE if EXPRESSION is true, and evaluate to VAL_IF_FALSE if EXPRESSION is false. This can be used in assignment such as the example above, or even as an expression, given the fact that it evaluates to a value, it can evaluate to a zero or a non-zero value. Basically anything that can evaluated can be used as an expression. So it's legal to put an assignment, a ternary statement, or function call inside an if statement.

switch statemnt

Sometimes when writing code, you might run into a situation where you might want to check a variable against a list of cases, for that, we have switch statements. Consider the following: Let's say I want take as an input a character, and check if it's any specific mode out of a set, and executing specific code as a result. Writing it using if-else statements is inefficient and bulky. Instead, use a switch statement with different cases, and a default case:

#include <stdio.h>
int main(){
 char mode = -1;
 printf("Enter the mode:\n");
 scanf("%c", &mode);
 switch(mode){
  case('D'):{
   printf("Drive");
   break;
  }
  case('F'):{
   printf("Fly");
   break;
  }
  case('S'):{
   printf("Swim");
   break;
  }
  default:{
   printf("Error: Non-existent mode.");
   break;
  }
 }
 return 0;
}

In this example we're checking the char "mode" for multiple cases; if D then drive, if F then fly, and so on...
Of course this example is rudimentary, but it's here to get the idea across. The break keyword breaks the iterating over the cases. If a case matched, once the program reached the break statement in the end, then it does not continue iterating. It's optional, although I haven't seen a switch statement being used like that. If no cases match, then it reached the default and executes the relevant code block. The default case is also optional.
The syntax, is simple:

switch(MY_EXPRESSION){
 case(OPTION_1){
  // BLOCK OF CODE OR STATEMENT;
  // OPTIONAL BLOCK;
 }
 case(OPTION_2){
  // OTHER BLOCK OF CODE OR STATEMENT;
  // OPTIONAL BLOCK;
 }
  .
  .
  .
 case(OPTION_N){
  // N'TH BLOCK OF CODE OR STATEMENT;
  // OPTIONAL BLOCK;
 }
 default:{
  // DEFAULT'S BLOCK OF CODE OR STATEMENT;
  // DEFAULT IS OPTIONAL
  // BREAKING IS ALSO REDUNDANT
 }
}

The EXPRESSION, can be anything that evaluates to a value, usually, a variable. As mentioned above, the default case is optional.

Summary

These are the basics of conditionals statements. We've learned about if and else statements, relational, equality, and logical operators and expressions. We also covered lazy evaluation, switch statements, and ternary operators.
In the next chapter, we'll discuss loops. Until then!

conditionals1.c
conditionals2.c
conditionals3.c

Contents