Traditionally, the first program a developer writes in the 'C' language is one which displays the message "Hello World" on the computer screen. This blog aims to introduce you to the tools commonly used in 'C' programming, setup the development environment and code the first program.

We discuss,

  • The development environment
  • The structure of a 'C' program
  • What's a printf() statement?
  • How to write a "Hello World" program?
  • How to compile & run a 'C' program?
  • How to deal with errors?
  • How to compile multiple 'C' and header files?
  • Makefile
  • Format specifiers
  • Console I/O statements

The development environment

Before we start our programming journey in 'C', let's get to know about the development environment we use in our course "Arduino & 'C' Programming: Learning Through Projects" and also in general. 'C' programs are written in a high-level language using letters, numbers and the other symbols that you find on a computer keyboard. In simple words, 'C' is actually written in a human readable format. But computers as you know require machine codes to perform an action. So to run the program, this 'C' code has to be converted to machine codes. This is done by the compiler. The result is an object file. Next, a program called the linker takes this object file, combines it with predefined routines from a standard library and produces an executable program. The tool flow diagram below shows the steps that must be taken to transform a program written in a high-level language into an executable program.

Source code is typically written with a software tool known as Integrated Development Environment (IDE) located on a PC. An IDE actually is a collection of mainly 3 tools. That includes a text editor which is used to write code, a compiler that translates the 'C code' into machine language or machine code and finally a linker that generates an executable binary code. Examples of such IDE include Turbo C++ compiler, Borland C++ compiler, Microsoft Visual C++ compiler, Dev C++ compiler, generic UNIX compiler (cc), the Free Software Foundation's gcc compiler and so on. Here we will be using the Free Software Foundation's gcc compiler. The gcc compiler is available with all Linux distributions. Its free and can be installed easily. Here we use Ubuntu 22.04 as our operating system. We will do all our 'C' programming in this development environment.
Open a terminal and enter the following command to install gcc in Ubuntu.

sudo apt install build-essential

This command installs the gcc compiler in the Ubuntu operating system.

There are many online IDE softwares available that can also be used for practicing 'C' programming such as www.onlinegdb.com. A simple google search should lead you to them. Even Android apps are available that has a 'C' compiler. You may install them if needed to learn and practice 'C' programming. So the options are many. Choose from any of these that suits your convenience and adapt to it accordingly.

The structure of a 'C' program

Now let's try to understand the structure of a 'C' program. Let's assume that we are going to construct a building. We need materials as well as a plan. We arrange and place the materials according to the plan to complete the building. Similar to that in a 'C' program the codes or functions or instructions represent the plan whereas the data or variables used represent the materials. The data or variables are manipulated according to the code to perform an action. So in short, 'C' programs are built from functions. These functions typically accept data as input, manipulate data and return the resulting value. For example, you could write a 'C' function that would take two numbers as input, add them together and return the sum as the result. There could be many such functions performing many such actions.

So how does the computer know where the program starts?
Which function does the computer execute first?
How many times a function is executed?
When is a function executed?
When does the program stop executing?

To answer these questions we should first learn the structure of a 'C' program.

All 'C' programs must have one function called main() which is always the first function executed.

void main(void)
{
//function statements
}

Let's look into the details of the notations used for the main() function. 

As you can see the name of the function is 'main'. It is followed by parenthesis or round brackets. 

A function could take input data for processing. These are known as input arguments. This list of input arguments are placed inside the parenthesis. If it doesn't take any arguments, the keyword 'void' is placed inside the parenthesis. The main function shown here doesn't take any arguments, so 'void' is placed here. 

The term 'main' is a keyword in 'C'. The term 'void' is also a keyword. As you progress through the lessons in 'C' you will encounter even more keywords. Keywords are reserved words in 'C'. They have a specific and fixed meaning. They are specifically used by the compiler during the translation process. So when we write a program in 'C', avoid using key words for any purpose other than the specified one.

The above code snippet shows the definition for the main() function. 

The first 'void' prior to the name of the function i.e., 'main', indicates to the compiler that this main() function does not return any value at all. 

This first line with the function name, the return value and input arguments is known as the function header.

Statements form the body of a function. They fall between the two curly braces, {..}. Here they have been omitted for example purposes. Curly braces surround the statements that form the body of a function. Even functions with no statements in their body require the braces. Braces indicate to the compiler that you are providing the definition of a function.

The main() function can execute code from other functions also. This is referred to as calling or invoking another function. An example is shown here.

void main(void)
{
add();
subtract();
}

So this is how you build a 'C' program. There is more to what we have discussed until now.
But that's for another session. For the time being to get started this is more than enough. We welcome you to join our course "Arduino & 'C' Programming: Learning Through Projects" to learn more.

What's a printf() statement?

The computer has input devices as well as output devices. Monitor is an output device. printf() is an inbuilt library function in 'C' programming language. It is used to display text on the screen. It is one of the main output functions. There are several other types of output functions also. Similarly there are input functions such as scanf() to read from input devices also. These are discussed in detail in our course "Arduino & 'C' Programming: Learning Through Projects". In this blog we will be using the printf() statement to write our first program to display "Hello World!!" on the screen.

How to write a "Hello World" program?

Traditionally, the first program a developer writes in the 'C' language is one which displays the message "Hello World!!" on the computer screen. So let's get on with it.
Let's create a folder for our first program.

Now let's create a text file and name it 'helloworld.c'. The extension '.c' indicates it is a 'C' program. If you are using a different development environment, the procedures to create a 'C' source code file will be different.

Next we open the 'C' file and start writing our first program. A sample program to print the string "Hello World!!" is shown here.

#include <stdio.h>
int main(void)
{
  printf(“Hello World!!\n”);
  return 0;
}

Just like we discussed earlier, we have a main function here that doesn't take any arguments. 

The printf() function prints a text string input onto the screen. The string should be put inside double quotes. Here we put the string "Hello World!!\n" inside the quotations.

The '\n' at the end is known as an escape sequence. Its also known as newline character. Using '\n' takes the cursor to the beginning of the next line, just like pressing the 'Enter' key.

The main function here returns an integer value. Here we return zero. We use the keyword return for that. The return value of a function can be used to indicate the status of the function executed like whether it was successful or whether it met with an error and so on.

Also you can see here, a statement  #include <stdio.h> is written at the beginning. Its called header file. We are invoking printf() in main function body to display a text string. When the compiler tries to translate this printf() statement, it needs the details of this function prior to beginning the translation process. These details of the printf() function are present in the stdio.h file. These are system header files. To use printf() in our program we have to include stdio.h header at the beginning itself. Similarly if we use any other library functions, the relevant header files of those functions have to be included in the program.
The angled brackets indicate they are system header files and that they are located in a directory specific to the compiler installation. The compiler checks for this header file in that location. So now we have the program ready. Let's compile and run it.

How to compile & run a 'C' program?

We will be using the gcc compiler for compilation. We open a terminal from the current directory and enter the following command.

gcc helloworld.c -o helloworld

gcc is the compiler program that does the translation. This program takes in the 'C' source file as input file. Here the source file is helloworld.c. The hyphenated option 'o' indicates the name of the output file. Here the name of the output file is given as helloworld. So what this statement does is  it takes in the 'C' source file 'helloworld.c' as input, compiles it and
generates an executable output file 'helloworld'. 

Press 'Enter' key to compile and generate the output file.

The compilation is successful with no errors. The output file has been generated.

Now let's run it. To execute this file we have to provide it permissions. For that we enter the following command.

chmod 777 helloworld

Now to run the program we enter the following command.

./helloworld

You can see that the text "Hello World!!" is displayed on the terminal screen. This is how you basically compile and run a 'C' program.

How to deal with errors?

The languages that we speak such as Hindi, Tamil, English and so on, all of them have alphabets, words, sentences, certain grammar and rules that are to be followed for effective communication. Similarly computer programming languages follow certain rules. So does 'C'. The compiler translates the 'C' code to machine language. It does this based on certain rules and guidelines. When the program that we have written fails to comply with these rules, the translation fails. The compiler detects it and displays them on the screen. Let's see a few of them.

In 'C', at the end of every statement, the compiler expects a semicolon. Let's remove the semicolon at the end of the printf() statement. On compiling it, the compiler displays an error. It says it expects semicolon at the end of the statement at a specific line number. Your code editor software should show the line numbers at the left end of the screen. If it doesn't, edit the settings to display them. This is an important step while doing programming.

If you put the semicolon back and compile again, the error will be gone.

Now let's try another run. Remove the closing bracket of the printf() statement. On compiling it the compiler displays an error. It has detected the missing bracket at a specific line number.

If you put the bracket back and compile again, the error will be gone. So this is how errors are displayed by the compiler. The compiler is fed with certain rules. Based on that it detects the error and displays them at certain line number. But sometimes the compiler might show the line number differently. This might be because the error could be actually at a different place where the compiler failed to detect it. Whatever that might be, it is the responsibility of the programmer to write the program according to the rules. If you fail to do that, the compiler cannot proceed with the translation. Using the description and the line number of the error displayed on the screen, the programmer should locate and remove all errors one by one. 

These errors that we discussed until now are known as syntax errors. Syntax error is same as grammatical error or non compliance with the rules. There is another category of error known as logical error. This error is related to the algorithm of the program. The program fails to do the required action. The compiler will not detect these errors. Here the code will be perfectly in compliance with the syntax. So the compiler shows no errors. But there could be issues in the logic of the program created by the programmer.. The programmer has the responsibility here to correct the logic of the  program.

How to compile multiple 'C' and header files?

Let's create one more file. Name it "display.c".

Open the file and write a function as shown here.

void displayfunc(void)
{
  printf(“Iam Display Function\n”);
}

The function has a printf() statement. It displays the line "Iam Display Function". The function takes no argument. So its void in the parenthesis. Also the function returns nothing. So its void here also. Now let's edit the main function, and call the display function in its body.

#include <stdio.h>
int main(void)
{
  printf(“Hello World\n”);
  displayfunc();
  return 0;
}

On running this code, we expect the "Hello World" text to get displayed first. Then we expect "Iam Display Function" to get displayed. So now we have two 'C' files. The program is incomplete at this point. We shall proceed with the compilation. We will encounter errors. While correcting it we shall see a few more new concepts. All these details are very important, and will definitely help you understand the general procedures adopted when creating a project. If you are using an IDE, most of these steps will be automated for you.
So you may not learn or understand how things work in the background. Here we are going to do all these steps by ourselves. That will help you solidify the concepts..So let's proceed.

To compile multiple 'C' files, open a terminal from the current directory, and enter the following command.

gcc helloworld.c display.c -o helloworld

So you can see that the gcc program has to be fed with all the 'C' files in the project as input. gcc will compile them and generate an output file helloworld. You can give any name for the output as you wish. Press 'Enter' key.

As expected there are many errors or warnings. In certain systems, this may show only as warnings and may even run. But its recommended to remove all the warnings and errors.
So let's check them one by one.

The first warning states implicit declaration of function ‘printf()' in display.c file. We are using printf() statement there. So compiler requires the header file stdio.h for translating the printf() statement in display.c file. So we include stdio.h in display.c and compile it again.

Now there is only one warning. It states implicit declaration of function ‘displayfunc' in main() function. As we learnt earlier, the compiler needs to know in advance the details of the functions being used in a file. So we have to include the function header at the start of the file. So let's add the function header of ‘displayfunc' to the start of the main() function.
Since this function resides in another file let's put the keyword extern in front of the function header. extern means external. Compile it again.

The errors are gone. Now run the binary helloworld.

As expected both the statements have been displayed on the terminal screen. 

In a project there might be several such 'C' source files, and they could get invoked anywhere in the program. Here the 'displayfunc' was invoked in main(). In a different project it could be another function getting invoked once or multiple times in a different file, in a different function. All this depends on the project. There could be hundreds of such functions and hundreds of such files. So its hard to keep track of all these. So normally developers use project specific header files for each 'C' file.

So here we could add display.h header file. We  put the function header in it.

In the helloworld.c file, we include the display.h header file instead of adding the function headers one by one. Notice that when we include a project specific header file we do not use angled brackets, instead we use double quotes.

The header file doesn't need to be fed as input to the gcc command. gcc requires only the 'C' source file. Compile it again.

It works as expected.

In a complex project there will be hundreds of such source files. To make things easier we could use wildcard patterns to compile the source code. Enter the compilation command as follows.

gcc *.c -o helloworld

'*.c' is the wild card pattern used to include all the 'C' files. This saves time. We don't have to type in each 'C' source file. Press 'Enter' and run 'helloworld'.

It works as expected.

Makefile

We shall close the discussion with one more topic in handling multiple source and header files i.e, by using Makefile. Makefile is a special type of file where you could enter several instructions on how to compile a source code. A complex project will have several directories of source code that includes source files, header files, libraries and several such entities. It will be very hard to manage them if we are going to compile them by typing on the terminal screen. They can be automated using the Makefile. All IDE use multiple Makefile to manage a complex project. A detailed discussion of Makefile is out of our scope. But we show you how a simple Makefile is done to automate the process.

First create a text file and name it Makefile. Open the file and add the compilation command we had used. The instructions added in a Makefile should be under a label.The label to be used by default is 'all'. Add the 'all' label and put the gcc instruction under it. Provide indentation using the tab key.

Now let's add one more label. We add the label clean. Under the label add instruction to remove any existing previously generated binary. Here we add instruction to remove 'helloworld'.

rm -f helloworld

In a complex project there could be several such binaries. So to create a fresh build, we have to remove previously generated binaries. Enter the command 'make clean'. Check if the files have been deleted. In the terminal enter the command 'make' and press Enter key. Run 'helloworld' binary and check.

All throughout the discussion up until now, we have been using the word compilation. Compilation is translating 'C' code to machine code. After compilation the linker generates the executable binary by linking all the object files and any system library required. In our study up until now, we have combined both processes to make it simple.
When we run the gcc command both these processes are run. However in a real industrial project, it may not be like this. First we shall see how to split the process. Then we shall see why it has to be separate in an industrial project. First run make clean to remove the previous binary.

In the Makefile edit the gcc command as follows.

gcc -c *.c

This instruction takes in all the 'C' source files and generate the corresponding object files. The option used here is '-c'. Run make and check if the object files have been generated with extension '.o' . This process of generating the object files is known as compilation.

Now add the following command in Makefile.

gcc -o helloworld *.o

This instruction combines all the object files along with system libraries to generate the final executable binary 'helloworld'. Note we have used wildcard pattern '*.o' for object files. Now run make . Check if the file has been generated. This process is known as linking.

Now add the following command in Makefile under the clean label to remove the object files also.

rm -f *.o

So this is how we split the process. Now let's understand why it should be separate. Our project is a simple one. It has a maximum of 2 source files. And they both are linked to generate a single binary. So the advantage or the reason to split this process might not be as evident as in a real project. In a real project, there could be several source files. The object files generated from these might be used to create multiple binaries. Also all the object files may not be used. So there needs to be flexibility in automating all these internal steps. The object files could be put in a separate directories and several such steps might be done to modularize and organize the code. So its quite reasonable to have independent control on all object files. 

Makefile provides many more methods to add automation to the build process. A complete discussion is not possible here. But whatever we discussed here is enough to get started.

Format specifiers

We learnt about the use of printf() statements. We used it to display text on the screen. The text was a fixed data string. In an actual program the data to be displayed on the screen might vary dynamically. So there will be a need to display different types of data like integers, floating point numbers, characters, text data etc on screen as and when they arise. printf() requires format specifiers to be used for displaying such variety of data. Format specifiers define the type of data to be printed on standard output. A sample program is shown here.

int main(void)
{
  printf(“Hello World %d %c %f %s\n”,10,’A’,3.8,”Format Specifier”);
  return 0;
}

As you can see here,

%c format specifier is used to display a single character
%s format specifier is used to display string data
%d format specifier is used to display integer
%f format specifier is used to display floating point number

The data to be displayed is given as inputs to the printf() function in the order they need to be displayed as comma separated values. The corresponding format specifiers are specified inside the quotations in the same order.

Let's remove the \n at the end of the first printf() statements and see what happens. You can see that the output of printf() statements are on the same line on the console until it reaches a \n character.. It is for this reason you have to use an escape sequence such as \n. The \n stands for next line or new line. We have to put this at the end of the string in the printf() statement. What it does is, the printf() statement prints the string first and then prints the escape sequences. The \n escape sequence is equivalent of pressing the enter key. So now the cursor will be in the second line and the second printf() statement will be printed there. Run the program and see the output.

Similarly there are other escape sequences such as \t which is the equivalent of pressing the tab key. If you need to print  ' or \ or " using the printf() statement, you need to use another escape sequence. You have to put a backslash in front of these characters. Let's try with an example.

int main(void)

{
  printf("SlNo:1\\10\t\"I\'am testing format specifiers\"\n");
}

Practice more examples to get hold of these concepts.

Console Input/Output statements

The screen and keyboard together are called a console. We have already seen the printf() function that displays data onto the screen. Similarly there is a function scanf() that helps us to read data from the keyboard. These 2 functions printf() and scanf() are called formatted console I/O functions because format specifiers can be used to format the data according to our requirements.
So let's check the usage of scanf() function. The usage of scanf() is similar to printf(). The difference is that we have to pass the address of the variables as comma separated list. Another point to be noted is that when scanf() is called, the program waits until the data is entered. i.e, until the Enter key is pressed. Let's receive a few data from the keyboard.

int main(void)
{
  int rollno, char name[20], float percentile;
  printf("Enter rollno:");
  scanf("%d",&rollno);
  printf("\n");
  printf("Enter name:");
  scanf("%s",name);
  printf("\n");
  printf("Enter percentile:");
  scanf("%f",&percentile);
  printf("\n");
  printf("Roll No:%d Name:%s Percentile:%f\n",rollno,name,percentile);
  return 0;
}

Conclusion

That brings us to the end of this session. We learnt about how to setup the development environment for 'C' programming in Ubuntu 22.04 operating system. We then discussed about the structure of a 'C' program and learnt what's a printf() statement & coded our first hello world program. After that we had a brief walk through on how to compile and run the 'C' code. We also discussed how to deal with errors & learnt how to compile multiple 'C' & header files. We then learnt how to employ a Makefile for automating a 'C' project . We discussed format specifiers and escape sequences used in printf() statement next and finally learnt how to use scanf() statements.

The discussions we had is by no means a complete one. For a detailed and complete study please refer standard literature available on the subject. Practice 'C' programming exercises to improve upon your practical skills in 'C' programming. We welcome you to join our course "Arduino & 'C' Programming: Learning Through Projects"  for a solid introduction to the quintessential concepts of 'C' programming. The takeaway should be an understanding regarding the general structure of a 'C' program. how a project is created and how its compiled and executed. The practical examples and functions that you practiced here should help you get started with 'C' programming.

Thank you

codecircuitry
Our vision is to create a platform where anyone could upskill as well as build their knowledge on hardware & firmware development through industry relevant courses in electronics, programming & mathematics at affordable prices. Driven by our passion for technology, we aim to bring in innovative hardware products and software applications at affordable prices. We also offer firmware development and guidance services in Beaglebone, Nvidia Jetson, Raspberry Pi and Arduino.

Launch your GraphyLaunch your Graphy
100K+ creators trust Graphy to teach online
CODECIRCUITRY 2024 Privacy policy Terms of use Contact us Refund policy