Skip to content
Home » All Posts » How Not To Exploit The C Loops

How Not To Exploit The C Loops

the c loops

Introduction

C Loops are control structures used for executing a block of code repeatedly until a specified condition is met. There are 3 primary loop types in C, each with their own advantages and use cases.

The While Loop

The while loop is useful when the number of iterations is not fixed but based on a condition.

Syntax:

while (condition) 
{
	/* code to be executed */
}

Example:

int a = 11;
while (a > 10 && a < 15)
{
	printf("a = %d\n", a);
	if (a == 13)
		break;
	a++;
}

The while loop in the example above executes the block of code as long as a is in between the range of 10 and 15 none-exclusive. At the end of the loop, the value of a is incremented by 1 via the increment operator (a++). Without this increment at the end, the while loop would result in a infinite loop because the value of a is always between the range of 10 and 15. There is, however, a conditional statement inside the loop that will jump out of the loop with a break clause if a == 13, this condition bypasses the while loop’s original condition. The example above will produce this output:

a = 11
a = 12
a = 13

The For Loop

The for loop is suitable when the number of iterations is known.

Syntax:

for (initialization; condition; increment/decrement) 
{
    /* code to be executed */
}

Example:

int b = 0;
for (b = 0; b < 5; b++)
{
	printf("b = %d\n", b);
}

The for loop in the example above will execute the printf 5 times, each with different values of b. You can also write logic to break out of the for loop early under some condition. The above example produces this output:

b = 0
b = 1
b = 2
b = 3
b = 4

The Do While Loop

Similar to the while loop, but it ensures that the code block is executed at least once. In other words, do while loop executes the block of code first and then check the conditions to keep looping. This guarantees that this structure is run at least once.

Syntax:

do 
{
	/* code to be executed */
} while (condition);

Example:

int c = 10;
do
{
	printf("c = %d\n", c);
	c++;
} while (c < 10);

The do while example above will execute printf exactly one time even though the condition to keep looping does not meet. It produces this output:

c = 10

Infinite Loops and C Loops Best Practices

An Infinite loop refers to a C loop that loops forever without a condition to break out of it or with a condition to exit that is rarely met. The following is an example of an infinite loop that does nothing:

while (1)
{
	/* this is an infinite loop that does nothing */
}

Although the example above appears harmless because it does nothing in the infinite loop, it actually does a lot of things here. While this infinite loop is running, you may start to notice that your compute responds slowly. This is because your CPU is giving all the computational power it has got to run this infinite loop that does nothing, causing your CPU usage at 100%. This is generally a very, very bad practice.

What If you application requires an infinite loop? How to make it consume less CPU power? Simple!

The high CPU usage problem with infinite loop can be eliminated by adding some interrupts at the end of the loop, such as sleep() function that pauses CPU for a specified seconds. This interrupt (or any forms of sleep) is absolutely required if you have a long running loop or infinite loop. Otherwise, you will have performance issues. The following example adds a sleep to an infinite loop:

while (1)
{
	/* this is an infinite loop that does nothing */
	sleep (1);
}

Break vs Continue Clauses

break and continue are flow control statements used within loops:

  • break: It is used to terminate the loop immediately, bypassing the remaining iterations. When a break statement is encountered, the loop in which it appears is immediately exited. The following while example will exit when variable d becomes the value of 5.
int d = 0;
while(1)
{
	if (d == 5)
		break;
	d++;
	sleep(1);
}
/* program continue execution here after break */
  • continue: It is used to skip the current iteration and move to the next iteration of the loop without executing the subsequent code within the loop in the current iteration. It does not exit the loop like break does. The following for loop example will print the value of e when it is an odd number. Each iteration of even number of e is skipped by the continue clause, so it does not get printed.
int e = 0;
for (e = 0; e < 20; e++)
{
	if (e % 2 == 0)
		continue; /* This skips the even numbers of e and continues to the next iteration */
	printf("e = %d\n", e); /* Only odd number of e gets printed */
}

Practical C Loops Examples

Main Loop Example

If your C program provides a service, it most likely have a main loop that keeps looping and waiting for incoming messages to process or does some tasks periodically until it receives a signal to break out of the loop and exit. Below is a simple example how you may implement a main loop:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

volatile sig_atomic_t g_shutdown = 0;    /* global variable to control the main loop */

static void signalHandler (int sig, siginfo_t * siginf, void *ptr)
{
	switch(sig)
	{
		case SIGTERM:
		case SIGINT:
		{
			/* 
			 * SIGTERM and SIGINT signal sets g_shutdown = 1 which will
			 * cause main loop to break and exit. Without this, this program
			 * cannot exit gracefully and needs to be shutdown by force due
			 * to the "infinite" main loop below.
 			 */
			printf("SIGTERM or SIGINT signal received!\n");
			g_shutdown = 1;
			break;
		}
		case SIGHUP:
		{
			printf("SIGHUP received!\n");
			break;
		}
		default:
		{
			printf("Unknown signal received!\n");
			break;
		}
	}
}

static int installSignalHandler(void)
{
	int ret= -1;
	struct sigaction act = {0};

	act.sa_flags = SA_SIGINFO | SA_RESTART;
	act.sa_sigaction = signalHandler;
	
	ret = sigaction(SIGTERM, &act, NULL);
	if(ret < 0)
	{
		iRetval = errno;
		printf("Failed to install SIGTERM signal handler\n");
		return ret;
	}
	ret = sigaction(SIGINT, &act, NULL);
	if(ret < 0)
	{
		iRetval = errno;
		printf("Failed to install SIGINT signal handler\n");
		return ret;
	}
	ret = sigaction(SIGHUP, &act, NULL);
	if(ret < 0)
	{
		iRetval = errno;
		printf("Failed to install SIGHUP signal handler\n");
		return ret;
	}
	return 0;
}

int main (void)
{
	int ret = -1;
	/* initialize signal handler */
	ret = installSignalHandler();
	if (ret)
	{
		printf("failed to install signal handler\n");
		exit(1);
	}
	while (!g_shutdown)
	{
		/*  
		 * main loop's logic here. Comes here every 1 second
		 * we will break out of this loop when user sends SIGTERM
		 * (ctrl-c) or SIGINT signals
		 */ 
		sleep(1);
	}
	exit(0);
}

Iterate 2-Dimensional Array with For Loop

#include <stdio.h>

#define ROWS 3
#define COLS 4

int main(void) 
{
	double data[ROWS][COLS] = 
	{
		{1.0, 2.0, 3.0, 4.0},
		{5.0, 6.0, 7.0, 8.0},
		{9.0, 10.0, 11.0, 12.0}
	};
	/*
	 * iterate the 2 dimensional array with for loops and print 
	 * its contents iteratively 
	 */
	for (int i = 0; i < ROWS; i++) 
	{
		for (int j = 0; j < COLS; j++) 
		{
			printf("%.2f\t", data[i][j]);
		}
		printf("\n");
	}
	return 0;
}

Related Pages

Join the conversation

Your email address will not be published. Required fields are marked *