Essential C Programming Guide
Essential C Programming Guide
C programming language is a MUST for students and working professionals to become a great
Software Engineer especially when they are working in Software Development Domain. Here
are some of the important reasons why you should learn C Programming −
It is a structured programming language and you can use the skills learned in C to master
other programming languages.
You can use C program to write efficient codes and develop robust projects.
C is a low-level language and you can use it to interact more directly with the computer's
hardware and memory.
Facts about C
C is the most widely used and popular System Programming Language. Most of the state-of-the-
art software have been implemented using C. Here are some facts about the C language:
C was invented to write an operating system called UNIX. The UNIX OS was totally
written in C.
C is a successor of B language which was introduced around the early 1970s.
The language was formalized in 1988 by the American National Standard Institute (ANSI).
Just to give you a little excitement about C programming, I'm going to give you a small
conventional C Programming Hello World program. You can run it here using the "Edit and
Run" button.
#include <stdio.h>
int main() {
/* my first program in C */
printf("Hello, World! \n");
return 0;
}
C was initially used for system development work, particularly the programs that make-up the
operating system. C was adopted as a system development language because it produces code
that runs nearly as fast as the code written in assembly language. Some examples of the use of C
are -
Operating Systems
Language Compilers
Assemblers
Text Editors
Print Spoolers
Network Drivers
Modern Programs
Databases
Language Interpreters
Utilities
Introduction
In 1978, Brian Kernighan and Dennis Ritchie produced the first publicly available description of
C, now known as the K&R standard.
The UNIX operating system, the C compiler, and essentially all UNIX application programs
have been written in C. C has now become a widely used professional language for various
reasons −
Easy to learn
Structured language
It produces efficient programs
It can handle low−level activities
It can be compiled on a variety of computer platforms
Facts about C
C was initially used for system development work, particularly the programs that make-up the
operating system. C was adopted as a system development language because it produces code
that runs nearly as fast as the code written in assembly language.
Operating Systems
Language Compilers
Assemblers
Text Editors
Print Spoolers
Network Drivers
Modern Programs
Databases
Language Interpreters
Utilities
C covers all the basic concepts of programming. It's a base or mother programming language to
learn object−oriented programming like C++, Java, .Net, etc. Many modern programming
languages such as C++, Java, and Python have borrowed syntax and concepts from C.
Advantages of C Language
Efficiency and speed − C is known for being high−performing and efficient. It can let you
work with memory at a low level, as well as allow direct access to hardware, making it
ideal for applications requiring speed and economical resource use.
Portable − C programs can be compiled and executed on different platforms with minimal
or no modifications. This portability is due to the fact that the language has been
standardized and compilers are available for use on various operating systems globally.
Close to Hardware − C allows direct manipulation of hardware through the use
of pointers and low−level operations. This makes it suitable for system programming and
developing applications that require fine-grained control over hardware resources.
Standard Libraries − For common tasks such as input/output
operations, string manipulation, and mathematical computations, C comes with a large
standard library which helps developers write code more efficiently by leveraging
pre−built functions.
Structured Programming − C helps to organize code into modular and
easy−to−understand structures. With functions, loops, and conditionals, developers can
produce clear code that is easy to maintain.
Procedural Language − C follows a procedural paradigm that is often simpler and more
straightforward for some types of programming tasks.
Versatility − C language is a versatile programming language and it can be used for
various types of software such as system applications, compilers, firmware, application
software, etc.
Drawbacks of C Language
Applications of C Language
System Programming − C language is used to develop system software which are close
to hardware such as operating systems, firmware, language translators, etc.
Embedded Systems − C language is used in embedded system programming for a wide
range of devices such as microcontrollers, industrial controllers, etc.
Compiler and Interpreters − C language is very common to develop language compilers
and interpreters.
Database Systems − Since C language is efficient and fast for low-level memory
manipulation. It is used for developing DBMS and RDBMS engines.
Networking Software − C language is used to develop networking software such as
protocols, routers, and network utilities.
Game Development − C language is widely used for developing games, gaming
applications, and game engines.
Scientific and Mathematical Applications − C language is efficient in developing
applications where scientific computing is required. Applications such as simulations,
numerical analysis, and other scientific computations are usually developed in C language.
Text Editor and IDEs − C language is used for developing text editors and integrated
development environments such as Vim and Emacs.
To learn C effectively, we need to understand its structure first. Every programming language
has its programming structure. A typical structure of a C program includes several parts. The
following steps show the C structure of a regular C program−
Include necessary header files that contain declarations of functions, constants, and macros that
can be used in one or more source code files. Some popular header files are as −
stdio.h − Provides input and output functions like printf and scanf.
#include <stdio.h>
stdlib.h − Contains functions involving memory allocation, rand function, and other utility
functions.
#include <stdlib.h>
#include <math.h>
string.h − Includes functions for manipulating strings, such as strcpy, strlen, etc.
#include <string.h>
ctype.h − Functions for testing and mapping characters, like isalpha, isdigit, etc.
#include <ctype.h>
stdbool.h − Defines the boolean data type and values true and false.
#include <stdbool.h>
#include <time.h>
#include <limits.h>
Define any macros or constants that will be used throughout the program. Macros and constants
are optional.
Example
#include <stdio.h>
#define PI 3.14159
int main() {
float radius = 5.0;
float area = PI * radius * radius;
Output
Global Declarations in C
int globalVariable;
void sampleFunction();
Declare global variables and functions that will be used across different parts of the program.
Take a look at the following example −
#include <stdio.h>
int main()
{
// Rest of the program
return 0;
}
Main Function
Every C program must have a main function. It is the entry point of the program. Take a look at
the following example −
int main() {
float radius = 5.0;
float area = PI * radius * radius;
Functions in C
Define other functions as needed. The main function may call these functions. Take a look at the
following example:
#include <stdio.h>
int main() {
// Programming statements
return 0;
}
// Global function definition
void samplefunction () {
// Function programming statements implementation
}
A C program can vary from 3 lines to millions of lines and it should be written into one or more
text files with extension ".c"; for example, hello.c. You can use "vi", "vim" or any other text
editor to write your C program into a file.
This tutorial assumes that you know how to edit a text file and how to write source code inside a
program file.
Dennis Ritchie and Ken Thompson developed the C programming language in 1972, primarily to
re-implement the Unix kernel. Because of its features such as low-level memory access,
portability and cross-platform nature etc., C is still extremely popular. Most of the features of C
have found their way in many other programming languages.
The development of C has proven to be a landmark step in the history of computing. Even
though different programming languages and technologies dominate today in different
application areas such as web development, mobile apps, device drivers and utilities, embedded
systems, etc., the underlying technologies of all of them are inspired by the features of C
language.
The utility of any technology depends on its important features. The features also determine its
area of application. In this chapter, we shall take an overview of some of the significant features
of C language.
In C, the logic of a process can be expressed in a structured or modular form with the use
of function calls. C is generally used as an introductory language to introduce programming to
school students because of this feature.
C is a General-Purpose Language
The C language hasn’t been developed with a specific area of application as a target. From
system programming to photo editing software, the C programming language is used in various
applications.
Some of the common applications of C programming include the development of Operating
Systems, databases, device drivers, etc.
C is a compiler-based language which makes the compilation and execution of codes faster. The
source code is translated into a hardware-specific machine code, which is easier for the CPU to
execute, without any virtual machine, as some of the other languages like Java need.
The fact that C is a statically typed language also makes it faster compared to dynamically typed
languages. Being a compiler-based language, it is faster as compared to interpreter-based
languages.
C is Portable
Another feature of the C language is its portability. C programs are machine-independent which
means that you can compile and run the same code on various machines with none or some
machine-specific changes.
C programming provides the functionality of using a single code on multiple systems depending
on the requirement.
C is Extensible
C is an extensible language. It means if a code is already written, you can add new features to it
with a few alterations. Basically, it allows adding new features, functionalities, and operations to
an existing C program.
Standard Libraries in C
Most of the C compilers are bundled with an extensive set of libraries with several built-in
functions. It includes OS-specific utilities, string manipulation, mathematical functions, etc.
Importantly, you can also create your user-defined functions and add them to the existing C
libraries. The availability of such a vast scope of functions and operations allows a programmer
to build a vast array of programs and applications using the C language.
Pointers in C
One of the unique features of C is its ability to manipulate the internal memory of the computer.
With the use of pointers in C, you can directly interact with the memory.
Pointers point to a specific location in the memory and interact directly with it. Using the C
pointers, you can interact with external hardware devices, interrupts, etc.
C is a Mid-Level Programming Language
High-level languages have features such as the use of mnemonic keywords, user-defined
identifiers, modularity etc. C programming language, on the other hand, provides a low-level
access to the memory. This makes it a mid-level language.
As a mid-level programming language, it provides the best of both worlds. For instance, C
allows direct manipulation of hardware, which high-level programming languages do not offer.
C is perhaps the language with the most number of built-in operators which are used in writing
complex or simplified C programs. In addition to the traditional arithmetic and comparison
operators, its binary and pointer related operators are important when bit-level manipulations are
required.
Recursion in C
C language provides the feature of recursion. Recursion means that you can create a function that
can call itself multiple times until a given condition is true, just like the loops.
C has three basic data types in int, float and char. However, C programming has the provision to
define a data type of any combination of these three types, which makes it very powerful.
In C, you can define structures and union types. You also have the feature of
declaring enumerated data types.
Preprocessor Directives in C
In C, we have preprocessor directives such as #include, #define, etc. They are not the language
keywords. Preprocessor directives in C carry out some of the important roles such as importing
functions from a library, defining and expanding the macros, etc.
File Handling in C
C language doesn’t directly manipulate files or streams. Handling file IO is not a part of the C
language itself but instead is handled by libraries and their associated header files.
File handling is generally implemented through high-level I/O which works through streams. C
identifies stdin, stdout and stderr as standard input, output and error streams. These streams can
be directed to a disk file to perform read/write operations.
These are some of the important features of C language that make it one of the widely used and
popular computer languages.
C - Environment Setup
To start learning programming in C, the first step is to setup an environment that allows you to
enter and edit the program in C, and a compiler that builds an executable that can run on your
operating system. You need two software tools available on your computer, (a) The C Compiler
and (b) Text Editor.
The C Compiler
The source code written in the source file is the human readable source for your program. It
needs to be "compiled", into machine language so that your CPU can actually execute the
program as per the instructions given.
There are many C compilers available. Following is a select list of C compilers that are widely
used −
Clang: Clang is an open-source C compiler that is part of the LLVM project. It is available for a
variety of platforms including Windows, macOS, and Linux. Clang is known for its speed and
optimization capabilities.
Microsoft Visual C++ − Microsoft Visual C++ is a proprietary C compiler that is developed by
Microsoft. It is available for Windows only. Visual C++ is known for its integration with the
Microsoft Visual Studio development environment.
Turbo C − Turbo C is a discontinued C compiler that was developed by Borland. It was popular
in the early 1990s, but it is no longer widely used.
The examples in this tutorial are compiled on the GCC compiler. The most frequently used and
free available compiler is the GNU C/C++ compiler. The following section explains how to
install GNU C/C++ compiler on various operating systems. We keep mentioning C/C++ together
because GNU gcc compiler works for both C and C++ programming languages.
Installation on UNIX/Linux
If you are using Linux or UNIX, then check whether GCC is installed on your system by
entering the following command from the command line −
$ gcc -v
If you have GNU compiler installed on your Ubuntu Linux machine, then it should print a
message as follows −
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v . . .
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
If GCC is not installed, then you will have to install it yourself using the detailed instructions
available at [Link]
Installation on Mac OS
If you use Mac OS X, the easiest way to obtain GCC is to download the Xcode development
environment from Apple's web site and follow the simple installation instructions. Once you
have Xcode setup, you will be able to use GNU compiler for C/C++.
Installation on Windows
To install GCC on Windows, you need to install MinGW. To install MinGW, go to the MinGW
downloads page, [Link] and follow the link to the MinGW
download page. Download the latest version of the MinGW installation program, mingw-w64-
[Link] from here.
While installing Min GW, at a minimum, you must install gcc-core, gcc-g++, binutils, and the
MinGW runtime, but you may wish to install more.
Add the bin subdirectory of your MinGW installation to your PATH environment variable, so
that you can specify these tools on the command line by their simple names.
After the installation is complete, you will be able to run gcc, g++, ar, ranlib, dlltool, and several
other GNU tools from the Windows command line.
Text Editor
You will need a Text Editor to type your program. Examples include Windows Notepad, OS Edit
command, Brief, Epsilon, EMACS, and vim or vi.
The name and version of the text editors can vary on different operating systems. For example,
Notepad will be used on Windows, and vim or vi can be used on windows as well as on Linux or
UNIX.
The files you create with your editor are called the source files and they contain the program
source codes. The source files for C programs are typically named with the extension ".c".
Before starting your programming, make sure you have one text editor in place and you have
enough experience to write a computer program, save it in a file, compile it and finally execute
it.
Using an IDE
Using a general-purpose text editor such as Notepad or vi for program development can be very
tedious. You need to enter and save the program with ".c" extension (say "hello.c"), and then
compile it with the following command −
The executable file is then run from the command prompt to obtain the output. However, if the
source code contains errors, the compilation will not be successful. Hence we need to repeatedly
switch between the editor program and command terminal. To avoid this tedious process, we
should an IDE (Integrated Development Environment).
There are many IDEs available for writing, editing, debugging and executing C programs.
Examples are CodeBlocks, NetBeans, VSCode, etc.
CodeBlocks is a popular open-source IDE for C and C++. It is available for installation on
various operating system platforms like Windows, Linux, MacOS.
For Windows, download [Link]
from [Link] URL. This will install CodeBlocks as
well as MinGW compiler on your computer. During the installation process, choose MinGW as
the compiler to use.
Example
After the installation is complete, launch it and enter the following code −
#include <stdio.h>
int main() {
/* my first program in C */
printf("Hello, World! \n");
return 0;
}
Output
From the Build menu, build and run the program (use F9 shortcut). The Build Log window
shows successful compilation messages. The output (Hello World) is displayed in a separate
command prompt terminal.
C - Program Structure
A typical program in C language has certain mandatory sections and a few optional sections,
depending on the program's logic, complexity, and readability. Normally a C program starts with
one or more preprocessor directives (#include statements) and must have a main() function that
serves as the entry point of the program. In addition, there may be global declarations
of variables and functions, macros, other user-defined functions, etc.
The C compiler comes with several library files, having ".h" as an extension. A ".h" file (called a
"header file") consists of one or more predefined functions (also called "library functions") to be
used in the C program.
The library functions must be loaded in any C program. The "#include" statement is used to
include a header file. It is a "preprocessor directive".
For example, printf() and scanf() functions are needed to perform console I/O operations. They
are defined in the stdio.h file. Hence, you invariably find #include <stdio.h> statement at the top
of any C program. Other important and frequently used header files
include string.h, math.h, stdlib.h, etc.
There are other preprocessor directives such as #define which is used to define constants and
macros and #ifdef for conditional definitions.
#define PI 3.14159
Example
#include <stdio.h>
#define PI 3.14159
int main(){
int radius = 5;
float area = PI*radius*radius;
printf("Area: %f", area);
return 0;
}
Output
Area: 78.539749
You can also define a macro with the "#define" directive. It is similar to a function in C. We can
pass one or more arguments to the macro name and perform the actions in the code segment.
The following code defines AREA macro using the #define statement −
Example
#include <stdio.h>
#define PI 3.14159
#define AREA(r) (PI*r*r)
int main(){
int radius = 5;
float area = AREA(radius);
printf("Area: %f", area);
return 0;
}
Output
Area: 78.539749
A C program is a collection of one or more functions. There are two types of functions in a C
program: library functions and user-defined functions.
There must be at least one user-defined function in a C program, whose name must be main().
The main() function serves as the entry point of the program. When the program is run, the
compiler looks for the main() function.
The main() function contains one or more statements. By default, each statement must end with a
semicolon. The statement may include variable declarations, decision control or loop constructs
or call to a library or another user-defined function.
In C, a function must have a data type. The data type of return value must match with the data
type of the function. By default, a function in C is of int type. Hence, if a function doesn’t have
a return statement, its type is int, and you may omit it in the function definition, but the
compiler issues a warning −
Example
#include <stdio.h>
int main() {
/* my first program in C */
printf("Hello, World! \n");
return 0;
}
Output
Hello, World!
This section consists of declaration of variables to be used across all the functions in a program.
Forward declarations of user-defined functions defined later in the program as well as user-
defined data types are also present in the global section.
int total = 0;
float average = 0.0;
Subroutines in a C Program
There may be more than one user-defined functions in a C program. Programming best practices
require that the programming logic be broken down to independent and reusable functions in a
structured manner.
Depending on the requirements, a C program may have one or more user-defined functions,
which may be called from the main() function or any other user-defined function as well.
Comments in a C Program
Apart from the programming elements of a C program such as variables, structures, loops,
functions, etc., the code may have a certain text inside "/* .. */" recognized as comments. Such
comments are ignored by the compiler.
Inserting comments in the code often proves to be helpful in documenting the program, and in
understanding as well as debugging the programming logic and errors.
If the /* symbol doesn’t have a matching */ symbol, the compiler reports an error: "Unterminated
comment".
A text between /* and */ is called as C-style comment, and is used to insert multi-line comments.
/*
Program to display Hello World
Author: Tutorialspoint
Built with codeBlocks
*/
A single line comment starts with a double forward-slash (//) and ends with a new line. It may
appear after a valid C statement also.
However, a valid statement can’t be given in a line that starts with "//". Hence, the following
statement is erroneous:
/*Headers*/
#include <stdio.h>
#include <math.h>
/*forward declaration*/
float area_of_square(float);
/*main function*/
int main() {
/* my first program in C */
float side = 5.50;
float area = area_of_square(side);
printf ("Side=%5.2f Area=%5.2f", side, area);
return 0;
}
/*subroutine*/
float area_of_square(float side){
float area = pow(side,2);
return area;
}
Output
C - Hello World
Every learner aspiring to become a professional software developer starts with writing a Hello
World program in the programming language he/she is learning. In this chapter, we shall learn
how to write a Hello World program in C language.
Before writing the Hello World program, make sure that you have the C programming
environment set up in your computer. This includes the GCC compiler, a text editor, and
preferably an IDE for C programming such as CodeBlocks.
Example
The first step is to write the source code for the Hello World program. Open a text editor on your
computer. On Windows, open Notepad or Notepad++, enter the following code and save it as
"hello.c".
#include <stdio.h>
int main(){
/* my first program in C */
printf("Hello World! \n");
return 0;
}
Output
Hello World!
Step 1
The first statement in the above code is the #include statement that imports the stdio.h file in the
current C program. This is called a preprocessor directive. This header file contains the
definitions of several library functions used for stand IO operations. Since we shall be calling the
printf() function which is defined in the stdio.h library, we need to include it in the first step.
Step 2
Every C program must contain a main() function. The main() function in this program prints the
"Hello World" message on the console terminal.
Inside the main() function, we have inserted a comment statement that is ultimately ignored by
the compiler; it is for the documentation purpose.
The next statement calls the printf() function. In C, every statement must terminate with a
semicolon symbol (;), failing which the compiler reports an error.
The printf() function, imported from the stdio.h library file, echoes the Hello World string to the
standard output stream. In case of Windows, the standard output stream is the Command prompt
terminal and in case of Linux it is the Linux terminal.
In C, every function needs to have a return value. If the function doesn’t return anything, its
value is void. In the example above, the main() function has int as its return value. Since the
main() function doesn’t need to return anything, it is defined to return an integer "0". The "return
0" statement also indicates that the program has been successfully compiled and run.
Step 3
Next, we need to compile and build the executable from the source code ("hello.c").
If you are using Windows, open the command prompt in the folder in which "hello.c" has been
saved. The following command compiles the source code −
The -c option specifies the source code file to be compiled. This will result in an object file with
the name hello.o if the C program doesn’t have any errors. If it contains errors, they will be
displayed. For example, if we forget to put the semicolon at the end of the printf() statement, the
compilation result will show the following error −
To build an executable from the compiled object file, use the following command −
The [Link] is now ready to be run from the command prompt that displays the Hello World
message in the terminal.
C:\Users\user>hello
Hello World!
On Ubuntu Linux, the object file is first given executable permission before running it by
prefixing "./" to it.
$ chmod a+x a.o
$ ./a.o
You can also use an IDE such as CodeBlocks to enter the code, edit, debug and run the Hello
World program more conveniently.
CodeBlocks is one the most popular IDEs for C/C++ development. Install it if you have not
already done and open it. Create a new file from the File menu, enter the following code and
save it as "hello.c".
Example
#include <stdio.h>
int main(){
/* my first program in C */
return 0;
}
Output
Hello World!
Choose Build and Run option from the Build menu as shown below −
You can also use the F9 shortcut for the same. If the program is error-free, the Build Log tab
shows the following messages −
Hello World!
If the code contains errors, the build log tab echoes them. For instance, if we miss the trailing
semicolon in the printf() statement, the log will be as below −
You can use any other IDE to run the C program. You will need to follow the documentation of
the respective IDE for the purpose.
Running the Hello World successfully also confirms that the C programming environment is
working properly on your computer.
Compilation Process in C
Compiling a C Program
A sequence of binary instructions consisting of 1 and 0 bits is called as machine code. High-
level programming languages such as C, C++, Java, etc. consist of keywords that are closer to
human languages such as English. Hence, a program written in C (or any other high-level
language) needs to be converted to its equivalent machine code. This process is
called compilation.
Note that the machine code is specific to the hardware architecture and the operating system. In
other words, the machine code of a certain C program compiled on a computer with Windows
OS will not be compatible with another computer using Linux OS. Hence, we must use the
compiler suitable for the target OS.
C Compilation Process Steps
In this tutorial, we will be using the gcc (which stands for GNU Compiler Collection). The GNU
project is a free-software project by Richard Stallman that allows developers to have access to
powerful tools for free.
The gcc compiler supports various programming languages, including C. In order to use it, we
should install its version compatible with the target computer.
Preprocessing
Compiling
Assembling
Linking
To understand this process, let us consider the following source code in C languge (main.c) −
#include <stdio.h>
int main(){
/* my first program in C */
return 0;
}
Output
Hello World!
The ".c" is a file extension that usually means the file is written in C. The first line is the
preprocessor directive #include that tells the compiler to include the stdio.h header file. The text
inside /* and */ are comments and these are useful for documentation purpose.
The entry point of the program is the main() function. It means the program will start by
executing the statements that are inside this function’s block. Here, in the given program code,
there are only two statements: one that will print the sentence "Hello World" on the terminal, and
another statement that tells the program to "return 0" if it exited or ended correctly. So, once we
compiled it, if we run this program we will only see the phrase "Hello World" appearing.
In order for our "main.c" code to be executable, we need to enter the command "gcc main.c", and
the compiling process will go through all of the four steps it contains.
Step 1: Preprocessing
The output of this step will be stored in a file with a ".i" extension, so here it will be in "main.i".
In order to stop the compilation right after this step, we can use the option "-E" with the gcc
command on the source file, and press Enter.
gcc -E main.c
Step 2: Compiling
The compiler generates the IR code (Intermediate Representation) from the preprocessed file, so
this will produce a ".s" file. That being said, other compilers might produce assembly code at this
step of compilation.
We can stop after this step with the "-S" option on the gcc command, and press Enter.
gcc -S main.c
.file "helloworld.c"
.text
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "Hello, World! \0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
leaq .LC0(%rip), %rcx
call puts
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
.def puts; .scl 2; .type 32; .endef
Step 3: Assembling
The assembler takes the IR code and transforms it into object code, that is code in machine
language (i.e. binary). This will produce a file ending in ".o".
We can stop the compilation process after this step by using the option "-c" with the gcc
command, and pressing Enter.
Note that the "main.o" file is not a text file, hence its contents won't be readable when you open
this file with a text editor.
Step 4: Linking
The linker creates the final executable, in binary. It links object codes of all the source files
together. The linker knows where to look for the function definitions in the static libraries or
the dynamic libraries.
Static libraries are the result of the linker making a copy of all the used library functions to the
executable file. The code in dynamic libraries is not copied entirely, only the name of the library
is placed in the binary file.
By default, after this fourth and last step, that is when you type the whole "gcc main.c"
command without any options, the compiler will create an executable program
called [Link] (or [Link] in case of Windows) that we can run from the command line.
We can also choose to create an executable program with the name we want, by adding the "-o"
option to the gcc command, placed after the name of the file or files we are compiling.
So now we could either type "./[Link]" if you didn’t use the "-o" option or "./hello" to
execute the compiled code. The output will be "Hello World" and following it, the shell prompt
will appear again.
Comments in C
Using comments in a C program increases the readability of the code. You must intersperse the
code with comments at appropriate places. As far as the compiler is concerned, the comments are
ignored. In C, the comments are one or more lines of text, that the compiler skips while building
the machine code.
The comments in C play an important part when the program needs to be modified, especially
by somebody else other than those who have written it originally. Putting comments is often not
given importance by the programmer, but using them effectively is important to improve the
quality of the code.
Any programming language, including C, is less verbose as compared to any human language
like English. It has far less number of keywords, C being one of the smallest languages with only
32 keywords. Hence, the instructions in a C program can be difficult to understand, especially for
someone with non-programming background.
The C language syntax also varies and is also complicated. Usually, the programmer tries to add
complexity to optimize the code. However, it makes the code hard to understand. Comments
provide a useful explanation and convey the intention behind the use of a particular
approach.
For example, take the case of the ?: operator in C, which is a shortcut for the if-else statement.
So, instead of the following code −
if (a % 2 == 0){
printf("%d is Even\n", a);
} else {
printf("%d is Odd\n", a);
}
Obviously, the second method is more complicated than the first. If useful comments are added,
it makes easier to understand the intention and logic of the statement used.
Types of Comments in C
Single-line comments
Multi-line comments/li>
Single-line Comment in C
The C++-style single-line comments were incorporated in C compilers with C99 standards. If
any text begins with the // symbol, the rest of the line is treated as a comment.
The text followed by a double oblique or forward slash [//] in a code is treated as a single-line
comment. All that text after // is ignored by the C compiler during compilation. Unlike the multi-
line or block comment, it need not be closed.
//comment text
The // symbol can appear anywhere. It indicates that all the text following it till the end of the
line is a comment. The subsequent line in the editor is again a place to write a valid C statement.
Take a look at the following program and observe how we have used single-line comments
inside its main function −
return 0;
}
Output
When you run this code, it will produce the following output −
Multi-line Comment in C
In early versions of C (ANSI C), any length of text put in between the symbols /* and */ is
treated as a comment. The text may be spread across multiple lines in the code file. You may call
it a multi-line comment. A block of consecutive lines is treated as a comment.
For example −
/*
Example of a multi-line comment
program to print Hello World
using printf() function
*/
Obviously, since the comments are ignored by the compiler, the syntax rules of C language don't
apply to the comment text.
Comments can appear anywhere in a program, at the top, in between the code, or at the
beginning of a function or a struct declaration, etc.
In this example, we have a multi-line comment that explains the role of a particular user-defined
function used in the given code −
/* headers */
#include <stdio.h>
#include <math.h>
/* main function */
int main(){
/* variable declaration */
float side = 5.50;
/* calling function */
float area = area_of_square(side);
printf("Side = %5.2f Area = %5.2f", side, area);
return 0;
}
Output
When you execute the code, it will produce the following output −
While inserting a comment, you must make sure that for every comment starting with /*, there
must be a corresponding */ symbol. If you start a comment with /* and fail to close it, then the
compiler will throw an error.
Note: A blocked comment or multi-line comment must be put inside /* and */ symbols, whereas
a single-line comment starts with the // symbol and is effective till the end of the line.
Placing comments in a program is always encouraged. Programmers usually avoid the practice of
adding comments. However, they can sometimes find it difficult to debug and modify their code
if it is not properly commented. Comments are especially vital when the development is done in
collaboration. Using comments effectively can be of help to all the members of a team.
Even though comments are ignored by the compiler, they should be clear in meaning and
concise. Whenever the code needs modification, the reason, the timestamp, and the author should
be mentioned in comments.
Tokens in C
A token is referred to as the smallest unit in the source code of a computer language such as C.
The term token is borrowed from the theory of linguistics. Just as a certain piece of text in a
language (like English) comprises words (collection of alphabets), digits, and punctuation
symbols. A compiler breaks a C program into tokens and then proceeds ahead to the next stages
used in the compilation process.
The first stage in the compilation process is a tokenizer. The tokenizer divides the source code
into individual tokens, identifying the token type, and passing tokens one at a time to the next
stage of the compiler.
The parser is the next stage in the compilation. It is capable of understanding the language's
grammar. identifies syntax errors and translates an error-free program into the machine language.
A C source code also comprises tokens of different types. The tokens in C are of the following
types −
Character set
Keyword tokens
Literal tokens
Identifier tokens
Operator tokens
Special symbol tokens
C Character set
The C language identifies a character set that comprises English alphabets – upper and lowercase
(A to Z, as well as a to z), digits 0 to 9, and certain other symbols with a special meaning
attached to them. In C, certain combinations of characters also have a special meaning attached
to them. For example, \n is known as a newline character. Such combinations are called escape
sequences.
Uppercase: A to Z
Lowercase: a to z
Digits: 0 to 9
Special characters: ! " # $ % & ' ( ) * + - . : , ; ` ~ = < > { } [ ] ^ _ \ /
A sequence of any of these characters inside a pair of double quote symbols " and " are used to
represent a string literal. Digits are used to represent numeric literal. Square brackets are used for
defining an array. Curly brackets are used to mark code blocks. Back slash is an escape
character. Other characters are defined as operators.
C Keywords
The C compiler checks whether a keyword has been used according to the syntax, and translates
the source code into the object code.
C Literals
A numeric literal contains digits, a decimal symbol, and/or the exponentiation character E or e.
The string literal is made up of any sequence of characters put inside a pair of double quotation
symbols. A character literal is a single character inside a single quote.
Arrays can also be represented in literal form by putting a comma-separated sequence of literals
between square brackets.
In C, escape sequences are also a type of literal. Two or more characters, the first being a
backslash \ character, put inside a single quote form an escape sequence. Each escape sequence
has a predefined meaning attached to it.
C Identifiers
In contrast to the keywords, the identifiers are the user-defined elements in a program. You need
to define various program elements by giving them an appropriate name. For example,
variable, constant, label, user-defined type, function, etc.
There are certain rules prescribed in C, to form an identifier. One of the important restrictions is
that a reserved keyword cannot be used as an identifier. For example, for is a keyword in C, and
hence it cannot be used as an identifier, i.e., name of a variable, function, etc.
C Operators
C Special symbols
Apart from the symbols defined as operators, the other symbols include punctuation symbols like
commas, semicolons, and colons. In C, you find them used differently in different contexts.
Similarly, the parentheses ( and ) are used in arithmetic expressions as well as in function
definitions. The curly brackets are employed to mark the scope of functions, code blocks
in conditional and looping statements, etc.
C - Keywords
Keywords are those predefined words that have special meaning in the compiler and they cannot
be used for any other purpose. As per the C99 standard, C language has 32 keywords. Keywords
cannot be used as identifiers.
The following table has the list of all keywords (reserved words) available in the C language:
do if static While
All the keywords in C have lowercase alphabets, although the keywords that have been newly
added in C, do have uppercase alphabets in them. C is a case-sensitive language. Hence, int is a
keyword but INT, or Int are not recognized as a keyword. The new keywords introduced from
C99 onwards start with an underscore character. The compiler checks the source code for the
correctness of the syntax of all the keywords and then translates it into the machine code.
Example of C Keywords
In the following program, we are using a keyword as an identifier i.e., as the name of the user-
defined function, that will cause a compilation error.
#include <stdio.h>
/* variable definition: */
int a=5, b=7;
register(a,b);
return 0;
}
void register(int a, int b)
{
printf("%d", a+b);
}
Errors
The reason for the errors is that we are using a keyword register as the name of a user-defined
function, which is not allowed.
The ANSI C version has 32 keywords. These keywords are the basic element of the program
logic. These keywords can be broadly classified in following types −
These keywords are used for variable declaration. C is a statically type language, the variable to
be used must be declared. Variables in C are declared with the following keywords:
C language allows you to define new data types as per requirement. The user defined type has
one or more elements of primary type.
The following keywords are provided for user defined data types −
Conditionals C Keywords
The following set of keywords help you to put conditional logic in the program. The conditional
logic expressed with if and else keywords provides two alternative actions for a condition. For
multi-way branching, use switch – case construct. In C, the jump operation in an assembler is
implemented by the goto keyword.
if Starts an if statement
Repetition or iteration is an essential aspect of the algorithm. C provides different alternatives for
forming a loop, and keywords for controlling the behaviour of the loop. Each of the keywords let
you form a loop of different characteristics and usage.
Other C Keywords
Volatile compiler that the value of the variable may change at any time
_Bool
_Complex
_Imaginary
inline
_Alignas
_Alignof
_Atomic
_Generic
_Noreturn
_Static_assert
When the C23 standard will be released it will introduce 14 more keywords −
alignas
alignof
bool
constexpr
false
nullptr
static_assert
thread_local
true
typeof
typeof_unqual
_Decimal128
Most of the recently reserved words begin with an underscore followed by a capital letter, Since
existing program source code should not have been using these identifiers.
Following points must be kept in mind when using the keywords:
Keywords are reserved by the programming language and have predefined meaning. They
cannot be used as name of a variable or function.
Each keyword has to be used as per the syntax stipulated for its use. If the syntax is violated,
the compiler reports compilation errors.
C is one of the smallest computer languages with only 32 keywords in its ANSI C version,
although a few more keywords have been added afterwards.
C - Identifiers
C Identifiers
Identifiers are the user-defined names given to make it easy to refer to the memory. It is also
used to define various elements in the program, such as the function, user-defined type, labels,
etc. Identifiers are thus the names that help the programmer to use programming elements more
conveniently.
When a variable or a function is defined with an identifier, the C compiler allocates it the
memory and associates the memory location to the identifier. As a result, whenever the
identifier is used in the instruction, C compiler can access its associated memory location. For
example, when we declare a variable age and assign it a value as shown in the following figure,
the compiler assigns a memory location to it.
Even if the programmer can use an identifier of his choice to name a variable or a function etc.,
there are certain rules to be followed to form a valid identifier.
As per the above rules, some examples of the valid and invalid identifiers are as follows −
Valid C Identifiers
Examples of C Identifiers
#include <stdio.h>
int main () {
/* variable definition: */
int marks = 50;
float marks = 65.50;
printf("%d %f", marks, marks);
return 0;
}Error
Identifiers are case-sensitive, as a result age is not the same as AGE.
ANSI standard recognizes a length of 31 characters for an identifier. Although you can
choose a name with more characters, only the first 31 will be recognized. Thus you can
form a meaningful and descriptive identifier.
Scope of C Identifiers
In C language, the scope of identifiers refers to the place where an identifier is declared and can
be used/accessed. There are two scopes of an identifier:
Global Identifiers
If an identifier has been declared outside before the declaration of any function, it is called as an
global (external) identifier.
Example
#include <stdio.h>
int main() {
printf("The value of marks is %d\n", marks);
}
Output
Local Identifiers
On the other hand, an identifier inside any function is an local (internal) identifier.
Example
#include <stdio.h>
int main() {
int marks= 100; // internal identifier
Output
Identifiers can also appear in a forward declaration of a function. However, the declaration
signature of a function should match with the definition.
struct student
{
int rollno;
char *name;
int m1,m2,m3;
float percent
};
struct student s1 = {1, "Raju", 50, 60, 70, 60.00};
struct student
{
int rollno;
char *name;
int m1,m2,m3;
float percent
};
typedef struct student STUDENT;
STUDENT s1 = {1, "Raju", 50, 60, 70, 60.00};
#include <stdio.h>
int main()
{
int x=0;
begin:
x++;
if (x>=10)
goto end;
printf("%d\n", x);
goto begin;
end:
return 0;
}
Output
1
2
3
4
5
6
7
8
9
#include <stdio.h>
enum week{Mon=10, Tue, Wed, Thur, Fri=10, Sat=16, Sun};
int main() {
printf("The value of enum week: %d\n",Mon);
return 0;
}
Output
C - User Input
Every computer application accepts certain data from the user, performs a predefined process on
the same to produce the output. There are no keywords in C that can read user inputs.
The standard library that is bundled with the C compiler includes stdio.h header file, whose
library function scanf() is most commonly used to accept user input from the standard input
stream. In addition, the stdio.h library also provides other functions for accepting input.
Example
To understand the need for user input, consider the following C program −
#include <stdio.h>
int main(){
int price, qty, ttl;
price = 100;
qty = 5;
ttl = price*qty;
return 0;
}
Output
The above program calculates the total purchase amount by multiplying the price and quantity of
an item purchased by a customer. Run the code and check its output −
Total: 500
For another transaction with different values of price and quantity, you need to edit the program,
put the values, then compile and run again. To do this every time is a tedious activity. Instead,
there must be a provision to assign values to a variable after the program is run.
The scanf() function reads the user input during the runtime, and assigns the value to a variable.
The C language recognizes the standard input stream as stdin and is represented by the standard
input device such as a keyboard. C always reads the data from the input stream in the form of
characters.
The scanf() function converts the input to a desired data type with appropriate format specifiers.
Syntax of Scanf()
The first argument to the scanf() function is a format string. It indicates the data type of the
variable in which the user input is to be parsed. It is followed by one or more pointers to
the variables. The variable names prefixed by & gives the address of the variable.
%c Character
%d Signed integer
%f Float values
%i Unsigned integer
%lf Double
Going back to the previous example, we shall use the scanf() function to accept the value for
"price" and "qty", instead of assigning them any fixed value.
#include <stdio.h>
int main(){
return 0;
}
Output
When the above program is run, C waits for the user to enter the values −
When the values are entered and you press Enter, the program proceeds to the subsequent steps.
What is more important is that, for another set of values, you don't need to edit and compile
again. Just run the code and the program again waits for the user input. In this way, the program
can be run any number of times with different inputs.
Integer Input
The %d format specifier has been defined for signed integer. The following program reads the
user input and stores it in the integer variable num.
#include <stdio.h>
int main(){
int num;
return 0;
}
Output
The scanf() function can read values to one or more variables. While providing the input values,
you must separate the consecutive values by a whitespace, a tab or an Enter.
#include <stdio.h>
int main(){
return 0;
}
Output
or
Float Input
For floating point input, you need to use the %f format specifier.
#include <stdio.h>
int main(){
float num1;
return 0;
}
Output
The scanf() function may read inputs for different types of variables. In the following program,
user input is stored in an integer and a float variable −
#include <stdio.h>
int main(){
int num1;
float num2;
return 0;
}
Output
Character Input
The %c format specifier reads a single character from the keyboard. However, we must give a
blank space before %c in the format string. This is because the %c conversion specifier won't
automatically skip any leading whitespaces.
If there is a stray newline in the input stream (from a previous entry, for example)
the scanf() call will consume it immediately.
The blank space in the format string tells scanf to skip the leading whitespace, and the first non-
whitespace character will be read with the %c conversion specifier.
#include <stdio.h>
int main(){
char ch;
return 0;
}
Output
The following program reads two characters separated by a whitespace in two char variables.
#include <stdio.h>
int main(){
return 0;
}
Output
The stdio.h header file also provides the getchar() function. Unlike scanf(), getchar() doesn't
have a format string. Also, it reads a single key stroke without the Enter key.
#include <stdio.h>
int main(){
char ch;
return 0;
}
Output
Enter a character: W
You entered:
W
You entered character: W
You can also use the unformatted putchar() function to print a single character.
The following program shows how you can read a series of characters till the user presses the
Enter key −
#include <stdio.h>
int main(){
char ch;
char word[10];
int i = 0;
printf("Enter characters. End by pressing the Enter key: ");
while(1){
ch = getchar();
word[i] = ch;
if (ch == '\n')
break;
i++;
}
printf("\nYou entered the word: %s", word);
return 0;
}
Output
String Input
There is also a %s format specifier that reads a series of characters into a char array.
#include <stdio.h>
int main(){
char name[20];
return 0;
}
Output
C uses the whitespace as the delimiter character. Hence, if you try to input a string that contains a
blank space, only the characters before the space are stored as the value.
The gets() function overcomes this limitation. It is an unformatted string input function. All the
characters till you press Enter are stored in the variable.
#include <stdio.h>
#include <stdlib.h>
int main(){
char name[20];
return 0;
}
Output
C - Basic Syntax
In C programming, the term "syntax" refers to the set of rules laid down for the programmer to
write the source code of a certain application. While there is a specific syntax recommended for
each of the keywords in C, certain general rules need to be followed while developing a program
in C.
Tokens in C
A C program consists of various tokens and a token is either a keyword, an identifier, a constant,
a string literal, or a symbol. For example, the following C statement consists of five tokens −
printf
(
"Hello, World! \n"
);
The C compiler identifies whether the token is a keyword, identifier, comment, a literal, an
operator, any of the other recognized special symbols or not. This exercise is done by the
tokenizer in the first stage of the compilation process.
Identifiers in C
A C identifier is a name used to identify a variable, function, or any other user-defined item. An
identifier starts with a letter A to Z, a to z, or an underscore '_' followed by zero or more letters,
underscores, and digits (0 to 9).
C prescribes certain rules to form the names of variables, functions or other programming
elements. They are not keywords. An identifier must start with an alphabet or underscore
character, and must not have any other character apart from alphabets, digits and underscore.
Keywords in C
The most important part of C language is its keywords. Keywords are the reserved words having
a predefined meaning with prescribed syntax for usage. In ANSI C, all keywords have lowercase
alphabets. The programmer needs to choose the correct keywords to construct the solution of the
problem at hand. To learn programming is basically to learn to correctly use the keywords.
The following list shows the reserved words in C. These reserved words may not be used
as constants or variables or any other identifier names.
Each keyword in C has a well−defined syntax in addition to the basic syntax explained in this
chapter. The usage of each keyword will be explained in the subsequent chapters.
Semicolons in C
In a C program, the semicolon is a statement terminator. That is, each individual statement must
be ended with a semicolon. It indicates the end of one logical entity.
Since the semicolon ";" is only the delimiter symbol for a C statement, there may be more than
one statements in a one physical line in a C program. Similarly, a single statement may span over
more than one lines in the source code.
The following line is perfectly valid in C. In one line, there are multiple statements −
The following code is also valid even if a statement spills over multiple lines −
if
(a>=50)
printf("pass");
else printf("fail");
Comments in C
Comments are like helping text in your C program and they are ignored by the compiler. They
start with /* and terminate with the characters */ as shown below −
/* my first program in C */
You cannot have comments within comments and they do not occur within a string or character
literals.
Source Code
The C program is a text file, containing a series of statements. The file must have a .c as its
extension. The C compiler identifies only the .c file for compilation process. Only the English
alphabets are used in the keywords and other identifiers of C language, although the string
literals may contain any Unicode characters.
Every C program must have one (and only one) main() function, from where the compiler starts
executing the code. However, it is not necessary that the main() function should be in the
beginning of the code in the .c file. There can be any number of functions in a C program. If a
function calls any other function before its definition, there should be its forward declaration.
Header Files
In addition to the keywords, a C program often needs to call predefined functions from the
library of header files. The required header files are imported with the #include preprocessor
directive. All the #include statements must be in the beginning of the source code.
Variable Declaration
Statements in a C Program
Statements are the basic building blocks of the program. Statements in the main() function are
executed in a top to bottom order by default. The sequence is controlled
by conditionals or looping constructs. As a basic syntax rule, each statement must have
semicolon (;) at the end.
Whitespaces in a C Program
While compiling the source code, the compiler ignores the whitespaces. Whitespace is the term
used in C to describe blanks, tabs, newline characters and comments. While one can use them for
better readability of the code, they have little significance for the compiler (unless they are a part
of a string literal, appearing inside the double quote symbols). A line containing only whitespace,
possibly with a comment, is known as a blank line, and a C compiler totally ignores it.
Whitespace separates one part of a statement from another and enables the compiler to identify
where one element in a statement, such as int, ends and the next element begins. Therefore, in
the following statement −
int age;
There must be at least one whitespace character (usually a space) between int and age for the
compiler to be able to distinguish them. On the other hand, in the following statement −
No whitespace characters are necessary between "fruit" and "=", or between "=" and "apples",
although you are free to include some if you wish to increase readability.
Compound Statements in C
Often, you need to define a cohesive block of statements as a single unit of programming logic.
For example, you may want more than one statements to be executed if a certain logical
expression is true, or multiple statements in a looping block. Similarly, a user-defined function
may have more than one statements. In such cases, statements are grouped together to form a
compound statement. C uses curly brackets for such grouping.
{
Statement1;
Statement2;
...
...
}
In the following code, the if and else parts have a block each of statements.
if (marks<50) {
printf("Result: Fail\n");
printf ("Better Luck next time");
}
else {
printf("Result: Pass\n");
printf("Congratulations");
}
Defining a custom type with struct, union or enum also requires clubbing more than one
statements together with curly brackets.
struct student {
char name[20];
int marks, age;
};
C - Data Types
Data types in C refer to an extensive system used for declaring variables or functions of
different types. The type of a variable determines how much space it occupies in storage and
how the bit pattern stored is interpreted. In this chapter, we will learn about data types in C. A
related concept is that of "variables", which refer to the addressable location in the memory of
the processor. The data captured via different input devices is stored in the computer memory. A
symbolic name can be assigned to the storage location called variable name.
C is a statically typed language. The name of the variable along with the type of data it intends to
store must be explicitly declared before actually using it.
C is also a strongly typed language, which means that the automatic or implicit conversion of
one data type to another is not allowed.
Basic Types
1 They are arithmetic types and are further classified into: (a)
integer types and (b) floating-point types.
Enumerated types
They are again arithmetic types and they are used to define
2
variables that can only assign certain discrete integer values
throughout the program.
The type void
3
The type specifier void indicates that no value is available.
Derived types
4 They include (a) Pointer types, (b) Array types, (c) Structure
types, (d) Union types and (e) Function types.
The array types and structure types are referred collectively as the aggregate types. The type of a
function specifies the type of the function's return value. We will see the basic types in the
following section, where as other types will be covered in the upcoming chapters.
The following table provides the details of standard integer types with their storage sizes and
value ranges −
-9223372036854775808 to
long 8 bytes
9223372036854775807
To get the exact size of a type or a variable on a particular platform, you can use
the sizeof operator. The expressions sizeof(type) yields the storage size of the object or type in
bytes.
Given below is an example to get the size of various type on a machine using different constant
defined in limits.h header file −
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>
return 0;
}
Output
When you compile and execute the above program, it produces the following result on Linux−
CHAR_BIT : 8
CHAR_MAX : 127
CHAR_MIN : -128
INT_MAX : 2147483647
INT_MIN : -2147483648
LONG_MAX : 9223372036854775807
LONG_MIN : -9223372036854775808
SCHAR_MAX : 127
SCHAR_MIN : -128
SHRT_MAX : 32767
SHRT_MIN : -32768
UCHAR_MAX : 255
UINT_MAX : 4294967295
ULONG_MAX : 18446744073709551615
USHRT_MAX : 65535
The following table provides the details of standard floating-point types with storage sizes and
value ranges and their precision −
Storage
Type Value range Precision
size
15 decimal
double 8 byte 2.3E-308 to 1.7E+308
places
The header file "float.h" defines the macros that allow you to use these values and other details
about the binary representation of real numbers in your programs.
The following example prints the storage space taken by a float type and its range values −
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>
return 0;
}
Output
When you compile and execute the above program, it produces the following result on Linux −
Note: "sizeof" returns "size_t". The type of unsigned integer of "size_t" can vary depending on
platform. And, it may not be long unsigned int everywhere. In such cases, we use "%zu" for the
format string instead of "%d".
Earlier versions of C did not have Boolean data type. C99 standardization of ANSI C introduced
_bool type which treats zero value as false and non-zero as true.
There are two user-defined data types struct and union, that can be defined by the user with the
help of the combination of other basic data types.
One of the unique features of C language is to store values of different data types in one variable.
The keywords struct and union are provided to derive a user-defined data type. For example,
struct student {
char name[20];
int marks, age;
};
A union is a special case of struct where the size of union variable is not the sum of sizes of
individual elements, as in struct, but it corresponds to the largest size among individual elements.
Hence, only one of elements can be used at a time. Look at following example:
union ab {
int a;
float b;
};
We shall learn more about structure and union types in a later chapter.
The void type specifies that no value is available. It is used in three kinds of situations −
Pointers to void
A pointer of type void * represents the address of an object, but
3 not its type. For example, a memory allocation function
void *malloc( size_t size ); returns a pointer to void which can
be casted to any data type.
int marks[5];
Arrays can be initialized at the time of declaration. The values to be assigned are put in
parentheses.
C also supports multi-dimensional arrays. To learn more about arrays, refer to the chapter
on Arrays in C.
A pointer is a special variable that stores address or reference of another variable/object in the
memory. The name of pointer variable is prefixed by asterisk (*). The type of the pointer
variable and the variable/object to be pointed must be same.
int x;
int *y;
y = &x;
Here, "y" is a pointer variable that stores the address of variable "x" which is of "int" type.
Pointers are used for many different purposes. Text string manipulation and dynamic memory
allocation are some of the processes where the use of pointers is mandatory. Later in this tutorial,
you can find a detailed chapter on Pointers in C.
C - Variables
A variable is nothing but a name given to a storage area that our programs can manipulate. Each
variable in C has a specific type, which determines the size and layout of the variable's memory;
the range of values that can be stored within that memory; and the set of operations that can be
applied to the variable.
Instead of identifying a free memory location and assigning it a value, you can find a suitable
mnemonic identifier and assign it a value. The C compiler will choose an appropriate location
and bind it to the identifier specified by you.
The name of the variable must start with an alphabet (upper or lowercase) or an underscore (_). It
may consist of alphabets (upper or lowercase), digits, and underscore characters. No other
characters can be a part of the name of a variable in C.
Variable names in C are case-sensitive. For example, "age" is not the same as "AGE".
The ANSI standard recognizes a length of 31 characters for a variable name. Although you can
choose a name with more characters, only the first 31 will be recognized. Using a descriptive
name for a variable, that reflects the value it intends to store is considered to be a good practice.
Avoid using very short variable names that might confuse you.
C is a statically typed language. Hence, the data type of the variable must be mentioned in the
declaration before its name. A variable may be declared inside a function (local variable) or
globally. More than one variable of the same type may be declared in a single statement.
Example
Based on the above set of rules and conventions, here are some valid and invalid variable names:
In C, variables can store data belonging to any of the types it recognizes. Hence there are as
many number of types of variables as the number of data types in C.
char
1
Typically a single octet(one byte). It is an integer type.
int
2
The most natural size of integer for the machine.
float
3
A single-precision floating point value.
double
4
A double-precision floating point value.
void
5
Represents the absence of type.
C programming language also allows to define various other types of variables such as
Enumeration type, Pointer type, Array type, Structure type, Union type, etc. For this chapter, let
us study only basic variable types.
Variable Definition in C
A variable definition tells the compiler where and how much storage to create for the variable. A
variable definition specifies a data type and contains a list of one or more variables of that type
as follows −
type variable_list;
Here, type must be a valid C data type including char, w_char, int, float, double, bool, or any
user-defined object; and variable_list may consist of one or more identifier names separated by
commas.
int i, j, k;
char c, ch;
float f, salary;
double d;
The line int i, j, k; declares and defines the variables i, j, and k; which instruct the compiler to
create variables named i, j and k of type int.
Variables can be initialized (assigned an initial value) in their declaration. The initializer consists
of an equal sign followed by a constant expression as follows −
// declaration of d and f
extern int d = 3, f = 5;
For definition without an initializer: variables with static storage duration are implicitly
initialized with NULL (all bytes have the value 0); the initial value of all other variables are
undefined.
Variable Declaration in C
As per the ANSI C standard, all the variables must be declared in the beginning. Variable
declaration after the first processing statement is not allowed. Although the C99 and C11
standard revisions have removed this stipulation, it is still considered a good programming
practice. You can declare a variable to be assigned a value later in the code, or you can initialize
it at the time of declaration.
Once a variable of a certain type is declared, it cannot be assigned a value of any other type. In
such a case the C compiler reports a type mismatch error.
A variable declaration provides assurance to the compiler that there exists a variable with the
given type and name so that the compiler can proceed with further compilation without requiring
complete detail about the variable. A variable definition has its meaning at the time of
compilation only, the compiler needs actual variable definition at the time of linking the
program.
A variable declaration is useful when you are using multiple files and you define your variable in
one of the files which will be available at the time of linking the program. You will use the
keyword "extern" to declare a variable at any place. Though you can declare a variable multiple
times in your C program, it can be defined only once in a file, a function, or a block of code.
Example
Try the following example, where variables have been declared at the top, but they have been
defined and initialized inside the main function −
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}
Output
When the above code is compiled and executed, it produces the following result:
value of c : 30
value of f : 23.333334
The same concept applies on function declaration where you provide a function name at the time
of its declaration and its actual definition can be given anywhere else. For example −
// function declaration
int func();
int main() {
// function call
int i = func();
}
// function definition
int func() {
return 0;
}
lvalue expressions
rvalue expressions
Lvalue Expressions in C
Expressions that refer to a memory location are called "lvalue" expressions. An lvalue may
appear as either the left-hand or right-hand side of an assignment.
Variables in C are lvalues and so they may appear on the left-hand side of an assignment.
Rvalue Expressions in C
The term "rvalue" refers to a data value that is stored at some address in memory. An "rvalue" is
an expression that cannot have a value assigned to it which means an rvalue may appear on the
right-hand side but not on the left-hand side of an assignment.
Numeric literals are rvalues and so they may not be assigned and cannot appear on the left-hand
side.
// valid statement
int g = 20;
// invalid statement
// it would generate compile-time error
10 = 20;
Integer Promotions in C
The C compiler promotes certain data types to a higher rank for the sake of achieving
consistency in the arithmetic operations of integers.
In addition to the standard int data type, the C language lets you work with its subtypes such as
char, short int, long int, etc. Each of these data types occupy a different amount of memory
space. For example, the size of a standard int is 4 bytes, whereas a char type is 2 bytes of length.
When an arithmetic operation involves integer data types of unequal length, the compiler
employs the policy of integer promotion.
Integer Promotions
As a general principle, the integer types smaller than int are promoted when an operation is
performed on them. If all values of the original type can be represented as an int, the value of the
smaller type is converted to an int; otherwise, it is converted to an unsigned int.
One must understand the concept of integer promotion to write reliable C code, and avoid
unexpected problems related to the size of data types and arithmetic operations on smaller
integer types.
Example
In this example, the two variables a and b seem to be storing the same value, but they are not
equal.
#include <stdio.h>
int main(){
char a = 251;
unsigned char b = a;
if (a == b)
printf("\n Same");
else
printf("\n Not Same");
return 0;
}
Output
When you run this code, it will produce the following output −
a=√
b=√
Not Same
You get this output because "a" and "b" are treated as integers during comparison. "a" is a signed
char converted to int as -5, while "b" is an unsigned char converted to int as 251.
Let us try to understand the mechanism of integer promotions with this example −
#include <stdio.h>
int main(){
return 0;
}
Output
Run the code and check its output −
d as int: 65 as char: A
In the arithmetic expression "(a * b) / c", the bracket is solved first. All the variables are of
signed char type, which is of 2 byte length and can store integers between -128 to 127. Hence the
multiplication goes beyond the range of char but the compiler doesn't report any error.
The C compiler applies integer promotion when it deals with arithmetic operations involving
small types like char. Before the multiplication of these char types, the compiler changes them to
int type. So, in this case, (a * b) gets converted to int, which can accommodate the result of
multiplication, i.e., 1200.
Example
Integer promotions are applied as part of the usual arithmetic conversions to certain argument
expressions; operands of the unary +, -, and ~ operators; and operands of the shift operators.
Take a look at the following example −
#include <stdio.h>
int main(){
char a = 10;
int b = a >> 3;
return 0;
}
Output
When you run this code, it will produce the following output −
b as int: 1 as char:
In the above example, shifting the bit structure of "a" to the left by three bits still results in its
value within the range of char (a << 3 results in 80).
Example
In this example, the rank of the char variable is prompted to int so that its left shift operation
goes beyond the range of char type.
#include <stdio.h>
int main(){
char a = 50;
int b = a << 2;
return 0;
}
Output
Promotion rules help the C compiler in maintaining consistency and avoiding unexpected results.
The fundamental principle behind the rules of promotion is to ensure that the expression's type is
adjusted to accommodate the widest data type involved, preventing data loss or truncation.
The integer types in C are char, short, int, long, long long and enum. Booleans are also
treated as an integer type when it comes to type promotions.
No two signed integer types shall have the same rank, even if they have the same
representation.
The rank of a signed integer type shall be greater than the rank of any signed integer type
with less precision.
The rank of long int > the rank of int > the rank of short int > the rank of signed char.
The rank of char is equal to the rank of signed char and unsigned char.
Whenever a small integer type is used in an expression, it is implicitly converted to int
which is always signed.
All small integer types, irrespective of sign, are implicitly converted to (signed) int when
used in most expressions.
In short, we have the following integer promotion rules −
Example
Here, the variables x and y are of char data type. When the division operation is performed on
them, they automatically get promoted to int and the resultant value is stored in z.
#include <stdio.h>
int main(){
char x = 68;
char y = 34;
char z = x/y;
printf("\nThe value of z: %d", z);
return 0;
}
Output
When you run this code, it will produce the following output −
The C compiler attempts data type conversion, especially when dissimilar data types appear in an
expression. There are certain times when the compiler does the conversion on its own (implicit
type conversion) so that the data types are compatible with each other. On other occasions, the C
compiler forcefully performs the conversion (explicit type conversion), which is carried out by
the type cast operator.
In C, implicit type conversion takes place automatically when the compiler converts the type of
one value assigned to a variable to another data type. It typically happens when a type with
smaller byte size is assigned to a "larger" data type. In such implicit data type conversion, the
data integrity is preserved.
While performing implicit or automatic type conversions, the C compiler follows the rules of
type promotions. Generally, the principle followed is as follows −
Integer Promotion
Integer promotion is the process by which values of integer type "smaller" than int or unsigned
int are converted either to int or unsigned int.
Example
#include <stdio.h>
int main(){
int i = 17;
char c = 'c'; /* ascii value is 99 */
int sum;
sum = i + c;
return 0;
}
Output
When you run this code, it will produce the following output −
Here, the value of sum is 116 because the compiler is doing integer promotion and converting
the value of "c" to ASCII before performing the actual addition operation.
Usual arithmetic conversions are implicitly performed to cast their values to a common type. The
compiler first performs integer promotion; if the operands still have different types, then they are
converted to the type that appears highest in the following hierarchy −
Example
#include <stdio.h>
int main(){
char a = 'A';
float b = a + 5.5;
printf("%f", b);
return 0;
}
Output
70.500000
When the above code runs, the char variable "a" (whose int equivalent value is 70) is promoted
to float, as the other operand in the addition expression is a float.
When you need to covert a data type with higher byte size to another data type having lower byte
size, you need to specifically tell the compiler your intention. This is called explicit type
conversion.
C provides a typecast operator. You need to put the data type in parenthesis before the operand to
be converted.
Note that if type1 is smaller in length than type2, then you don’t need such explicit casting. It is
only when type1 is greater in length than type2 that you should use the typecast operator.
Typecasting is required when we want to demote a greater data type variable to a comparatively
smaller one or convert it between unrelated types like float to int.
Example
#include <stdio.h>
int main(){
int x = 10, y = 4;
float z = x/y;
printf("%f", z);
return 0;
}
Output
2.000000
While we expect the result to be 10/4 (that is, 2.5), it shows 2.000000. It is because both the
operands in the division expression are of int type. In C, the result of a division operation is
always in the data type with larger byte length. Hence, we have to typecast one of the integer
operands to float, as shown below −
Example
#include <stdio.h>
int main(){
int x = 10, y = 4;
float z = (float)x/y;
printf("%f", z);
return 0;
}
Output
If we change the expression such that the division itself is cast to float, the result will be
different.
Typecasting Functions in C
The standard C library includes a number of functions that perform typecasting. Some of the
functions are explained here −
The atoi() function converts a string of characters to an integer value. The function is declared in
the stdlib.h header file.
Example
The following code uses the atoi() function to convert the string "123" to a number 123 −
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("%d\n", num);
return 0;
}
Output
123
You can use the itoa() function to convert an integer to a null terminated string of characters. The
function is declared in the stdlib.h header file.
Example
The following code uses itoa() function to convert an integer 123 to string "123" −
#include <stdio.h>
#include <stdlib.h>
int main(){
itoa(num,str, 10);
printf("%s\n", str);
return 0;
}
Output
123
The malloc() Function − The malloc() function is a dynamic memory allocation function.
In function arguments and return values − You can apply the typecast operator to formal
arguments or to the return value of a user-defined function.
Example
Here is an example −
#include <stdio.h>
#include <stdlib.h>
float divide(int, int);
int main(){
int x = 10, y = 4;
float z = divide(x, y);
printf("%f", z);
return 0;
}
Output
When you run this code, it will produce the following output −
2.500000
Employing implicit or explicit type conversion in C helps in type safety and improved code
readability, but it may also lead to loss of precision and its complicated syntax may be confusing.
Booleans in C
Unlike the int, char or float types, the ANSI C standard doesn’t have a built-in or primary
Boolean type. A Boolean or bool data generally refers to the one that can hold one of the two
binary values: true or false (or yes/no, on/off, etc.). Even if the bool type is not available in C,
you can implement the behaviour of Booleans with the help of an enum type.
The new versions of C compilers, complying with the C99 standard or later, support
the bool type, which has been defined in the header file stdbool.h.
The enum type assigns user-defined identifiers to integral constants. We can define an
enumerated type with true and false as the identifiers with the values 1 and 0.
Example
1 or any other number that is not 0 represents true, whereas 0 represents false.
#include <stdio.h>
Output
1
0
To make it more concise, we can use the typedef keyword to call enum bool by the name BOOL.
Example 1
#include <stdio.h>
int main(){
BOOL x = true;
BOOL y = false;
Output
1
0
Example 2
We can even use the enumerated constants in the decision-making or loop statements −
#include <stdio.h>
int main(){
int i = 0;
while(true){
i++;
printf("%d\n", i);
if(i >= 5)
break;
}
return 0;
}
Output
When you run this code, it will produce the following output −
1
2
3
4
5
Boolean Values with #define
The #define preprocessor directive is used to define constants. We can use this to define the
Boolean constants, FALSE as 0 and TRUE as 1.
Example
#include <stdio.h>
#define FALSE 0
#define TRUE 1
int main(){
return 0;
}
Output
False: 0
True: 1
The C99 standard of C has introduced the stdbool.h header file. It contains the definition
of bool type, which actually is a typedef alias for _bool type. It also defines the
macros true which expands to 1, and false which expands to 0.
Example 1
#include <stdio.h>
#include <stdbool.h>
int main(){
bool a = true;
bool b = false;
return 0;
}
Output
True: 1
False: 0
Example 2
We can use bool type variables in logical expressions too, as shown in the following example −
#include <stdio.h>
#include <stdbool.h>
int main(){
bool x;
x = 10 > 5;
if(x)
printf("x is True\n");
else
printf("x is False\n");
bool y;
int marks = 40;
y = marks > 50;
if(y)
printf("Result: Pass\n");
else
printf("Result: Fail\n");
}
Output
x is True
Result: Fail
Example 3
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main(void){
while(loop){
i++;
printf("i: %d \n", i);
if (i >= 5)
loop = false;
}
printf("Loop stopped!\n");
return EXIT_SUCCESS;
}
Output
When you run this code, it will produce the following output −
i: 1
i: 2
i: 3
i: 4
i: 5
Loop stopped!
C - Constants
Instead of repeatedly using hard-coded values in a program, it is advised to define a constant and
use it. Constants in a C program are usually employed to refer to a value which may be error-
prone if it is to be used repetitively in the program, at the same time its value is not likely to
change.
For example, the value of mathematical constant PI is a high-precision floating point number
3.14159265359, and if it is likely to appear frequently, it is declared as a constant and used by its
name.
We may consider a constant in C as a read-only variable, as its value can only be used
subsequently but cannot be modified.
You can declare a constant in C program with either of the following two ways −
For example,
Example
#include <stdio.h>
int main(){
const float PI = 3.14159265359;
float radius = 5;
float area = PI*radius*radius;
printf ("area: %f", area);
return 0;
}
Output
area: 78.539818
However, changing the value of a constant is prohibited. The following statement gives a
compiler error −
In case of variables, you can declare a variable and assign it a value later on in the program,
however you cannot follow the same process in case of a constant.
You can declare a constant in C without assigning it a value. But when you try to assign it a
value afterwords, then the compiler will throw an error.
Note: "sizeof" returns "size_t". The type of unsigned integer of "size_t" can vary depending on
platform. And, it may not be long unsigned int everywhere. In such cases, we use "%zu" for the
format string instead of "%d".
This is because the compiler assigns a random garbage value at the time of declaration, which
you cannot change afterwards. Hence, you must declare and initialize the constant at once.
A constant in C can be of any of the data types including primary data types such as int, float,
char, and derived data types such as struct.
Using the #define preprocessor directive is also an effective method to define a constant. Here is
its syntax −
#define PI = 3.14159265359
Although the constant so defined can also be used in any expression (just as the one with the
const keyword), there is a difference between the two.
The constants created by the #define directive are not handled by the compiler. Instead, they
behave as macros, whose values are substituted at the runtime.
The other notable difference is that you need not mention the data type of the value to be
assigned to the constant when using the #define directive.
Given below is another example of a constant defined using the #define directive −
#include <stdio.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main() {
int area;
area = LENGTH * WIDTH;
printf("length: %d width: %d", LENGTH, WIDTH);
printf("%c", NEWLINE);
printf("value of area : %d", area);
return 0;
}
Output
Upon running this code, you will get the following output −
length: 10 width: 5
value of area : 50
Since a constant is also an identifier in C, it follows all the rules of forming an identifier.
Identifiers in C are case-sensitive. Hence the convention followed while defining a constant in C
is that it uses uppercase characters, however it is not mandatory.
By definition, constants are immutable. Why would you change the value of a constant in the
first place? We use constants whose value is supposed to remain unchanged. To be able to
change the value, we would define a variable rather than a constant.
We have seen that it is not possible to assign a new value to an already defined constant.
However, there exists a workaround with which a new value can be assigned to a constant.
The technique uses the concept of pointers in C. A Pointer is a variable that stores the address of
another variable. Since it is a variable, its value can be changed. Moreover, this change reflects
in the original variable.
The following code demonstrates how to change the value of a constant with the pointer
mechanism −
#include <stdio.h>
int main(){
const int x = 10;
printf("Initial Value of Constant: %d\n", x);
// y is a pointer to constant x
int* y = &x;
Output
Note that this technique is effective only for those constants which are defined using
the const qualifier.
If you have defined your constant using the #define directive, then you cannot apply this
process. This is because the pointer has a data type, and it must be of the same type whose
address is to be stored. On the other hand, the constant defined using the #define directive
doesn't really have a data type. It is in fact a macro whose value is substituted during the runtime.
C - Literals
int x = 10;
int x = 10;
int y = x*2;
In the first case, 10 is an integer literal assigned to "x". In the second case, the result of "x*2"
expression is assigned to "y".
A literal is thus a value of a certain data type represented directly into the source code. Normally,
literals are used to set a value of a variable.
On their own, literals don’t form any of the programming element. Different notations are used
to represent the values of different data types.
Integer Literals in C
In the above example, 10 is an integer literal. A positive or negative whole number represented
with digits 0 to 9, without a fractional part is a decimal integer literal. It must be within the
acceptable range for the given OS platform.
int x = 200;
int y = -50;
An integer literal can also have a suffix that is a combination of "U" and "L", for "unsigned" and
"long", respectively. The suffix can be uppercase or lowercase and can be in any order.
int c = 89U;
long int d = 99998L;
C allows you to represent an integer in octal and hexadecimal number systems. For a literal
representation of an octal, prefix the number with 0 (ensure that the number uses octal digits
only, from 0 to 7).
For a hexadecimal literal, prefix the number with 0x or 0X. The hexadecimal number must have
0 to 9, and A to F (or a to f) symbols.
Example
#include <stdio.h>
int main(){
Output
Octal to decimal: 21
Hexadecimal to decimal: 161
Modern C compilers also let you represent an integer as a binary number, for which you need to
add a 0b prefix.
Example
#include <stdio.h>
int main(){
int x = 0b00010000;
printf("binary to decimal: %d", x);
}
Output
binary to decimal: 16
212 /* valid */
215u /* valid */
0xFeeL /* valid */
078 /* invalid: 8 is not an octal digit */
032UU /* invalid: cannot repeat a suffix */
Here are some other examples of various types of integer literals −
85 /* decimal */
0213 /* octal */
0x4b /* hexadecimal */
30 /* int */
30u /* unsigned int */
30l /* long */
30ul /* unsigned long */
Floating-point Literals in C
A floating-point literal in C is a real number with an integer part and a fractional part within the
range acceptable to the compiler in use, and represented in digits, decimal point with an optional
exponent symbol (e or E).
A floating point literal is generally used for initializing or setting the value of a float or a double
variable in C.
Example
The following assignment examples use floating point literals with a decimal point separating the
integer and the fractional part −
#include <stdio.h>
int main(){
float x = 10.55;
float y = -1.333;
printf("x and y are: %f, %f", x, y);
}
Output
Floating point literals with a high degree of precision can be stated with the exponentiation
symbol "e" or "E". This is called the scientific notation of a float literal.
While representing decimal form, you must include the decimal point, the exponent, or both.
While representing exponential form, you must include the integer part, the fractional part, or
both.
Example
#include <stdio.h>
int main(){
float x = 100E+4;
float y = -1.3E-03;
printf("x: %f\n", x);
printf("y: %f\n", y);
}
Output
When you run this code, it will produce the following output −
x: 1000000.000000
y: -0.001300
3.14159 /* valid */
314159E-5L /* valid */
510E /* invalid: incomplete exponent */
210f /* invalid: no decimal or exponent */
.e55 /* invalid: missing integer or fraction */
Character Literals in C
A character literal in C is a single character enclosed within single quote symbols. Note that C
recognizes straight quotes only. Hence, use ' to form a character literal and not ‘). Here is an
example −
char x = 'I';
Character literals are generally assigned to a char variable that occupies a single byte. Using
the %c format specifier outputs the character. Use %d and you’ll obtain the ASCII value of the
character.
Example
#include <stdio.h>
int main(){
char x = 'I';
printf("x: %c\n", x);
printf("x: %d\n", x);
}
Output
x: I
x: 73
Escape Sequences in C
C defines a number of escape sequences as a sequence of characters starting with "\" and an
alternate meaning attached to the following characters.
Even though an escape sequence consists of more than one characters, it is put inside single
quotes. An escape sequence produces the effect of a single non-printable character. For
example, '\n' is an escape sequence that represents a newline character, with the same effect as
pressing the Enter key.
Example
#include <stdio.h>
int main(){
char x = 'I';
char y = 'J';
printf("x: %c\ny: %c", x,y);
}
Output
x: I
y: J
A character literal can also be a UNICODE representation of a character. Such a literal has /u at
the beginning.
Example
#include <stdio.h>
int main(){
char x = '\u09A9';
printf("x: %c\n", x);
printf("x: %d\n", x);
}
Output
x: ⌐
y: -87
String Literals in C
A sequence of characters put inside double quotation symbols forms a string literal. C doesn’t
provide a string variable. Instead, we need to use an array of char type to store a string.
Example
#include <stdio.h>
int main(){
Output
A string literal may contain plain characters, escape sequences, and Unicode characters. For
example −
You can also have a literal representation of an array by putting its elements inside the curly
brackets { and }. For example:
Similarly, the curly brackets can also be used for a literal representation of a struct value. For
example −
struct marks {
int phy;
int che;
int math
};
struct marks m1 = {50, 60, 70};
Escape Sequence in C
An escape sequence in C is a literal made up of more than one character put inside single
quotes. Normally, a character literal consists of only a single character inside single quotes.
However, the escape sequence attaches a special meaning to the character that appears after a
backslash character (\).
The \ symbol causes the compiler to escape out of the string and provide meaning attached to the
character following it.
Look at \n as an example. When put inside a string, the \n acts as a newline character, generating
the effect of pressing the Enter key. The following statement −
Hello
World
The new line is an unprintable character. The \n escape sequence is useful to generate its effect.
Similarly, the escape sequence \t is equivalent to pressing the Tab key on the keyboard.
An escape sequence is a sequence of characters that does not represent itself when used inside a
character or string literal but is translated into another character or a sequence of characters that
may be difficult or impossible to represent directly.
In C, all escape sequences consist of two or more characters, the first of which is the
backslash \ (called the "Escape character"); the remaining characters have an interpretation of the
escape sequence as per the following table.
\\ \ character
\? ? character
\a Alert or bell
\b Backspace
\f Form feed
\n Newline
\r Carriage return
\t Horizontal tab
\v Vertical tab
Let us understand how these escape sequences work with the help of a set of examples.
The newline character, represented by the escape sequence \n in C, is used to insert the effect of
carriage return on the output screen. You would use this escape sequence to print text in separate
lines and improve the readability of output.
Example
#include <stdio.h>
int main(){
Output
Hello.
Good morning.
My name is Ravi
Example
#include <stdio.h>
int main(){
printf("Name:\tRavi\tMarks:\t50");
}
Output
To add backslash character itself as a part of a string, it must precede by another backslash. First
backslash escapes out of the string, and the second one takes the effect.
Example
#include <stdio.h>
int main(){
Output
These characters have a special meaning in C since " and ' symbols are used for the
representation of a character literal and a string literal respectively. Hence, to treat these
characters as a part of the string, they must be escaped with an additional backslash preceding
them.
Example
#include <stdio.h>
int main(){
printf("Welcome to \"TutorialsPoint\"\n");
printf ("\'Welcome\' to TutorialsPoint");
}
Output
Welcome to "TutorialsPoint"
'Welcome' to TutorialsPoint
The escape sequence "\b", represents the backspace character. It is used erase a character or a
specific portion of a text that has already been printed on the screen.
Example
#include <stdio.h>
int main(){
Welcome t TutorialsPoint
C also has a \r escape sequence. The newline escape sequence (\n) moves the cursor to the
beginning of the next line, while the carriage return escape sequence (\r) moves the cursor to the
beginning of the current line.
This escape sequence is used for Octal numbers of one to three digits. An octal escape sequence
is a backslash followed by one, two, or three octal digits (0-7). It matches a character in the
target sequence with the value specified by those digits.
Example
#include <stdio.h>
int main(){
printf("%c", '\141');
return 0;
}
Output
When you run this code, it will produce the following output −
A hexadecimal escape sequence is a backslash followed by the letter "x" followed by two
hexadecimal digits (0-9a-fA-F). It matches a character in the target sequence with the value
specified by the two digits.
Example
#include <stdio.h>
int main(){
printf("%c", '\x41');
return 0;
}
Output
The escape sequence \a represents the alert or bell character. When executed, it produces a sound
or visual alert depending on the terminal or console being used.
Example
#include <stdio.h>
int main(){
printf("Hello \a world\n");
return 0;
}
Output
Escape sequences are used widely in many other programming languages such as Java, PHP, C#,
etc.
Format Specifiers in C
Format specifiers in C are certain special symbols used in the formatted console IO functions
such as printf() and scanf(), as well as formatted file IO functions such as fprintf() and fscanf().
Format specifiers are formed of a predefined sequence of one or more alphanumeric characters
followed by the % symbol. For example, %d, %s, %f, %lf, etc. are some of the format specifiers
used in C.
The CPU performs IO operations with input and output devices in a streaming manner. The data
read from a standard input device (for example, a keyboard) through the standard input stream is
called stdin. Similarly the data sent to the standard output, which is the computer display screen,
through the standard output device is called stdout.
The computer receives data from the stream in a text form, however you may want to parse it in
variables of different data types such as int, float or a string. Similarly, the data stored in int, float
or char variables has to be sent to the output stream in a text format. Format specifier symbols
are used exactly for this purpose.
The printf() function is the most commonly used standard output function, defined in
the stdio.h header file. The prototype of printf() function is as follows −
The first argument of this function is a string that is interspersed with one or more format
specifiers. There may be one or more expressions as argument after the first. The compiler
substitutes each format specifier with the value of its successive expression. The resultant
formatted string is then passed to the output stream.
Example
In the following code, we have an int variable age and a float variable percent. The printf()
function prints the values of both as below −
#include <stdio.h>
int main(){
return 0;
}
Output
When you run the code, it will produce the following output −
Age: 18
Percent: 67.750000
The value of the first variable replaces the first format specifier %d. Similarly, %f is substituted
by the value of the percent variable.
Format specifiers are also used to parse the input stream into the variables of required type. The
following example highlights how it's done.
Example
In this example, the program asks the user to input age and percent values. They are stored in the
int and float variables, respectively.
#include <stdio.h>
int main(){
int age;
float percent;
printf("Enter Age and Percent: \n");
return 0;
}
Output
ANSI C defines a number of format specifiers. The following table lists the different specifiers
and their purpose −
%c Character
%d Signed integer
%f Float values
%g or %G Similar as %e or %E
%i Unsigned integer
%lf Double
%Lf Long double
%o Octal representation
%p Pointer
%s String
%u Unsigned int
%x or %X Hexadecimal representation
A minus symbol (−) tells left alignment.
A number after % specifies the minimum field width. If a string is less than the width, it
will be filled with spaces.
A period (.) is used to separate field width and precision.
C uses %d for signed integer, %i for unsigned integer, %ld or %li for long
integer, %o or %O for octal representation, and %x or %X for hexadecimal representation of
an integer.
Example
The following example highlights how integer format specifiers are used in C −
#include <stdio.h>
int main(){
Output
When you run this code, it will produce the following output −
Signed integer: 20
Unsigned integer: 20
Long integer: 20
Octal integer: 24
Hexadecimal integer: 14
Floating-point Formats
C uses the %f format specifier for single precision float number, %lf for double
precision, %Lf for long double number. To represent a floating point number in scientific
notation, C uses the %e or %E specifier symbol.
You can specify the width and the precision in the form of number of places after the decimal
point. For example, to state the width of number to 4 digits with 2 digits after the decimal point,
use the form %4.2f.
Example
#include <stdio.h>
int main(){
return 0;
}
Output
float: 5.347000
double: 5.347000
Scientific notation: 5.347000e+000
width and precision: 5.35
String Formats
The char data type in C is actually a subset of int data type. Hence, a char variable
with %c format specifier corresponds to the character in single quotes. On the other hand, if you
use the %d specifier, then the char variable will be formatted to its ASCII value.
In C, a string is an array of char data. To display an array of chars, C uses the %s specifier.
Example
#include <stdio.h>
int main(){
char ch = 'D';
char word[]="Hello World";
return 0;
Output
When you run this code, it will produce the following output −
As character: D
As its ASCII value: 68
String format: Hello World
The stdio.h library defines the functions fscanf() and fprintf() for formatted IO with disk files,
instead of standard input/output streams.
Example 1
The following code opens a file in write mode and saves the values of three variables in it.
#include <stdio.h>
int main(){
int x,y,z;
fclose(fp);
return 0;
}
Output
The fprintf() function uses the file represented by the file pointer fp to write the data.
The next example shows how you can open the same file in read mode to read the formatted
data.
Example 2
The following program reads back the data from the file by opening it in read mode.
#include <stdio.h>
int main(){
int x,y,z;
fclose(fp);
return 0;
}
Output
The fscanf() function reads the formatted input from fp which is the pointer to the file opened.
Here, you will get the following output −
10, 20, 30
Storage Classes in C
A storage class defines the scope (visibility) and lifetime of variables and/or functions within a
C Program. They precede the type that they modify.
auto
register
static
extern
The auto storage class is the default storage class for all local variables.
{
int mount;
auto int month;
}
The example above defines two variables with in the same storage class. 'auto' can only be used
within functions, i.e., local variables.
The register storage class is used to define local variables that should be stored in a register
instead of RAM. This means that the variable has a maximum size equal to the register size
(usually one word) and can't have the unary '&' operator applied to it (as it does not have a
memory location).
{
register int miles;
}
The register should only be used for variables that require quick access such as counters. It
should also be noted that defining 'register' does not mean that the variable will be stored in a
register. It means that it MIGHT be stored in a register depending on hardware and
implementation restrictions.
The static storage class instructs the compiler to keep a local variable in existence during the
life-time of the program instead of creating and destroying it each time it comes into and goes
out of scope. Therefore, making local variables static allows them to maintain their values
between function calls.
The static modifier may also be applied to global variables. When this is done, it causes that
variable's scope to be restricted to the file in which it is declared.
Example
In C programming, when static is used on a global variable, it causes only one copy of that
member to be shared by all the objects of its class. Look at the example below −
#include <stdio.h>
/* function declaration */
void func(void);
static int count = 5; /* global variable */
main(){
while(count--) {
func();
}
return 0;
}
/* function definition */
void func(void) {
Output
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0
The extern storage class is used to give a reference of a global variable that is visible to ALL the
program files. When you use 'extern', the variable cannot be initialized however, it points the
variable name at a storage location that has been previously defined.
When you have multiple files and you define a global variable or function, which will also be
used in other files, then extern will be used in another file to provide the reference of defined
variable or function. Just for understanding, extern is used to declare a global variable or
function in another file.
The extern modifier is most commonly used when there are two or more files sharing the same
global variables or functions as explained below.
#include <stdio.h>
int count;
extern void write_extern();
main(){
count = 5;
write_extern();
}
#include <stdio.h>
void write_extern(void) {
printf("Count is %d\n", count);
}
Here, extern is being used to declare count in the second file, whereas it has its definition in the
first file (main.c). Now, compile these two files as follows −
It will produce the executable program [Link]. When this program is executed, it will produce the
following output −
Count is 5
C - Operators
An operator is a symbol that tells the compiler to perform specific mathematical or logical
functions. By definition, an operator performs a certain operation on operands. An operator
needs one or more operands for the operation to be performed.
Depending on how many operands are required to perform the operation, operands are called as
unary, binary or ternary operators. They need one, two or three operands respectively.
C language is rich in built-in operators and provides the following types of operators −
Arithmetic Operators
Relational Operators
Logical Operators
Bitwise Operators
Assignment Operators
Misc Operators
We will, in this chapter, look into the way each operator works. Here, you will get an overview
of all these chapters. Thereafter, we have provided independent chapters on each of these
operators that contain plenty of examples to show how these operators work in C Programming.
Arithmetic Operators
We are most familiar with the arithmetic operators. These operators are used to perform
arithmetic operations on operands. The most common arithmetic operators are addition (+),
subtraction (-), multiplication (*), and division (/).
In addition, the modulo (%) is an important arithmetic operator that computes the remainder of a
division operation. Arithmetic operators are used in forming an arithmetic expression. These
operators are binary in nature in the sense they need two operands, and they operate on numeric
operands, which may be numeric literals, variables or expressions.
a+b
Here "+" is an arithmetic operator. We shall learn more about arithmetic operators in C in a
subsequent chapter.
The following table shows all the arithmetic operators supported by the C language. Assume
variable A holds 10 and variable B holds 20 then −
Show Examples
A+B=
+ Adds two operands.
30
A−B=
− Subtracts second operand from the first.
-10
A*B=
* Multiplies both operands.
200
Relational Operators
We are also acquainted with relational operators while learning secondary mathematics. These
operators are used to compare two operands and return a boolean value (true or false). They are
used in a boolean expression.
The most common relational operators are less than (<), greater than (>), less than or equal to
(<=), greater than or equal to (>=), equal to (==), and not equal to (!=). Relational operators are
also binary operators, needing two numeric operands.
a>b
We shall learn more about with relational operators and their usage in one of the following
chapters.
Show Examples
Operator Description Example
(A == B)
Checks if the values of two operands are equal
== is not
or not. If yes, then the condition becomes true.
true.
Logical Operators
These operators are used to combine two or more boolean expressions. We can form a compound
Boolean expression by combining Boolean expression with these operators. An example of
logical operator is as follows −
The most common logical operators are AND (&&), OR(||), and NOT (!). Logical operators are
also binary operators.
Show Examples
Bitwise Operators
Bitwise operators let you manipulate data stored in computer’s memory. These operators are
used to perform bit-level operations on operands.
The most common bitwise operators are AND (&), OR (|), XOR (^), NOT (~), left shift (<<),
and right shift (>>). Here the "~" operator is a unary operator, while most of the other bitwise
operators are binary in narure.
Bitwise operator works on bits and perform bit−by−bit operation. The truth tables for &, "|", and
"^" are as follows −
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
A = 0011 1100
B = 0000 1101
------------------------
~A = 1100 0011
The following table lists the bitwise operators supported by C. Assume variable 'A' holds 60 and
variable 'B' holds 13, then −
Show Examples
(A & B)
Binary AND Operator copies a bit to the result = 12,
&
if it exists in both operands. i.e., 0000
1100
(A | B) =
Binary OR Operator copies a bit if it exists in 61, i.e.,
|
either operand. 0011
1101
(A ^ B)
Binary XOR Operator copies the bit if it is set in = 49,
^
one operand but not both. i.e., 0011
0001
(~A ) =
Binary One's Complement Operator is unary ~(60),
~
and has the effect of 'flipping' bits. i.e,. -
0111101
A << 2 =
Binary Left Shift Operator. The left operands
240 i.e.,
<< value is moved left by the number of bits
1111
specified by the right operand.
0000
A >> 2 =
Binary Right Shift Operator. The left operands
15 i.e.,
>> value is moved right by the number of bits
0000
specified by the right operand.
1111
Assignment Operators
As the name suggests, an assignment operator "assigns" or sets a value to a named variable in C.
These operators are used to assign values to variables. The "=" symbol is defined as assignment
operator in C, however it is not to be confused with its usage in mathematics.
The following table lists the assignment operators supported by the C language −
Show Examples
C=A+
B will
Simple assignment operator. Assigns values assign the
=
from right side operands to left side operand value of
A + B to
C
C += A is
Add AND assignment operator. It adds the
equivalent
+= right operand to the left operand and assign the
to C = C
result to the left operand.
+A
C -= A is
Subtract AND assignment operator. It subtracts
equivalent
-= the right operand from the left operand and
to C = C -
assigns the result to the left operand.
A
C /= A is
Divide AND assignment operator. It divides the
equivalent
/= left operand with the right operand and assigns
to C = C /
the result to the left operand.
A
C %= A
Modulus AND assignment operator. It takes is
%= modulus using two operands and assigns the equivalent
result to the left operand. to C = C
%A
C <<= 2
is same as
<<= Left shift AND assignment operator.
C = C <<
2
C >>= 2
is same as
>>= Right shift AND assignment operator.
C = C >>
2
C &= 2 is
&= Bitwise AND assignment operator. same as C
=C&2
C ^= 2 is
^= Bitwise exclusive OR and assignment operator. same as C
=C^2
C |= 2 is
|= Bitwise inclusive OR and assignment operator. same as C
=C|2
Hence, the expression "a = 5" assigns 5 to the variable "a", but "5 = a" is an invalid expression in
C.
The "=" operator, combined with the other arithmetic, relational and bitwise operators form
augmented assignment operators. For example, the += operator is used as add and assign
operator. The most common assignment operators are =, +=, -=, *=, /=, %=, &=, |=, and ^=.
Besides the operators discussed above, there are a few other important operators
including sizeof and ? : supported by the C Language.
Show Examples
sizeof(a), where a is
sizeof() Returns the size of a variable.
integer, will return 4.
Operators Precedence in C
Operator precedence determines the grouping of terms in an expression and decides how an
expression is evaluated. Certain operators have higher precedence than others; for example, the
multiplication operator has a higher precedence than the addition operator.
For example, x = 7 + 3 * 2; here, x is assigned 13, not 20 because operator * has a higher
precedence than +, so it first gets multiplied with 3*2 and then adds into 7.
Here, operators with the highest precedence appear at the top of the table, those with the lowest
appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Show Examples
Other Operators in C
Apart from the above, there are a few other operators in C that are not classified into any of the
above categories. For example, the increment and decrement operators (++ and --) are unary in
nature and can appear as a prefix or postfix to the operand.
The operators that work with the address of memory location such as the address-of operator (&)
and the dereference operator (*). The sizeof operator (sizeof) appears to be a keyword but really
an operator.
C also has the type cast operator (()) that forces the type of an operand to be changed. C also uses
the dot (.) and the arrow (->) symbols as operators when dealing with derived data types such
as struct and union.
The C99 version of C introduced a few additional operators such as auto, decltype.
A single expression in C may have multiple operators of different type. The C compiler evaluates
its value based on the operator precedence and associativity of operators. For example, in the
following expression −
a+b*c
Many other programming languages, which are called C-family languages (such
as C++, C#, Java, Perl and PHP) have an operator nomenclature that is similar to C.
Arithmetic Operators in C
In addition to the above operations assigned to the four symbols +, −, *, and / respectively, C has
another arithmetic operator called the modulo operator for which we use the %symbol.
The following table lists the arithmetic operators in C −
Operator Description
The ++ and -- operators are also listed in the above table. We shall learn about increment and
decrement operators in a separate chapter.
The following example demonstrates how to use these arithmetic operators in a C program −
#include <stdio.h>
int main(){
return 0;
}
Output
When you run this code, it will produce the following output −
Operand1: 10 Operand2: 3
Type Casting in C
The first three results are as expected, but the result of division is not. You expect 10/3 to be a
fractional number (3.333333). Is it because we used the %d format specifier to print the outcome
of the division? If we change the last line of the code as follows −
Now the outcome of the division operation will be "0.000000", which is even more surprising.
The reason why C behaves like this is because the division of an integer with another integer
always returns an integer.
To obtain floating-point division, at least one operand must be a float, or you need to use the
typecast operator to change one of the integer operands to float.
Now, change the last printf statement of the given program as follows −
When you run run the code again after making this change, it will show the correct division −
Note: If you use %d format specifier for a floating-point expression, it will always result in "0".
Example
The result of arithmetic operations with at least one float (or double) operand is always float.
Take a look at the following example −
#include <stdio.h>
int main(){
return 0;
}
Output
In C, char data type is a subset of int type. Hence, we can perform arithmetic operations
with char operands.
Example
The following example shows how you can perform arithmetic operations with two operands out
of which one is a "char" type −
#include <stdio.h>
int main(){
return 0;
}
Output
operand1: F operand2: 3
Since a char data type is a subset of int, the %c format specifier returns the ASCII character
associated with an integer returned by the %d specifier.
If any arithmetic operation between two char operands results in an integer beyond the range of
char, the %c specifier displays blank.
Modulo Operator in C
Example
#include <stdio.h>
int main(){
int op1 = 10;
int op2 = 3;
return 0;
}
Output
Operand1: 10 Operand2: 3
Modulo of op1 and op2: 1
The modulo operator needs both the operands of int type. If not, the compiler gives a type
mismatch error. For example, change the data type of "op1" to float in the above code and run
the program again −
Now, you will get a type mismatch error with the following message −
Negation Operator in C
The increment and decrement operators represented by the symbols ++ and -- are unary
operators. They have been covered in a separate chapter. The "−" symbol, representing
subtraction operator, also acts a unary negation operator.
Example
The following example highlights how you can use the negation operator in C −
#include <stdio.h>
int main(){
int op1 = 5;
int op2 = -op1;
return 0;
}
Output
When you run this code, it will produce the following output −
Operand1: 5 Operand2: -5
In the above example, the "–" symbol returns the negative value of op1 and assigns the same to
op2.
Relational Operators in C
Relational operators in C are defined to perform comparison of two values. The familiar angular
brackets < and > are the relational operators in addition to a few more as listed in the table
below.
These relational operators are used in Boolean expressions. All the relational operators evaluate
to either True or False.
C doesn’t have a Boolean data type. Instead, "0" is interpreted as False and any non-zero value is
treated as True.
Example 1
#include <stdio.h>
int main(){
int op1 = 5;
int op2 = 3;
printf("op1: %d op2: %d op1 < op2: %d\n", op1, op2, op1 < op2);
return 0;
}
Output
Relational operators have an important role to play in decision-control and looping statements in
C.
We use the = symbol in C as the assignment operator. So, C uses the "==" (double equal) as
the equality operator.
The angular brackets > and < are used as the "greater than" and "less than" operators. When
combined with the "=" symbol, they form the ">=" operator for "greater than or equal" and "<="
operator for "less than or equal" comparison.
Finally, the "=" symbol prefixed with "!" (!=) is used as the inequality operator.
Example 2
#include <stdio.h>
int main(){
int a = 21;
int b = 10;
int c ;
if(a == b){
printf("Line 1 - a is equal to b\n" );
} else {
printf("Line 1 - a is not equal to b\n" );
}
if (a < b){
printf("Line 2 - a is less than b\n" );
} else {
printf("Line 2 - a is not less than b\n" );
}
if (a > b){
printf("Line 3 - a is greater than b\n" );
} else {
printf("Line 3 - a is not greater than b \n\n" );
}
if (a <= b){
printf("Line 4 - a is either less than or equal to b\n" );
}
if (b >= a){
printf("Line 5 - b is either greater than or equal to b\n" );
}
if(a != b){
printf("Line 6 - a is not equal to b\n" );
} else {
printf("Line 6 - a is equal to b\n" );
}
return 0;
}
Output
When you run this code, it will produce the following output −
a: 21 b: 10
Line 1 - a is not equal to b
Line 2 - a is not less than b
Line 3 - a is greater than b
a: 5 b: 20
Line 4 - a is either less than or equal to b
Line 5 - b is either greater than or equal to b
Line 6 - a is not equal to b
Example 3
The == operator needs to be used with care. Remember that "=" is the assignment operator in C.
If used by mistake in place of the equality operator, you get an incorrect output as follows −
#include <stdio.h>
int main(){
int a = 5;
int b = 3;
if (a = b){
printf("a is equal to b");
}
else {
printf("a is not equal to b");
}
return 0;
}
Output
The value of "b" is assigned to "a" which is non-zero, and hence the if expression returns true.
a is equal to b
Example 4
We can have "char" types too as the operand for all the relational operators, as the "char" type is
a subset of "int" type. Take a look at this example −
#include <stdio.h>
int main(){
char a = 'B';
char b = 'd';
if(a == b){
printf("Line 1 - a is equal to b \n");
} else {
printf("Line 1 - a is not equal to b \n");
}
if (a < b){
printf("Line 2 - a is less than b \n");
} else {
printf("Line 2 - a is not less than b \n");
}
if (a > b) {
printf("Line 3 - a is greater than b \n");
} else {
printf("Line 3 - a is not greater than b \n");
}
if(a != b) {
printf("Line 4 - a is not equal to b \n");
} else {
printf("Line 4 - a is equal to b \n");
}
return 0;
}
Output
Run the code and check its output −
a: B b: d
Line 1 - a is not equal to b
Line 2 - a is less than b
Line 3 - a is not greater than b
Line 4 - a is not equal to b
Relational operators cannot be used for comparing secondary types such as arrays or derived
types such as struct or union types.
Logical Operators in C
Logical operators in C evaluate to either True or False. Logical operators are typically used with
Boolean operands.
The logical AND operator (&&) and the logical OR operator (||) are both binary in nature
(require two operands). The logical NOT operator (!) is a unary operator.
Since C treats "0" as False and any non-zero number as True, any operand to a logical operand is
converted to a Boolean data.
The result of a logical operator follows the principle of Boolean algebra. The logical operators
follow the following truth tables.
Logical AND (&&) Operator
The && operator in C acts as the logical AND operator. It has the following truth table −
a b a&&b
The above truth table shows that the result of && is True only if both the operands are True.
C uses the double pipe symbol (||) as the logical OR operator. It has the following truth table −
a b a||b
The above truth table shows that the result of || operator is True when either of the operands is
True, and False if both operands are false.
The logical NOT ! operator negates the value of a Boolean operand. True becomes False, and
False becomes True. Here is its truth table −
A !a
True False
False True
Unlike the other two logical operators && and ||, the logical NOT operator ! is a unary operator.
Example 1
#include <stdio.h>
int main(){
int a = 5;
int b = 20;
if (a && b){
printf("Line 1 - Condition is true\n" );
}
if (a || b){
printf("Line 2 - Condition is true\n" );
}
if (a && b){
printf("Line 3 - Condition is true\n" );
} else {
printf("Line 3 - Condition is not true\n" );
}
return 0;
}
Output
Example 2
In C, a char type is a subset of int type. Hence, logical operators can work with char type too.
#include <stdio.h>
int main(){
char a = 'a';
char b = '\0'; // Null character
if (a && b){
printf("Line 1 - Condition is true\n" );
}
if (a || b){
printf("Line 2 - Condition is true\n" );
}
return 0;
}
Output
Logical operators are generally used to build a compound boolean expression. Along with
relational operators, logical operators too are used in decision-control and looping statements in
C.
Example 3
#include <stdio.h>
int main(){
return 0;
}
Output
Result:Pass
Example 4
The similar logic can also be expressed using the && operator as follows −
#include <stdio.h>
int main(){
return 0;
}
Output
Result: Pass
Example 5
#include <stdio.h>
int main(){
int i = 0;
return 0;
}
Output
In the above code, the while loop continues to iterate till the expression "!(i > 5)" becomes false,
which will be when the value of "i" becomes more than 5.
i=0
i=1
i=2
i=3
i=4
i=5
C has bitwise counterparts of the logical operators such as bitwise AND (&), bitwise OR (|), and
binary NOT or complement (~) operator.
Bitwise Operators in C
Bitwise operators contrast with logical operators in C. For example, the logical AND operator
(&&) performs AND operation on two Boolean expressions, while the bitwise AND operator
(&) performs the AND operation on each corresponding bit of the two operands.
For the three logical operators &&, ||, and !, the corresponding bitwise operators in C
are &, | and ~.
Additionally, the symbols ^ (XOR), << (left shift) and >> (right shift) are the other bitwise
operators.
The bitwise AND (&) operator performs as per the following truth table −
0 0 0
0 1 0
1 0 0
1 1 1
Bitwise binary AND performs logical operation on the bits in each position of a number in its
binary form.
Assuming that the two int variables "a" and "b" have the values 60 (equivalent to 0011 1100 in
binary) and 13 (equivalent to 0000 1101 in binary), the "a & b" operation results in 13, as per the
bitwise ANDing of their corresponding bits illustrated below −
0011 1100
& 0000 1101
---------
= 0000 1100
The bitwise OR (|) operator performs as per the following truth table −
0 0 0
0 1 1
1 0 1
1 1 1
Bitwise binary OR performs logical operation on the bits in each position of a number in its
binary form.
Assuming that the two int variables "a" and "b" have the values 60 (equivalent to 0011 1100 in
binary) and 13 (equivalent to 0000 1101 in binary), then "a | b" results in 61, as per the bitwise
OR of their corresponding bits illustrated below −
0011 1100
| 0000 1101
---------
= 0011 1101
The bitwise XOR (^) operator performs as per the following truth table −
0 0 0
0 1 1
1 0 1
1 1 0
Bitwise binary XOR performs logical operation on the bits in each position of a number in its
binary form. The XOR operation is called "exclusive OR".
Note: The result of XOR is 1 if and only if one of the operands is 1. Unlike OR, if both bits are
1, XOR results in 0.
Assuming that the two int variables "a" and "b" have the values 60 (equivalent to 0011 1100 in
binary) and 13 (equivalent to 0000 1101 in binary), the "a ^ b" operation results in 49, as per the
bitwise XOR of their corresponding bits illustrated below −
0011 1100
^ 0000 1101
---------
= 0011 0001
The left shift operator is represented by the << symbol. It shifts each bit in its left-hand operand
to the left by the number of positions indicated by the right-hand operand. Any blank spaces
generated while shifting are filled up by zeroes.
Assuming that the int variable "a" has the value 60 (equivalent to 0011 1100 in binary), the "a <<
2" operation results in 240, as per the bitwise left-shift of its corresponding bits illustrated below
−
The right shift operator is represented by the >> symbol. It shifts each bit in its left-hand operand
to the right by the number of positions indicated by the right-hand operand. Any blank spaces
generated while shifting are filled up by zeroes.
Assuming that the int variable a has the value 60 (equivalent to 0011 1100 in binary), the "a >>
2" operation results in 15, as per the bitwise right-shift of its corresponding bits illustrated below
−
The 1's compliment operator (~) in C is a unary operator, needing just one operand. It has the
effect of "flipping" the bits, which means 1s are replaced by 0s and vice versa.
a ~a
0 1
1 0
Assuming that the int variable "a" has the value 60 (equivalent to 0011 1100 in binary), then the
"~a" operation results in -61 in 2’s complement form, as per the bitwise right-shift of its
corresponding bits illustrated below −
Example
In this example, we have highlighted the operation of all the bitwise operators:
#include <stdio.h>
int main(){
c = a | b; /* 61 = 0011 1101 */
printf("Line 2 - Value of c is %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - Value of c is %d\n", c );
return 0;
}
Output
When you run this code, it will produce the following output −
Line 1 - Value of c is 12
Line 2 - Value of c is 61
Line 3 - Value of c is 49
Line 4 - Value of c is -61
Line 5 - Value of c is 240
Line 6 - Value of c is 15
Assignment Operators in C
In C language, the assignment operator stores a certain value in an already declared variable. A
variable in C can be assigned the value in the form of a literal, another variable, or an expression.
The value to be assigned forms the right-hand operand, whereas the variable to be assigned
should be the operand to the left of the "=" symbol, which is defined as a simple assignment
operator in C.
The following table lists the assignment operators supported by the C language −
C <<= 2 is same
<<= Left shift AND assignment operator.
as C = C << 2
C >>= 2 is same
>>= Right shift AND assignment operator.
as C = C >> 2
C &= 2 is same as
&= Bitwise AND assignment operator.
C=C&2
The = operator is one of the most frequently used operators in C. As per the ANSI C standard, all
the variables must be declared in the beginning. Variable declaration after the first processing
statement is not allowed.
You can declare a variable to be assigned a value later in the code, or you can initialize it at the
time of declaration.
You can use a literal, another variable, or an expression in the assignment statement.
Once a variable of a certain type is declared, it cannot be assigned a value of any other type. In
such a case the C compiler reports a type mismatch error.
In C, the expressions that refer to a memory location are called "lvalue" expressions. A lvalue
may appear as either the left-hand or right-hand side of an assignment.
On the other hand, the term rvalue refers to a data value that is stored at some address in
memory. A rvalue is an expression that cannot have a value assigned to it which means an rvalue
may appear on the right-hand side but not on the left-hand side of an assignment.
Variables are lvalues and so they may appear on the left-hand side of an assignment. Numeric
literals are rvalues and so they may not be assigned and cannot appear on the left-hand side. Take
a look at the following valid and invalid statements −
In addition to the = operator, C allows you to combine arithmetic and bitwise operators with
the = symbol to form augmented or compound assignment operator. The augmented operators
offer a convenient shortcut for combining arithmetic or bitwise operation with assignment.
Example 1
For example, the expression "a += b" has the same effect of performing "a + b" first and then
assigning the result back to the variable "a".
#include <stdio.h>
int main(){
int a = 10;
int b = 20;
a += b;
printf("a: %d", a);
return 0;
}
Output
Example 2
Similarly, the expression "a <<= b" has the same effect of performing "a << b" first and then
assigning the result back to the variable "a".
#include <stdio.h>
int main(){
int a = 60;
int b = 2;
a <<= b;
printf("a: %d", a);
return 0;
}
Output
a: 240
Example 3
#include <stdio.h>
int main(){
int a = 21;
int c ;
c = a;
printf("Line 1 - = Operator Example, Value of c = %d\n", c );
c += a;
printf("Line 2 - += Operator Example, Value of c = %d\n", c );
c -= a;
printf("Line 3 - -= Operator Example, Value of c = %d\n", c );
c *= a;
printf("Line 4 - *= Operator Example, Value of c = %d\n", c );
c /= a;
printf("Line 5 - /= Operator Example, Value of c = %d\n", c );
c = 200;
c %= a;
printf("Line 6 - %%= Operator Example, Value of c = %d\n", c );
c <<= 2;
printf("Line 7 - <<= Operator Example, Value of c = %d\n", c );
c >>= 2;
printf("Line 8 - >>= Operator Example, Value of c = %d\n", c );
c &= 2;
printf("Line 9 - &= Operator Example, Value of c = %d\n", c );
c ^= 2;
printf("Line 10 - ^= Operator Example, Value of c = %d\n", c );
c |= 2;
printf("Line 11 - |= Operator Example, Value of c = %d\n", c );
return 0;
}
Output
When you compile and execute the above program, it will produce the following result −
While most of the operators in C are binary in nature, there are a few unary operators as well. An
operator is said to be unary if it takes just a single operand, unlike a binary operator which needs
two operands.
Some operators in C are binary as well as unary in their usage. Examples of unary operators in C
include ++, --, !, etc.
The increment operator (++) adds 1 to the value of its operand variable and assigns it back to the
variable.
The statement a++ is equivalent to writing "a = a + 1." The "++" operator can appear before or
after the operand and it will have the same effect. Hence, a++ is equivalent to ++a.
However, when the increment operator appears along with other operators in an expression, its
effect is not the same. The precedence of "prefix ++" is more than "postfix ++". Hence, "b =
a++;" is not the same as "b = ++a;"
In the former case, "a" is assigned to "b" before the incrementation; while in the latter case, the
incrementation is performed before the assignment.
The decrement operator (--) subtracts 1 from the value of its operand variable and assigns it back
to the variable.
However, when the decrement operator appears along with other operators in an expression, its
effect is not the same. The precedence of "prefix --" is more than "postfix --". Hence, "b = a--" is
not the same as "b = --a".
In the former case, "a" is assigned to "b" before the decrementation; while in the latter case, the
decrementation is performed before the assignment.
The "+" and "–" operators are well known as binary addition and subtraction operators.
However, they can also be used in unary fashion. When used as unary, they are prefixed to the
operand variable.
The "+" operator is present implicitly whenever a positive value is assigned to any numeric
variable. The statement "int x = 5;" is same as "int x = +5;". The same logic applies to float and
char variable too.
Example
#include <stdio.h>
int main(){
char x = 'A';
char y = +x;
float a = 1.55;
float b = +a;
return 0;
}
Output
When you run this code, it will produce the following output −
x: A y: A
a: 1.550000 y: 1.550000
The "−" symbol, that normally represents the subtraction operator, also acts the unary negation
operator in C. The following code shows how you can use the unary negation operator in C.
Example
In this code, the unary negation operator returns the negative value of "x" and assigns the same
to another variable "y".
#include <stdio.h>
int main(){
int x = 5;
int y = -x;
return 0;
}
Output
x: 5 y: -5
We use the & symbol in C as the binary AND operator. However, we also use the
same & symbol in unary manner as the "address-of" operator.
Example
The & operator returns the memory address of its variable operand. Take a look at the following
example −
#include <stdio.h>
int main(){
char x = 'A';
printf ("Address of x: %d\n", &x);
return 0;
}
Output
Address of x: 6422047
Note: The C compiler assigns a random memory address whenever a variable is declared. Hence,
the result may vary every time the address is printed.
The format specifier %p is used to get a hexadecimal representation of the memory address.
char x = 'A';
printf ("Address of x: %p\n", &x);
Address of x: 000000000061FE1F
The address of a variable is usually stored in a "pointer variable". The pointer variable is
declared with a "*" prefix. In the code snippet below, "x" is a normal integer variable while "y"
is a pointer variable.
int x = 10;
int *y = &x;
We normally use the "*" symbol as the multiplication operator. However, it is also used as the
"dereference operator" in C.
When you want to store the memory address of a variable, the variable should be declared with
an asterisk (*) prefixed to it.
int x = 10;
int *y = &x;
Here the variable "y" stores the address of "x", hence "y" acts as a pointer to "x". To access the
value of "x" with the help of its pointer, use the dereference operator (*).
Example 1
#include <stdio.h>
int main(){
int x = 10;
int *y = &x;
return 0;
}
Output
x: 10 Address of x: 6422036
Value at x with Dereference: 10
Example 2
You can also assign a value to the original variable with the help of the dereference pointer −
#include <stdio.h>
int main(){
int x = 10;
int *y = &x;
*y = 20;
return 0;
}
Output
x: 10 Address of x: 6422036
x: 20 with dereference: 20
The logical NOT operator (!) in C negates the value of a Boolean operand. True becomes False
and False becomes True. The logical NOT operator (!) is a unary operator.
Example 1
#include <stdio.h>
int main(){
int a = 0;
int b = 20;
return 0;
}
Output
Example 2
#include <stdio.h>
int main(){
int i = 0;
return 0;
}
Output
In this code, the while loop continues to iterate till the expression "!(i > 5)" becomes False,
which will be when the value of "i" becomes more than 5.
i=0
i=1
i=2
i=3
i=4
i=5
a ~a
0 1
1 0
Assuming that the int variable "a" has the value 60 (equivalent to 0011 1100 in binary), the "~a"
operation results in -61 in 2’s complement form, as per the bitwise right-shift of its
corresponding bits.
Example
#include <stdio.h>
int main(){
return 0;
}
Output
When you run this code, it will produce the following output −
Value of c is -61
Increment and Decrement Operators in C
The increment operator (++) increments the value of a variable by 1, while the decrement
operator (--) decrements the value.
Increment and decrement operators are frequently used in the construction of counted loops in C
(with the for loop). They also have their application in the traversal of array and pointer
arithmetic.
The ++ and -- operators are unary and can be used as a prefix or posfix to a variable.
Syntax
int a = 5;
a++; // postfix increment
int b = 5;
++b; // prefix increment
int c = 5;
c--; // postfix decrement
int d = 5;
--d; // prefix decrement
In other words, "a++" has the same effect as "++a", as both the expressions increment the value
of variable "a" by 1. Similarly, "a--" has the same effect as "--a".
The expression "a++;" can be treated as the equivalent of the statement "a = a + 1;". Here, the
expression on the right adds 1 to "a" and the result is assigned back to 1, therby the value of "a"
is incremented by 1.
Example 1
#include <stdio.h>
int main(){
char a = 'a', b = 'M';
int x = 5, y = 23;
a++;
printf("postfix increment a: %c\n", a);
++b;
printf("prefix increment b: %c\n", b);
x--;
printf("postfix decrement x : %d\n", x);
--y;
printf("prefix decrement y : %d\n", y);
return 0;
}
Output
When you run this code, it will produce the following output −
a: a b: M
postfix increment a: b
prefix increment b: N
x: 5 y: 23
postfix decrement x: 4
prefix decrement y: 22
The above example shows that the prefix as well as postfix operators have the same effect on the
value of the operand variable. However, when these "++" or "--" operators appear along with the
other operators in an expression, they behave differently.
Example 2
In the following code, the initial values of "a" and "b" variables are same, but the printf()
statement displays different values −
#include <stdio.h>
int main(){
int x = 5, y = 5;
return 0;
}
Output
x: 5 y: 5
postfix increment x: 5
prefix increment y: 6
In the first case, the printf() function prints the value of "x" and then increments its value. In the
second case, the increment operator is executed first, the printf() function uses the incremented
value for printing.
Operator Precedence
There are a number of operators in C. When multiple operators are used in an expression, they
are executed as per their order of precedence. Increment and decrement operators behave
differently when used along with other operators.
When an expression consists of increment or decrement operators alongside other operators, the
increment and decrement operations are performed first. Postfix increment and decrement
operators have higher precedence than prefix increment and decrement operators.
Example 1
Take a look at the following example −
#include <stdio.h>
int main(){
int x = 5, z;
z = x++;
printf("x: %d z: %d\n", x, z);
return 0;
}
Output
x: 5
x: 6 z: 5
Since "x++" increments the value of "x" to 6, you would expect "z" to be 6 as well. However, the
result shows "z" as 5. This is because the assignment operator has a higher precedence over
postfix increment operator. Hence, the existing value of "x" is assigned to "z", before
incrementing "x".
Example 2
#include <stdio.h>
int main(){
int x = 5, y = 5, z;
return 0;
}
Output
When you run this code, it will produce the following output −
y: 5
y: 6 z: 6
The result may be confusing, as the value of "y" as well as "z" is now 6. The reason is that the
prefix increment operator has a higher precedence than the assignment operator. Hence, "y" is
incremented first and then its new value is assigned to "z".
The associativity of operators also plays an important part. For increment and decrement
operators, the associativity is from left to right. Hence, if there are multiple increment or
decrement operators in a single expression, the leftmost operator will be executed first, moving
rightward.
Example 3
In this example, the assignment expression contains both the prefix as well as postfix operators.
#include <stdio.h>
int main(){
int x = 5, y = 5, z;
z = x++ + ++y;
printf("x: %d y: %d z: %d\n", x,y,z);
return 0;
}
Output
Run the code and check its output −
x: 6 y:6 z: 11
In this example, the first operation to be done is "y++" ("y" becomes 6). Secondly the "+"
operator adds "x" (which is 5) and "y", the result assigned to "z" as 11, and then "x++"
increments "x" to 6.
Example
The looping body is executed for all the values of a variable between the initial and the final
values, incrementing it after each round.
#include <stdio.h>
int main(){
int x;
return 0;
}
Output
When you run this code, it will produce the following output −
x: 1
x: 2
x: 3
x: 4
x: 5
Pointer Arithmetic in C
In C language, a pointer is a variable that stores the address of another variable. The address is an
integer. A pointer variable can be used as an operand with increment or decrement operator.
However, unlike the normal int, float or char variable where the increment/decrement operator
changes the value by 1, in case of the pointer, its value is changed by the size of the data type.
Example
In this example, the pointer to an int variable increments by 4, as the size of int is 4. Similarly,
the size of char variable is 1, hence its pointer increments by 1.
#include <stdio.h>
int main(){
int x = 50;
int *ptr = &x;
ptr++;
printf("The address of x is: %d\n\n", ptr);
char y = 'a';
char *ptr1 = &y;
ptr1++;
printf("The address of y is: %d\n", ptr1);
return 0;
}
Output
When you run this code, it will produce the following output −
size of int: 4
The address of x is: 6422028
The address of x is: 6422032
size of char: 1
The address of y is: 6422027
The address of y is: 6422028
Ternary Operator in C
The ternary operator (?:) in C is a type of conditional operator. The term "ternary" implies that
the operator has three operands. The ternary operator is often used to put multiple conditional (if-
else) statements in a more compact manner.
The following C program uses the ternary operator to check if the value of a variable is even or
odd.
#include <stdio.h>
int main(){
int a = 10;
(a % 2 == 0) ? printf("%d is Even \n", a) : printf("%d is Odd \n", a);
return 0;
}
Output
When you run this code, it will produce the following output −
10 is Even
Change the value of "a" to 15 and run the code again. Now you will get the following output −
15 is Odd
Example 2
The conditional operator is a compact representation of if–else construct. We can rewrite the
logic of checking the odd/even number by the following code −
#include <stdio.h>
int main(){
int a = 10;
if (a % 2 == 0){
printf("%d is Even\n", a);
}
else{
printf("%d is Odd\n", a);
}
return 0;
}
Output
Example 3
The following program compares the two variables "a" and "b", and assigns the one with the
greater value to the variable "c".
#include <stdio.h>
int main(){
c = (a >= b) ? a : b;
return 0;
}
Output
When you run this code, it will produce the following output −
a: 100 b: 20 c: 100
Example 4
#include <stdio.h>
int main(){
if (a >= b){
c = a;
}
else {
c = b;
}
printf ("a: %d b: %d c: %d\n", a, b, c);
return 0;
}
Output
a: 100 b: 20 c: 100
Example 5
If you need to put multiple statements in the true and/or false operand of the ternary operator,
you must separate them by commas, as shown below −
#include <stdio.h>
int main(){
return 0;
}
Output
In this code, the greater number is assigned to "c", along with printing the appropriate message.
a is larger a: 100 b: 20 c: 20
Example 6
The corresponding program with the use of if–else statements is as follows −
#include <stdio.h>
int main(){
return 0;
}
Output
a is larger
a: 100 b: 20 c: 100
Just as we can use nested if-else statements, we can use the ternary operator inside the True
operand as well as the False operand.
First C checks if expr1 is true. If so, it checks expr2. If it is true, the result is expr3; if false, the
result is expr4.
If expr1 turns false, it may check if expr5 is true and return expr6 or expr7.
Example 1
#include <stdio.h>
int main(){
int a = 15;
printf("a: %d\n", a);
(a % 2 == 0) ? (
(a%3 == 0)? printf("divisible by 2 and 3") : printf("divisible by 2 but not 3"))
:(
(a%3 == 0)? printf("divisible by 3 but not 2") : printf("not divisible by 2, not divisible by 3")
);
return 0;
}
Output
a: 15
divisible by 3 but not 2
a: 16
divisible by 2 but not 3
a: 17
not divisible by 2, not divisible by 3
a: 18
divisible by 2 and 3
Example 2
In this program, we have used nested if–else statements for the same purpose instead of
conditional operators −
#include <stdio.h>
int main(){
int a = 15;
printf("a: %d\n", a);
if(a % 2 == 0){
if (a % 3 == 0){
printf("divisible by 2 and 3");
}
else {
printf("divisible by 2 but not 3");
}
}
else{
if(a % 3 == 0){
printf("divisible by 3 but not 2");
}
else {
printf("not divisible by 2, not divisible by 3");
}
}
return 0;
}
Output
When you run this code, it will produce the following output −
a: 15
divisible by 3 but not 2
C - The sizeof Operator
The sizeof operator is a compile−time unary operator. It is used to compute the size of its
operand, which may be a data type or a variable. It returns the size in number of bytes.
It can be applied to any data type, float type, or pointer type variables.
sizeof(type or var);
When sizeof() is used with a data type, it simply returns the amount of memory allocated to that
data type. The outputs can be different on different machines, for example, a 32-bit system can
show a different output as compared to a 64-bit system.
Take a look at the following example. It highlights how you can use the sizeof operator in a C
program −
#include <stdio.h>
int main(){
int a = 16;
return 0;
}
Output
Size of variable a: 4
Size of int data type: 4
Size of char data type: 1
Size of float data type: 4
Size of double data type: 8
In this example, we declare a struct type and find the size of the struct type variable.
#include <stdio.h>
struct employee {
char name[10];
int age;
double percent;
};
int main(){
struct employee e1 = {"Raghav", 25, 78.90};
printf("Size of employee variable: %d\n",sizeof(e1));
return 0;
}
Output
In the following code, we have declared an array of 10 int values. Applying the sizeof operator
on the array variable returns 40. This is because the size of an int is 4 bytes.
#include <stdio.h>
int main(){
Output
Run the code and check its output −
Size of arr: 40
In C, we don’t have a function that returns the number of elements in a numeric array (we can
get the number of characters in a string using the strlen() function). For this purpose, we can use
the sizeof() operator.
We first find the size of the array and then divide it by the size of its data type.
#include <stdio.h>
int main(){
Output
When you run this code, it will produce the following output −
No of elements in arr: 10
The sizeof operator is used to compute the memory block to be dynamically allocated with
the malloc() and calloc() functions.
The following statement allocates a block of 10 integers and stores its address in the pointer −
#include <stdio.h>
int main(){
char a = 'S';
double b = 4.65;
int s = (int)(a+b);
printf("Size of explicitly converted expression: %d\n",sizeof(s));
return 0;
}
Output
Size of variable a: 1
Size of an expression: 8
Size of explicitly converted expression: 4
The sizeof() operator returns the same value irrespective of the type. This includes the pointer of
a built−in type, a derived type, or a double pointer.
#include <stdio.h>
int main(){
Output
Operator Precedence in C
A single expression in C may have multiple operators of different types. The C compiler
evaluates its value based on the operator precedence and associativity of operators.
The precedence of operators determines the order in which they are evaluated in an expression.
Operators with higher precedence are evaluated first.
x = 7 + 3 * 2;
Here, the multiplication operator "*" has a higher precedence than the addition operator "+". So,
the multiplication 3*2 is performed first and then adds into 7, resulting in "x = 13".
The following table lists the order of precedence of operators in C. Here, operators with the
highest precedence appear at the top of the table, and those with the lowest appear at the bottom.
Operator Associativity
In C, the associativity of operators refers to the direction (left to right or right to left) an
expression is evaluated within a program. Operator associativity is used when two operators of
the same precedence appear in an expression.
15 / 5 * 2
Both the "/" (division) and "*" (multiplication) operators have the same precedence, so the order
of evaluation will be decided by associativity.
As per the above table, the associativity of the multiplicative operators is from Left to Right. So,
the expression is evaluated as −
(15 / 5) * 2
It evaluates to −
3*2=6
Example 1
In the following code, the multiplication and division operators have higher precedence than the
addition operator.
The left−to−right associativity of multiplicative operator results in multiplication of "b" and "c"
divided by "e". The result then adds up to the value of "a".
#include <stdio.h>
int main(){
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = a + b * c / d;
printf("e : %d\n" , e );
return 0;
}
Output
When you run this code, it will produce the following output −
e: 50
Example 2
We can use parenthesis to change the order of evaluation. Parenthesis () got the highest priority
among all the C operators.
#include <stdio.h>
int main(){
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * c / d;
printf("e: %d\n", e);
return 0;
}
Output
e: 90
In this expression, the addition of a and b in parenthesis is first. The result is multiplied by c and
then the division by d takes place.
Example 3
In the expression that calculates e, we have placed a+b in one parenthesis, and c/d in another,
multiplying the result of the two.
#include <stdio.h>
int main(){
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * (c / d);
printf("e: %d\n", e );
return 0;
}
Output
e: 90
The "++" and "− −" operators act as increment and decrement operators, respectively. They are
unary in nature and can be used as a prefix or postfix to a variable.
When used as a standalone, using these operators in a prefix or post−fix manner has the same
effect. In other words, "a++" has the same effect as "++a". However, when these "++" or "− −"
operators appear along with other operators in an expression, they behave differently.
Postfix increment and decrement operators have higher precedence than prefix increment and
decrement operators.
Example
The following example shows how you can use the increment and decrement operators in a C
program −
#include <stdio.h>
int main(){
int x = 5, y = 5, z;
printf("x: %d \n", x);
z = x++;
printf("Postfix increment: x: %d z: %d\n", x, z);
z = ++y;
printf("Prefix increment. y: %d z: %d\n", y ,z);
return 0;
}
Output
x: 5
Postfix increment: x: 6 z: 5
Prefix increment. y: 6 z: 6
Logical operators have left−to−right associativity. However, the compiler evaluates the least
number of operands needed to determine the result of the expression. As a result, some operands
of the expression may not be evaluated.
Here the second operand "y > 50" is evaluated only if the first expression evaluates to True.
C - Misc Operators
Besides the main categories of operators (arithmetic, logical, assignment, etc.), C uses the
following operators that are equally important. Let us discuss the operators classified under this
category.
The "&" symbol, already defined in C as the Binary AND Operator copies a bit to the result if
it exists in both operands. The "&" symbol is also defined as the address−of operator.
The "*" symbol − A well−known arithmetic operator for multiplication, it can also be used as
a dereference operator.
C uses the ">" symbol, defined as a ternary operator, used to evaluate a conditional expression.
In C, the dot "." symbol is used as the member access operator in connection with a struct or
union type.
C also uses the arrow "→" symbol as an indirection operator, used especially with the pointer to
the struct variable.
The sizeof operator is a compile−time unary operator. It is used to compute the size of its
operand, which may be a data type or a variable. It returns the size in number of bytes. It can be
applied to any data type, float type, or pointer type variables.
sizeof(type or var);
When sizeof() is used with the data types, it simply returns the amount of memory allocated to
that data type. The output can be different on different machines like a 32−bit system can show
different output while a 64−bit system can show different of the same data types.
Example
#include <stdio.h>
int main(){
int a = 16;
return 0;
}
Output
When you run this code, it will produce the following output −
Size of variable a: 4
Size of int data type: 4
Size of char data type: 1
Size of float data type: 4
Size of double data type: 8
Address-of Operator in C
The "&" operator returns the address of an existing variable. We can assign it to a pointer
variable −
int a;
Assuming that the compiler creates the variable at the address 1000 and "x" at the address 2000,
then the address of "a" is stored in "x".
Example
Let us understand this with the help of an example. Here, we have declared an int variable. Then,
we print its value and address −
#include <stdio.h>
int main(){
return 0;
}
Output
type *var;
The name of the variable must be prefixed with an asterisk (*). The data type indicates it can
store the address of which data type. For example −
int *x;
In this case, the variable x is meant to store the address of another int variable.
float *y;
The "y" variable is a pointer that stores the memory location of a float variable.
The "&" operator returns the address of an existing variable. We can assign it to the pointer
variable −
int a;
int *x = &a;
We can see that the address of this variable (any type of variable for that matter) is an integer.
So, if we try to store it in a pointer variable of int type, see what happens −
The compiler doesn’t accept this, and reports the following error −
initialization of 'int *' from incompatible pointer type 'float *' [-Wincompatible-pointer-types]
It indicates that the type of a variable and the type of its pointer must be the same.
In C, variables have specific data types that define their size and how they store values.
Declaring a pointer with a matching type (e.g., "float *") enforces type compatibility between
the pointer and the data it points to.
Different data types occupy different amounts of memory in C. For example, an int typically
takes 4 bytes, while a float might take 4 or 8 bytes depending on the system.
Adding or subtracting integers from pointers moves them in memory based on the size of the
data they point to.
Example 1
#include <stdio.h>
int main(){
return 0;
}
Output
var1: 10.550000
address of var1: 6422044
floatptr: 6422044
address of floatptr: 6422032
Example 2
The * operator is called the Dereference operator. It returns the value stored in the address which
is stored in the pointer, i.e., the value of the variable it is pointing to. Take a look at the following
example −
#include <stdio.h>
int main(){
return 0;
}
Output
In C language, the "?" character is used as the ternary operator. It is also known as a conditional
operator.
The term "ternary" implies that the operator has three operands. The ternary operator is often
used to put conditional (if−else) statements in a compact way.
Example
The following C program uses the ? operator to check if the value of a is even or odd.
#include <stdio.h>
int main(){
int a = 10;
(a % 2==0) ? printf("%d is Even\n", a) : printf("%d is Odd\n", a);
return 0;
}
Output
10 is Even
Change the value of "a" to 15 and run the code again. Now you will get the following output −
15 is Odd
In C language, you can define a derived data type with struct and union keywords. A derived or
user−defined data type that groups together member elements of different types.
The dot operator is a member selection operator, when used with the struct or union variable.
The dot (.) operator has the highest operator precedence in C Language and its associativity is
from left to right.
[Link];
Here, var is a variable of a certain struct or a union type, and member is one of the elements
defined while creating structure or union.
A new derived data type is defined with struct keyword as following syntax −
struct newtype {
type elem1;
type elem2;
type elem3;
...
...
};
var.elem1;
Example
Let us declare a struct type named book, declare a struct variable. The following example shows
the use of "." operator to access the members in the book structure.
#include <stdio.h>
struct book{
char title[10];
double price;
int pages;
};
int main(){
Output
Title: Learn C
Price: 675.500000
No of Pages: 325
size of book struct: 32
A structure is a derived data type in C. In C, the struct keyword has been provided to define a
custom data type.
A new derived data type is defined with a struct keyword as the following syntax −
struct type {
type var1;
type var2;
type var3;
...
...
};
Usually, a struct is declared before the first function is defined in the program, after the include
statements. That way, the derived type can be used for declaring its variable inside any function.
struct book {
char title[10];
double price;
int pages;
};
To declare a variable of this type, use the following syntax −
The initialization of a struct variable is done by placing value of each element inside curly
brackets.
You can also store the address of a struct variable in the struct pointer variable.
strptr = &b1;
C defines the arrow (→) symbol to be used with struct pointer as indirection operator (also called
struct dereference operator). It helps to access the elements of the struct variable to which the
pointer reference to.
Example
In this example, strptr is a pointer to struct book b1 variable. Hence, strrptr−>title returns the
title, similar to [Link] does.
#include <stdio.h>
#include <string.h>
struct book {
char title[10];
double price;
int pages;
};
int main() {
struct book b1 = {"Learn C", 675.50, 325};
struct book *strptr;
strptr = &b1;
printf("Title: %s\n", strptr->title);
printf("Price: %lf\n", strptr->price);
printf("No of Pages: %d\n", strptr->pages);
return 0;
}
Output
Title: Learn C
Price: 675.500000
No of Pages: 325
C - Decision Making
Sequential logic
Decision or branching
Repetition or iteration
A computer program is sequential in nature and runs from top to bottom by default. The
decision-making statements in C provide an alternative line of execution. You can ask a group of
statements to be repeatedly executed till a condition is satisfied.
The decision-making structures control the program flow based on conditions. They are
important tools for designing complex algorithms.
In programming, we come across situations when we need to make some decisions. Based on
these decisions, we decide what should we do next. Similar situations arise in algorithms too
where we need to make some decisions and based on these decisions, we will execute the next
block of code.
The next instruction depends on a Boolean expression, whether the condition is determined to be
True or False. C programming language assumes any non-zero and non-null values as True, and
if it is either zero or null, then it is assumed as a False value.
if statement
1 An if statement consists of a boolean expression followed by
one or more statements.
if...else statement
2 An if statement can be followed by an optional else statement,
which executes when the Boolean expression is false.
nested if statements
3 You can use one if or else-if statement inside another if or else-
if statement(s).
switch statement
4 A switch statement allows a variable to be tested for equality
against a list of values.
If Statement in C Programming
The if statement is used for deciding between two paths based on a True or False outcome. It is
represented by the following flowchart −
Syntax
if (Boolean expr){
expression;
...
}
The if–else statement offers an alternative path when the condition isn't met.
Syntax
if (Boolean expr){
expression;
...
}
else{
expression;
...
}
An if statement can be followed by an optional else statement, which executes when the Boolean
expression is false.
Nested if statements are required to build intricate decision trees, evaluating multiple nested
conditions for nuanced program flow.
You can use one if or else-if statement inside another if or else-if statement(s).
A switch statement simplifies multi-way choices by evaluating a single variable against multiple
values, executing specific code based on the match. It allows a variable to be tested for equality
against a list of values.
Syntax
switch(expression) {
case constant-expression :
statement(s);
break; /* optional */
case constant-expression :
statement(s);
break; /* optional */
As in if statements, you can use one switch statement inside another switch statement(s).
The ?: Operator in C Programming
We have covered the conditional operator (?:) in the previous chapter which can be used to
replace if-else statements. It condenses an if-else statement into a single expression, offering
compact and readable code.
Where Exp1, Exp2, and Exp3 are expressions. Notice the use and placement of the colon (:). The
value of a "?" expression is determined like this −
Exp1 is evaluated. If it is true, then Exp2 is evaluated and becomes the value of the entire ?
expression.
If Exp1 is false, then Exp3 is evaluated and its value becomes the value of the : expression.
You can simulate nested if statements with the ? operator. You can use another ternary operator
in true and/or false operand of an existing ? operator.
An algorithm can also have an iteration logic. In C, the while, do–while and for statements are
provided to form loops.
The loop formed by while and do–while are conditional loops, whereas the for statement forms
a counted loop.
The loops are also controlled by the Boolean expressions. The C compiler decides whether the
looping block is to be repeated again, based on a condition.
In C, the break statement is used in switch–case constructs as well as in loops. When used inside
a loop, it causes the repetition to be abandoned.
The Continue Statement in C Programming
In C, the continue statement causes the conditional test and increment portions of the loop to
execute.
goto label;
..
.
label: statement;
With the goto statement, the flow can be directed to any previous step or any subsequent step.
C - The If Statement
Syntax of if Statement
if(boolean_expression) {
/* statement(s) will execute if the boolean expression is true */
}
C uses a pair of curly brackets to form a code block. If the Boolean expression evaluates to true,
then the block of code inside the if statement will be executed.
If the Boolean expression evaluates to false, then the first set of code after the end of
the if statement (after the closing curly brace) will be executed.
C programming treats any non-zero and non-null values as true. And if the values are either zero
or null, then they are treated as false values.
Flowchart of if Statement
When the program control comes across the if statement, the condition is evaluated.
If the condition is true, the statements inside the if block are executed.
If the condition is false, the program flow bypasses the conditional block.
Statements after the if block are executed to continue the program flow.
#include <stdio.h>
Output
Value of a is : 12
a is less than 20
Now assign a number greater than 20. The if condition is not executed.
Value of a is: 40
In the following example, three variables "a", "b" and "c" are compared. The if block will be
executed when "a" is greater than both "b" and "c".
#include <stdio.h>
int main () {
return 0;
}
Output
Note that the statement following the conditional block is executed after the block is executed. If
the condition is false, the program jumps directly to the statement after the block.
In this example, the net payable amount is calculated by applying discount on the bill amount.
The discount applicable is 5 percent if the amount is between 1000 to 5000, and 10 percent if the
amount is above 5000. No discount is applicable for purchases below 1000.
#include <stdio.h>
int main () {
Output
In this program, a student is declared as passed only if the average of "phy" and "maths" marks
is greater than equal to 50. Also, the student should have secured more than 35 marks in both the
subjects. Otherwise, the student is declared as failed.
#include <stdio.h>
if (avg<50) {
printf("Result: Fail\n");
}
return 0;
}
Output
C allows an optional else keyword to specify the statements to be executed if the if condition is
false. For representation of more complex algorithms, you can have nested if–else constructs in a
C program.
The if-else statement is one of the frequently used decision-making statements in C. The if-
else statement offers an alternative path when the condition isn't met.
The else keyword helps you to provide an alternative course of action to be taken when the
Boolean expression in the if statement turns out to be false. The use of else keyword is optional;
it's up to you whether you want to use it or not.
The C compiler evaluates the condition, and executes a statement or a block of statements
following the if statement if it is true.
If the programming logic needs the computer to execute some other instructions when the
condition is false, they are put as a part of the else clause.
if (Boolean expr){
Expression;
...
}
else{
Expression;
...
}
An if statement is followed by an optional else statement, which executes when the Boolean
expression is false.
if (marks<50)
printf("Result: Fail\n");
else
printf("Result: Pass\n");
However, when there are more than one statements, either in the if or in the else part, you need to
tell the compiler that they need to be treated as a compound statement.
Example 1
Consider the following code. It intends to calculate the discount at 10% if the amount is greater
than 100, and no discount otherwise.
#include <stdio.h>
int main() {
int amount = 50;
float discount;
printf("Amount: %d\n", amount);
return 0;
}
Output
Example 2
#include <stdio.h>
int main() {
int amount = 50;
float discount, nett;
printf("Amount: %d\n", amount);
if (amount<100)
printf("Discount not applicable\n");
else
printf("Discount applicable");
discount = amount*10/100;
nett = amount - discount;
printf("Discount: %f Net payable: %f", discount, nett);
return 0;
}
Output
The code doesn’t give any compiler error, but gives incorrect output −
Amount: 50
Discount not applicable
Discount: 5.000000 Net payable: 45.000000
It produces an incorrect output because the compiler assumes that there is only one statement in
the else clause, and the rest of the statements are unconditional.
The above two code examples emphasize the fact that when there are more than one statements
in the if or else else, they must be put in curly brackets.
To be safe, it is always better to use curly brackets even for a single statement. In fact, it
improves the readability of the code.
Example 3
In the code given below, the tax on employee’s income is computed. If the income is below
10000, the tax is applicable at 10%. For the income above 10000, the excess income is charged
at 15%.
#include <stdio.h>
int main() {
int income = 5000;
float tax;
printf("Income: %d\n", income);
if (income<10000){
tax = (float)(income * 10 / 100);
printf("tax: %f \n", tax);
}
else {
tax= (float)(1000 + (income-10000) * 15 / 100);
printf("tax: %f", tax);
}
}
Output
Set the income variable to 15000, and run the program again.
Income: 15000
tax: 1750.000000
Example 4
The following program checks if a char variable stores a digit or a non-digit character.
#include <stdio.h>
int main() {
char ch='7';
Output
Assign any other character such as "*" to "ch" and see the result.
C also allows you to use else-if in the programs. Let's see where you may have to use an else-
if clause.
Let's suppose you have a situation like this. If a condition is true, run the given block that
follows. If it isn't, run the next block instead. However, if none of the above is true and all else
fails, finally run another block. In such cases, you would use an else-if clause.
if (condition){
// if the condition is true,
// then run this code
} else if(another_condition){
// if the above condition was false
// and this condition is true,
// then run the code in this block
} else{
// if both the above conditions are false,
// then run this code
}
#include <stdio.h>
int main(void) {
int age = 15;
Now, supply a different value for the variable "age" and run the code again. You will get a
different output if the supplied value is less than 18.
C - Nested If Statements
It is always legal in C programming to nest if-else statements, which means you can use
one if or else-if statement inside another if or else-if statement(s).
In the programming context, the term "nesting" refers to enclosing a particular programming
element inside another similar element. For example, nested loops, nested structures, nested
conditional statements, etc. If an if statement in C is employed inside another if statement, then
we call it as a nested if statement in C.
Syntax
if (expr1){
if (expr2){
block to be executed when
expr1 and expr2 are true
}
else{
block to be executed when
expr1 is true but expr2 is false
}
}
Another if statement can appear inside a top-level if block, or its else block, or inside both.
Example 1
Let us take an example, where the program needs to determine if a given number is less than
100, between 100 to 200, or above 200. We can express this logic with the following compound
Boolean expression −
#include <stdio.h>
if (a >= 200){
printf("Value of a is more than 200\n" );
}
}
Output
Run the code and check its output. Here, we have intialized the value of "a" as 274. Change this
value and run the code again. If the supplied value is less than 100, then you will get a different
output. Similarly, the output will change again if the supplied number is in between 100 and 200.
Value of a is : 274
Value of a is more than 200
Example 2
Now let's use nested conditions for the same problem. It will make the solution more
understandable when we use nested conditions.
First, check if "a >= 100". Inside the true part of the if statement, check if it is <200 to decide if
the number lies between 100-200, or it is >200. If the first condition (a >= 100) is false, it
indicates that the number is less than 100.
#include <stdio.h>
return 0;
}
Output
Run the code and check its output. You will get different outputs for different input values of "a"
−
Value of a is : 120
Value of a is between 100 and 200
Example 3
The following program uses nested if statements to determine if a number is divisible by 2 and 3,
divisible by 2 but not 3, divisible by 3 but not 2, and not divisible by both 2 and 3.
#include <stdio.h>
int main(){
int a = 15;
printf("a: %d\n", a);
if (a % 2 == 0) {
if (a % 3 == 0){
printf("Divisible by 2 and 3");
}
else {
printf("Divisible by 2 but not 3");
}
}
else {
if (a % 3 == 0){
printf("Divisible by 3 but not 2");
}
else{
printf("Not divisible by 2, not divisible by 3");
}
}
return 0;
}
Output
a: 15
Divisible by 3 but not 2
Example 4
Given below is a C program to check if a given year is a leap year or not. Whether the year is a
leap year or not is determined by the following rules −
#include <stdio.h>
int main(){
// Test the program with the values 1900, 2023, 2000, 2012
int year = 1900;
printf("year: %d\n", year);
// is divisible by 4?
if (year % 4 == 0){
// is divisible by 100?
if (year % 100 == 0){
// is divisible by 400?
if(year % 400 == 0){
printf("%d is a Leap Year\n", year);
}
else{
printf("%d is not a Leap Year\n", year);
}
}
else{
printf("%d is not a Leap Year\n", year);
}
}
else{
printf("%d is a Leap Year\n", year);
}
}
Output
Run the code and check its output −
year: 1900
1900 is not a Leap Year
Test the program with different values for the variable "year" such as 1900, 2023, 2000, 2012.
The same result can be achieved by using the compound Boolean expressions instead of nested if
statements, as shown below −
A switch statement allows a variable to be tested for equality against a list of values. Each value
is called a case, and the variable being switched on is checked for each switch case.
C switch-case Statement
The flow of the program can switch the line execution to a branch that satisfies a given case. The
schematic representation of the usage of switch-case construct is as follows −
switch (Expression){
The parenthesis in front of the switch keyword holds an expression. The expression should
evaluate to an integer or a character. Inside the curly brackets after the parenthesis, different
possible values of the expression form the case labels.
One or more statements after a colon(:) in front of the case label forms a block to be executed
when the expression equals the value of the label.
You can literally translate a switch-case as "in case the expression equals value1, execute the
block1", and so on.
C checks the expression with each label value, and executes the block in front of the first match.
Each case block has a break as the last statement. The break statement takes the control out of
the scope of the switch construct.
You can also define a default case as the last option in the switch construct. The default case
block is executed when the expression doesn’t match with any of the earlier case values.
The expression used in a switch statement must have an integral or enumerated type, or be
of a class type in which the class has a single conversion function to an integral or
enumerated type.
You can have any number of case statements within a switch. Each case is followed by the
value to be compared to and a colon.
The constant-expression for a case must be the same data type as the variable in the switch,
and it must be a constant or a literal.
When the variable being switched on is equal to a case, the statements following that case
will execute until a break statement is reached.
When a break statement is reached, the switch terminates, and the flow of control jumps to
the next line following the switch statement.
Not every case needs to contain a break. If no break appears, the flow of control will fall
through to subsequent cases until a break is reached.
A switch statement can have an optional default case, which must appear at the end of the
switch. The default case can be used for performing a task when none of the cases is true.
No break is needed in the default case.
Example 1
In the following code, a series of if-else statements print three different greeting messages based
on the value of a "ch" variable ("m", "a" or "e" for morning, afternoon or evening).
#include <stdio.h>
int main(){
if (ch == 'm')
printf("Good Morning");
return 0;
}
The if-else logic in the above code is replaced by the switch-case construct in the code below −
#include <stdio.h>
switch (ch){
case 'a':
printf("Good Afternoon\n");
break;
case 'e':
printf("Good Evening\n");
break;
case 'm':
printf("Good Morning\n");
}
return 0;
}
Output
Change the value of "ch" variable and check the output. For ch = 'm', we get the following output
−
Time code: m
Good Morning
The use of break is very important here. The block of statements corresponding to each case
ends with a break statement. What if the break statement is not used?
The switch-case works like this: As the program enters the switch construct, it starts comparing
the value of switching expression with the cases, and executes the block of its first match.
The break causes the control to go out of the switch scope. If break is not found, the subsequent
block also gets executed, leading to incorrect result.
Example 2
Let us comment out all the break statements in the above code.
#include <stdio.h>
int main (){
switch (ch){
case 'a':
printf("Good Afternoon\n");
// break;
case 'e':
printf("Good Evening\n");
// break;
case 'm':
printf("Good Morning\n");
}
return 0;
}
Output
You expect the "Good Morning" message to be printed, but you find all the three messages
printed!
Time code: a
Good Afternoon
Good Evening
Good Morning
This is because C falls through the subsequent case blocks in the absence of break statements at
the end of the blocks.
Example 3
In the following program, "grade" is the switching variable. For different cases of grades, the
corresponding result messages will be printed.
#include <stdio.h>
int main(){
switch(grade){
case 'A' :
printf("Outstanding!\n" );
break;
case 'B':
printf("Excellent!\n");
break;
case 'C':
printf("Well Done\n" );
break;
case 'D':
printf("You passed\n" );
break;
case 'F':
printf("Better try again\n" );
break;
default :
printf("Invalid grade\n" );
}
printf("Your grade is %c\n", grade);
return 0;
}
Output
Now change the value of "grade" (it is a "char" variable) and check the outputs.
Example 4
The following example displays a menu for arithmetic operations. Based on the value of the
operator code (1, 2, 3, or 4), addition, subtraction, multiplication or division of two values is
done. If the operation code is something else, the default case is executed.
#include <stdio.h>
printf("1: addition\n");
printf("2: subtraction\n");
printf("3: multiplication\n");
printf("4: division\n");
return 0;
}
Output
1: addition
2: subtraction
3: multiplication
4: division
a: 10 b: 5 : op: 1
Result: 15.00
For other values of "op" (2, 3, and 4), you will get the following outputs −
a: 10 b: 5 : op: 2
Result: 5.00
a: 10 b: 5 : op: 3
Result: 50.00
a: 10 b: 5 : op: 4
Result: 2.00
a: 10 b: 5 : op: 5
Invalid operation
switch (exp) {
case 1:
case 2:
statements;
break;
case 3:
statements;
break;
default:
printf("%c is a non-alphanumeric character\n", ch);
}
You can also use the ellipsis (…) to combine a range of values for an expression. For example, to
match the value of switching variable with any number between 1 to 10, you can use "case 1 …
10"
Example 1
#include <stdio.h>
switch (number){
default:
printf("The number is not between 1 and 10\n");
}
return 0;
}
Output
Run the code and check its output. For "number = 5", we get the following output −
Example 2
The following program checks whether the value of the given char variable stores a lowercase
alphabet, an uppercase alphabet, a digit, or any other key.
#include <stdio.h>
char ch = 'g';
switch (ch){
case 'a' ... 'z':
printf("%c is a lowercase alphabet\n", ch);
break;
default:
printf("%c is a non-alphanumeric character\n", ch);
}
return 0;
}
Output
g is a lowercase alphabet
It is possible to have a switch as a part of the statement sequence of an outer switch. Even if the
case constants of the inner and outer switch contain common values, no conflicts will arise.
Syntax
switch(ch1){
case 'A':
printf("This A is part of outer switch" );
switch(ch2) {
case 'A':
printf("This A is part of inner switch" );
break;
case 'B': /* case code */
}
break;
case 'B': /* case code */
}
Example
#include <stdio.h>
int main (){
switch(b){
case 200:
printf("This is part of inner switch\n", a);
}
}
printf("Exact value of a is: %d\n", a);
printf("Exact value of b is: %d\n", b);
return 0;
}
Output
When the above code is compiled and executed, it produces the following output −
Just like nested if–else, you can have nested switch-case constructs. You may have a different
switch-case construct each inside the code block of one or more case labels of the outer switch
scope.
switch (exp1){
case val1:
switch (exp2){
case val_a:
stmts;
break;
case val_b:
stmts;
break;
}
case val2:
switch (expr2){
case val_c:
stmts;
break;
case val_d:
stmts;
break;
}
}
Example
#include <stdio.h>
int main(){
int x = 1, y = 'b', z='X';
// Outer Switch
switch (x){
case 1:
printf("Case 1 \n");
switch (y){
case 'a':
printf("Case a \n");
break;
case 'b':
printf("Case b \n");
break;
}
break;
case 2:
printf("Case 2 \n");
switch (z){
case 'X':
printf("Case X \n");
break;
case 'Y':
printf("Case Y \n");
break;
}
}
return 0;
}
Output
When you run this code, it will produce the following output −
Case 1
Case b
Change the values of the variables (x, y, and z) and check the output again. The output depends
on the values of these three variables.
C - Loops
Loops are a programming construct that denote a block of one or more statements that are
repeatedly executed a specified number of times, or till a certain condition is reached.
Repetitive tasks are common in programming, and loops are essential to save time and minimize
errors. In C programming, the keywords while, do–while and for are provided to implement
loops.
Looping constructs are an important part of any processing logic, as they help in performing the
same process again and again. A C programmer should be well acquainted with implementing
and controlling the looping construct.
Programming languages provide various control structures that allow for more complicated
execution paths. A loop statement allows us to execute a statement or group of statements
multiple times.
The statements in a C program are always executed in a top-to-bottom manner. If we ask the
compiler to go back to any of the earlier steps, it constitutes a loop.
Example: Loops in C
#include <stdio.h>
int main (){
return 0;
}
Output
a: 1
a: 2
a: 3
a: 4
a: 5
The program prints the value of "a", and increments its value. These two steps are repeated a
number of times. If you need to print the value of "a" from 1 to 100, it is not desirable to
manually repeat these steps in the code. Instead, we can ask the compiler to repeatedly execute
these two steps of printing and incrementing till it reaches 100.
You can use for, while or do-while constructs to repeat a loop. The following program shows
how you can print 100 values of "a" using the "while" loop in C −
#include <stdio.h>
int main () {
return 0;
}
Output
a: 1
a: 2
a: 3
a: 4
.....
.....
a: 98
a: 99
a: 100
If a step redirects the program flow to any of the earlier steps, based on any condition, the loop is
a conditional loop. The repetitions will stop as soon as the controlling condition turns false. If the
redirection is done without any condition, it is an infinite loop, as the code block repeats forever.
Parts of C Loops
Counted Loops in C
If the loop is designed to repeat for a certain number of times, it is a counted loop. In C,
the for loop is an example of counted loop.
Conditional Loops in C
If the loop is designed to repeat till a condition is true, it is a conditional loop. The while and do–
while constructs help you to form conditional loops.
Looping Statements in C
while loop
Repeats a statement or group of statements while a given
1
condition is true. It tests the condition before executing the loop
body.
for loop
2 Executes a sequence of statements multiple times and
abbreviates the code that manages the loop variable.
do-while loop
3 It is more like a while statement, except that it tests the
condition at the end of the loop body.
nested loops
4 You can use one or more loops inside any
other while, for or do-while loop.
Each of the above loop types have to be employed depending upon which one is right for the
given situation. We shall learn about these loop types in detail in the subsequent chapters.
Loop control statements change the execution from its normal sequence. When execution leaves
a scope, all automatic objects that were created in that scope are destroyed.
break statement
1 Terminates the loop or switch statement and transfers execution
to the statement immediately following the loop or switch.
continue statement
2 Causes the loop to skip the remainder of its body and
immediately retest its condition prior to reiterating.
goto statement
3
Transfers the control to the labeled statement.
The break and continue statements have contrasting purposes. The goto statement acts as a
jump statement if it causes the program to go to a later statement. If the goto statement redirects
the program to an earlier statement, then it forms a loop.
A loop becomes an infinite loop if a condition never becomes false. An infinite loop is a loop
that repeats indefinitely because it has no terminating condition, or the termination condition is
never met or the loop is instructed to start over from the beginning.
Although it is possible for a programmer to intentionally use an infinite loop, they are often
mistakes made by new programmers.
The for loop is traditionally used for creating an infinite loop. Since none of the three
expressions that form the "for" loop are required, you can make an endless loop by leaving the
conditional expression empty.
#include <stdio.h>
for( ; ; ){
printf("This loop will run forever. \n");
}
return 0;
}
Output
By running this code, you will get an endless loop that will keep printing the same line forever.
When the conditional expression is absent, it is assumed to be true. You may have an
initialization and increment expression, but C programmers more commonly use
the for(;;) construct to signify an infinite loop.
Note − You can terminate an infinite loop by pressing the "Ctrl + C" keys.
C - While Loop
In C, while is one of the keywords with which we can form loops. The while loop is one of the
most frequently used types of loops in C. The other looping keywords in C are for and do-while.
The while loop is often called the entry verified loop, whereas the do-while loop is an exit
verified loop. The for loop, on the other hand, is an automatic loop.
while(expression){
statement(s);
}
The while keyword is followed by a parenthesis, in which there should be a Boolean expression.
Followed by the parenthesis, there is a block of statements inside the curly brackets.
The while loop works like this. The C compiler evaluates the expression. If the expression is
true, the code block that follows, will be executed. If the expression is false, the compiler ignores
the block next to the while keyword, and proceeds to the immediately next statement after the
block.
The while keyword implies that the compiler continues to execute the ensuing block as long as
the expression is true. The condition sits at the top of the looping construct. After each iteration,
the condition is tested. If found to be true, the compiler performs the next iteration. As soon as
the expression is found to be false, the loop body will be skipped and the first statement after the
while loop will be executed.
Let us try to understand the behaviour of while loop with a few examples.
Example 1
The following program prints the "Hello World" message five times.
#include <stdio.h>
int main(){
Output
Here, the while loop acts as a counted loop. Run the code and check its output −
Hello World
Hello World
Hello World
Hello World
Hello World
End of loop
The variable "a" that controls the number of repetitions is initialized to 1, before
the while statement. Since the condition "a <= 5" is true, the program enters the loop, prints the
message, increments "a" by 1, and goes back to the top of the loop.
In the next iteration, "a" is 2, hence the condition is still true, hence the loop repeats again, and
continues till the condition turns false. The loop stops repeating, and the program control goes to
the step after the block.
Now, change the initial value of "a" to 10 and run the code again. Now the output will show the
following −
End of loop
This is because the condition before the while keyword is false in the very first iteration itself,
hence the block is not repeated.
Example 2
The following program prints all the lowercase alphabets with the help of a while loop.
#include <stdio.h>
int main(){
// local variable definition
char a = 'a';
Output
abcdefghijklmnopqrstuvwxyz
End of loop
A "char" variable represents a character corresponding to its ASCII value. Hence, it can be
incremented. Hence, we increment the value of the variable from "a" till it reaches "z".
Example 3
In this example, the while loop is used as a conditional loop. The loop continues to repeat till
the input received is non-negative.
#include <stdio.h>
int main(){
int x = 0;
Output
0 is Even
End of loop
Example 4
In the code given below, we have two variables "a" and "b" initialized to 10 and 0, respectively.
Inside the loop, "b" is decremented and "a" is incremented on each iteration. The loop is
designed to repeat till "a" and "b" are not equal. The loop ends when both reach 5.
#include <stdio.h>
int main(){
Output
When you run this code, it will produce the following output −
a: 9 b: 1
a: 8 b: 2
a: 7 b: 3
a: 6 b: 4
a: 5 b: 5
End of loop
The do-while loop appears similar to the while loop in most cases, although there is a difference
in its syntax. The do-while is called the exit verified loop. In some cases, their behaviour is
different. Difference between while and do-while loop is explained in the do-while chapter of
this tutorial.
In all the examples above, the while loop is designed to repeat for a number of times, or till a
certain condition is found. C has break and continue statements to control the loop. These
keywords can be used inside the while loop.
Example
while (expr){
...
...
if (condition)
break;
...
}
Example
while (expr){
...
...
if (condition)
continue;
...
}
For Loop in C
Most programming languages including C support the for keyword for constructing a loop. In C,
the other loop-related keywords are while and do-while. Unlike the other two types, the for loop
is called an automatic loop, and is usually the first choice of the programmers.
The for loop is an entry-controlled loop that executes the statements till the given condition. All
the elements (initialization, test condition, and increment) are placed together to form a for
loop inside the parenthesis with the for keyword.
The init step is executed first, and only once. This step allows you to declare and initialize any
loop control variables. You are not required to put a statement here, as long as a semicolon
appears.
Next, the condition is evaluated. If it is true, the body of the loop is executed. If it is false, the
body of the loop does not execute and the control jumps to the next statement just after the "for"
loop.
After the body of the "for" loop executes, the control flow jumps back up to the increment
statement. This statement allows you to update any loop control variables. This statement can be
left blank, as long as a semicolon appears after the condition.
The condition is now evaluated again. If it is true, the loop executes and the process repeats itself
(body of loop, then increment step, and then again the condition). After the condition becomes
false, the "for" loop terminates.
The for loop may be employed with different variations. Let us understand how the for loop
works in different situations.
This is the most basic form of the for loop. Note that all the three clauses inside the parenthesis
(in front of the for keyword) are optional.
#include <stdio.h>
int main(){
int a;
return 0;
}
Output
a: 1
a: 2
a: 3
a: 4
a: 5
The initialization step can be placed above the header of the for loop. In that case, the init part
must be left empty by putting a semicolon.
Example
#include <stdio.h>
int main(){
int a = 1;
Output
a: 1
a: 2
a: 3
a: 4
a: 5
You can also put an empty statement in place of the increment clause. However, you need to put
the increment statement inside the body of the loop, otherwise it becomes an infinite loop.
Example
#include <stdio.h>
int main(){
int a;
Output
Here too, you will get the same output as in the previous example −
a: 1
a: 2
a: 3
a: 4
a: 5
You can also omit the second clause of the test condition in the parenthesis. In that case, you will
need to terminate the loop with a break statement, otherwise the loop runs infinitely.
Example
#include <stdio.h>
int main(){
int a;
Output
There may be initialization of more than one variables and/or multiple increment statements in
a for statement. However, there can be only one test condition.
Example
#include <stdio.h>
int main(){
int a, b;
return 0;
}
Output
When you run this code, it will produce the following output −
a: 1 b: 1 a*b: 1
a: 2 b: 2 a*b: 4
a: 3 b: 3 a*b: 9
a: 4 b: 4 a*b: 16
a: 5 b: 5 a*b: 25
Example
#include <stdio.h>
int main(){
int a;
return 0;
}
Output
a: 5
a: 4
a: 3
a: 2
a: 1
For loop is well suited for traversal of one element of an array at a time. Note that each element
in the array has an incrementing index starting from "0".
Example
#include <stdio.h>
int main(){
int i;
int arr[] = {10, 20, 30, 40, 50};
return 0;
}
Output
When you run this code, it will produce the following output −
a[0]: 10
a[1]: 20
a[2]: 30
a[3]: 40
a[4]: 50
The following program computes the average of all the integers in a given array.
#include <stdio.h>
int main(){
int i;
int arr[] = {10, 20, 30, 40, 50};
int sum = 0;
float avg;
Output
Average = 30.000000
The following code uses a for loop to calculate the factorial value of a number. Note that the
factorial of a number is the product of all integers between 1 and the given number. The factorial
is mathematically represented by the following formula −
x! = 1 * 2 * . . . * x
#include <stdio.h>
int main(){
int i, x = 5;
int fact = 1;
return 0;
}
Output
When you run this code, it will produce the following output −
5! = 120
The for loop is ideally suited when the number of repetitions is known. However, the looping
behaviour can be controlled by the break and continue keywords inside the body of
the for loop. Nested for loops are also routinely used in the processing of two
dimensional arrays.
Do-While Loop in C
The do-while loop is one of the most frequently used types of loops in C.
The do and while keywords are used together to form a loop. The do-while is an exit-verified
loop where the test condition is checked after executing the loop's body. Whereas
the while loop is an entry-verified. The for loop, on the other hand, is an automatic loop.
do {
statement(s);
} while(condition);
The loop construct starts with the keword do. It is then followed by a block of statements inside
the curly brackets. The while keyword follows the right curly bracket. There is a parenthesis in
front of while, in which there should be a Boolean expression.
Now let's understand how the while loop works. As the C compiler encounters the do keyword,
the program control enters and executes the code block marked by the curly brackets. As the end
of the code block is reached, the expression in front of the while keyword is evaluated.
If the expression is true, the program control returns back to the top of loop. If the expression is
false, the compiler stops going back to the top of loop block, and proceeds to the immediately
next statement after the block. Note that there is a semicolon at the end of while statement.
The while keyword implies that the compiler continues to execute the ensuing block as long as
the expression is true. However, since the condition sits at the end of the looping construct, it is
checked after each iteration (rather than before each iteration as in the case of a while loop).
The program performs its first iteration unconditionally, and then tests the condition. If found to
be true, the compiler performs the next iteration. As soon as the expression is found to be false,
the loop body will be skipped and the first statement after the while loop will be executed.
Let us try to understand the behaviour of the while loop with a few examples.
The following program prints the Hello world message five times.
#include <stdio.h>
int main(){
return 0;
}
Output
Here, the do-while loop acts as a counted loop. Run the code and check its output −
Hello World
Hello World
Hello World
Hello World
Hello World
End of loop
The variable "a" that controls the number of repetitions is initialized to 1. The program enters the
loop unconditionally, prints the message, increments "a" by 1.
As it reaches the end of the loop, the condition in the while statement is tested. Since the
condition "a <= 5" is true, the program goes back to the top of the loop and re-enters the loop.
Now "a" is 2, hence the condition is still true, hence the loop repeats again, and continues till the
condition turns false. The loop stops repeating, and the program control goes to the step after the
block.
Now, change the initial value of "a" to 10 and run the code again. It will produce the following
output −
Hello World
End of loop
This is because the program enters the looping block unconditionally. Since the condition before
the while keyword is false, hence the block is not repeated for the next time. Hence, the do-while
loop takes at least one iteration as the test condition is at the end of the loop. For this reason, do-
while loop is called an "exit-verified loop".
The loops constructed with while and do-while appear similar. You can easily convert
a while loop into a do-while loop and vice versa. However, there are certain key differences
between the two.
The obvious syntactic difference is that the do-while construct starts with the do keyword and
ends with the while keyword. The while loop doesn't need the do keyword. Secondly, you find a
semicolon in front of while in case of a do-while loop. There is no semicolon in while loops.
Example
The location of the test condition that controls the loop is the major difference between the two.
The test condition is at the beginning of a while loop, whereas it is at the end in case of a do-
while loop. How does it affect the looping behaviour? Look at the following code −
#include <stdio.h>
int main(){
return 0;
}
Output
Initially, "a" and "b" are initialized to "0" and the output of both the loops is same.
Now change the initial value of both the variables to 3 and run the code again. There's no change
in the output of both the loops.
Note that the while loop doesn't take any iterations, but the do-while executes its body once.
This is because the looping condition is verified at the top of the loop block in case of while, and
since the condition is false, the program doesn't enter the loop.
In case of do-while, the program unconditionally enters the loop, increments "b" to 11 and then
doesn't repeat as the condition is false. It shows that the do-while is guaranteed to take at least
one repetition irrespective of the initial value of the looping variable.
The do-while loop can be used to construct a conditional loop as well. You can also
use break and continue statements inside a do-while loop.
Nested Loops in C
In the programming context, the term "nesting" refers to enclosing a particular programming
element inside another similar element. For example, nested loops, nested structures, nested
conditional statements, etc.
Nested Loops
When a looping construct in C is employed inside the body of another loop, we call it a nested
loop (or, loops within a loop). Where, the loop that encloses the other loop is called the outer
loop. The one that is enclosed is called the inner loop.
Outer loop {
Inner loop {
...
...
}
...
}
C provides three keywords for loops formation − while, do-while, and for. Nesting can be done
on any of these three types of loops. That means you can put a while loop inside a for loop,
a for loop inside a do-while loop, or any other combination.
The general behaviour of nested loops is that, for each iteration of the outer loop, the inner loop
completes all the iterations.
Nested for loops are very common. If both the outer and inner loops are expected to perform
three iterations each, the total number of iterations of the innermost statement will be "3 * 3 = 9".
#include <stdio.h>
int main(){
int i, j;
// outer loop
for(i = 1; i <= 3; i++){
// inner loop
for(j = 1; j <= 3; j++){
printf("i: %d j: %d\n", i, j);
}
printf("End of Inner Loop \n");
}
printf("End of Outer Loop");
return 0;
}
Output
When you run this code, it will produce the following output −
i: 1 j: 1
i: 1 j: 2
i: 1 j: 3
End of Inner Loop
i: 2 j: 1
i: 2 j: 2
i: 2 j: 3
End of Inner Loop
i: 3 j: 1
i: 3 j: 2
i: 3 j: 3
End of Inner Loop
Now let's analyze how the above program works. As the outer loop is encountered, "i" which is
the looping variable for the outer loop is initialized to 1. Since the test condition (a <= 3) is true,
the program enters the outer loop body.
The program reaches the inner loop, and "j" which is the variable that controls the inner loop is
initialized to 1. Since the test condition of the inner loop (j <= 3) is true, the program enters the
inner loop. The values of "a" and "b" are printed.
The program reaches the end of the inner loop. Its variable "j" is incremented. The control jumps
to step 4 until the condition (j <= 3) is true.
As the test condition becomes false (because "j" becomes 4), the control comes out of the inner
loop. The end of the outer loop is encountered. The variable "i" that controls the outer variable is
incremented and the control jumps to step 3. Since it is the start of the inner loop, "j" is again set
to 1.
The inner loop completes its iteration and ends again. Steps 4 to 8 will be repeated until the test
condition of the outer loop (i <= 3) becomes false. At the end of the outer loop, "i" and "j" have
become 4 and 4 respectively.
The result shows that, for each value of the outer looping variable, the inner looping variable
takes all the values. The total lines printed are "3 * 3 = 9".
Nesting a While Loop Inside a For Loop
Any type of loop can be nested inside any other type. Let us rewrite the above example by
putting a while loop inside the outer for loop.
#include <stdio.h>
int main(){
int i, j;
return 0;
}
Output
i: 1 j: 1
i: 1 j: 2
i: 1 j: 3
End of Inner While Loop
i: 2 j: 1
i: 2 j: 2
i: 2 j: 3
End of Inner While Loop
i: 3 j: 1
i: 3 j: 2
i: 3 j: 3
End of inner while Loop
Programmers use nested loops in a lot of applications. Let us take a look at some more examples
of nested loops.
The following program prints the tables of 1 to 10 with the help of two nested for loops.
#include <stdio.h>
int main(){
int i, j;
printf("Program to Print the Tables of 1 to 10 \n");
// outer loop
for(i = 1; i <= 10; i++){
// inner loop
for(j = 1; j <= 10; j++){
printf("%4d", i*j);
}
printf("\n");
}
return 0;
}
Output
The following code prints the increasing number of characters from a string.
#include <stdio.h>
#include <string.h>
int main(){
int i, j, l;
char x[] = "TutorialsPoint";
l = strlen(x);
// outer loop
for(i = 0; i < l; i++){
// inner loop
for(j = 0; j <= i; j++){
printf("%c", x[j]);
}
printf("\n");
}
return 0;
}
Output
When you run this code, it will produce the following output −
T
Tu
Tut
Tuto
Tutor
Tutori
Tutoria
Tutorial
Tutorials
TutorialsP
TutorialsPo
TutorialsPoi
TutorialsPoin
TutorialsPoint
In this program, we will show how you can use nested loops to display a two-dimensional
array of integers. The outer loop controls the row number and the inner loop controls the
columns.
#include <stdio.h>
int main(){
int i, j;
int x[4][4] = {
{1, 2, 3, 4},
{11, 22, 33, 44},
{9, 99, 999, 9999},
{10, 20, 30, 40}
};
// outer loop
for (i=0; i<=3; i++){
// inner loop
for(j=0; j <= 3; j++){
printf("%5d", x[i][j]);
}
printf("\n");
}
return 0;
}
Output
When you run this code, it will produce the following output −
1 2 3 4
11 22 33 44
9 99 999 9999
10 20 30 40
C - Infinite Loop
In C language, an infinite loop (or, an endless loop) is a never-ending looping construct that
executes a set of statements forever without terminating the loop. It has a true condition that
enables a program to run continuously.
If the flow of the program is unconditionally directed to any previous step, an infinite loop is
created, as shown in the following flowchart −
An infinite loop is very rarely created intentionally. In case of embedded headless systems and
server applications, the application runs in an infinite loop to listen to the client requests. In other
circumstances, infinite loops are mostly created due to inadvertent programming errors.
To create an infinite loop, you need to use one of the loop constructs (while, do while, or for)
with a non-zero value as a test condition. Generally, 1 is used as the test condition, you can use
any non-zero value. A non-zero value is considered as true.
Example
#include <stdio.h>
int main() {
while (1)
{
printf("Hello World");
}
return 0;
}
Hello WorldHello WorldHello WorldHello WorldHello WorldHello World
Hello WorldHello WorldHello WorldHello WorldHello WorldHello World
Hello WorldHello WorldHello ...
Types of Infinite Loops in C
In C language, infinite while, infinite do while, and infinite for are the three infinite loops. These
loops execute the code statement continuously. Let us understand the implementation of infinite
loops using all loop constructs.
The while keyword is used to form a counted loop. The loop is scheduled to repeat till the value
of some variable successively increments to a predefined value. However, if the programmer
forgets to put the increment statement within the loop body, the test condition doesn’t arrive at
all, hence it becomes endless or infinite.
Example 1
#include <stdio.h>
int i = 0;
while (i <= 10){
// i++;
printf("i: %d\n", i);
}
return 0;
}
Output
Since the increment statement is commented out here, the value of "i" continues to remain "0",
hence the output shows "i: 0" continuously until you forcibly stop the execution.
i: 0
i: 0
i: 0
...
...
Example 2
The parenthesis of while keyword has a Boolean expression that initially evaluates to True, and
is eventually expected to become False. Note that any non-zero number is treated as True in C.
Hence, the following while loop is an infinite loop:
#include <stdio.h>
while(1){
printf("Hello World \n");
}
return 0;
}
Output
Hello World
Hello World
Hello World
...
...
while (condition){
...
...
}
Note that the there is no semicolon symbol in front of while, indicating that the following code
block (within the curly brackets) is the body of the loop. If we place a semicolon, the compiler
treats this as a loop without body, and hence the while condition is never met.
Example 3
In the following code, an increment statement is put inside the loop block, but because of the
semicolon in front of while, the loop becomes infinite.
#include <stdio.h>
int i = 0;
while(i < 10);{
i++;
printf("Hello World \n");
}
return 0;
}
Output
When the program is run, it won't print the message "Hello World". There is no output because
the while loop becomes an infinite loop with no body.
The for loop in C is used for performing iteration of the code block for each value of a variable
from its initial value to the final value, incrementing it on each iteration.
Example 1
Note that all the three clauses of the for statement are optional. Hence, if the middle clause that
specifies the final value to be tested is omitted, the loop turns infinite.
#include <stdio.h>
// infinite for loop
int main(){
int i;
for(i=1; ; i++){
i++;
printf("Hello World \n");
}
return 0;
}
Output
The program keeps printing Hello World endlessly until you stop it forcibly, because it has no
effect of incrementing "i" on each turn.
Hello World
Hello World
Hello World
...
...
You can also construct a for loop for decrementing the values of a looping variable. In that case,
the initial value should be greater than the final test value, and the third clause in for must be a
decrement statement (using the "--" operator).
If the initial value is less than the final value and the third statement is decrement, the loop
becomes infinite. The loop still becomes infinite if the initial value is larger but you mistakenly
used an increment statement.
Example 2
#include <stdio.h>
int main(){
// infinite for loop
for(int i = 10; i >= 1; i++){
i++;
printf("Hello World \n");
}
}
Output
Hello World
Hello World
Hello World
...
...
Example 3
#include <stdio.h>
int main(){
Output
Hello World
Hello World
Hello World
...
...
Example 4
If all the three statements in the parenthesis are blank, the loop obviously is an infinite loop, as
there is no condition to test.
#include <stdio.h>
int main(){
int i;
Output
Hello World
Hello World
Hello World
...
...
An infinite loop can also be implemented using the do-while loop construct. You have to use 1 as
the test condition with the while.
Example
int main() {
do
{
printf("Hello World\n");
} while (1);
return 0;
}
Hello World
Hello World
Hello World
Hello World
...
...
There may be certain situations in programming where you need to start with an
unconditional while or for statement, but then you need to provide a way to terminate the loop
by placing a conditional break statement.
Example
In the following program, there is no test statement in for, but we used a break statement to
make it a finite loop.
#include <stdio.h>
int main(){
if(i == 5)
break;
}
return 0;
}
Output
The program prints "Hello World" till the counter variable reaches [Link] World
Hello World
Hello World
Hello World
When the program enters an infinite loop, it doesn’t stop on its own. It has to be forcibly
stopped. This is done by pressing "Crtrl + C" or "Ctrl + Break" or any other key combination
depending on the operating system.
Example
#include <stdio.h>
int main(){
// do loop execution
LOOP:
a++;
printf("a: %d\n", a);
goto LOOP;
return 0;
}
Output
When executed, the above program prints incrementing values of "a" from 1 onwards, but it
doesn’t stop. It will have to be forcibly stopped by pressing "Ctrl + Break" keys.
a: 1
a: 2
...
...
a: 10
a: 11
...
...
Infinite loops are mostly unintentionally created as a result of programming bug. Even if the
looping keyword doesn’t specify the termination condition, the loop has to be terminated with
the break keyword.
Break Statement in C
The break statement in C is used in two different contexts. In switch-case, break is placed as the
last statement of each case block. The break statement may also be employed in the body of any
of the loop constructs (while, do–while as well as for loops).
When used inside a loop, break causes the loop to be terminated. In the switch-case
statement, break takes the control out of the switch scope after executing the
corresponding case block.
The break statement is never used unconditionally. It always appears in the True part of
an if statement. Otherwise, the loop will terminate in the middle of the first iteration itself.
while(condition1){
...
...
if(condition2)
break;
...
...
}
The while loop increments the divisor by 1 and tries to check if it is divisible. If found divisible,
the while loop is terminated.
#include <stdio.h>
int i = 2;
int x = 121;
printf("x: %d\n", x);
return 0;
}
Output
x: 121
121 is not prime
Now, change the value of "x" to 25 and run the code again. It will produce the following output
−
x: 25
25 is not prime
You can use a break statement inside a for loop as well. Usually, a for loop is designed to
perform a certain number of iterations. However, sometimes it may be required to abandon the
loop if a certain condition is reached.
The following program prints the characters from a given string before a vowel (a, e, I, or u) is
detected.
#include <stdio.h>
#include <string.h>
int main () {
return 0;
}
Output
R
h
y
t
h
m
If break appears in an inner loop of a nested loop construct, it abandons the inner loop and
continues the iteration of the outer loop body. For the next iteration, it enters the inner loop
again, which may be broken again if the condition is found to be true.
In the following program, two nested loops are employed to obtain a list of all the prime numbers
between 1 to 30. The inner loop breaks out when a number is found to be divisible, setting the
flag to 1. After the inner loop, the value of flag is checked. If it is "0", the number is a prime
number.
#include <stdio.h>
int main(){
int i, num, n, flag;
printf("The prime numbers in between the range 1 to 30:\n");
Output
2 is prime
3 is prime
5 is prime
7 is prime
11 is prime
13 is prime
17 is prime
19 is prime
23 is prime
29 is prime
An infinite loop is rarely created intentionally. However, in some cases, you may start an infinite
loop and break from it when a certain condition is reached.
In the following program, an infinite for loop is used. On each iteration, a random number
between 1 to 100 is generated till a number that is divisible by 5 is obtained.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
int i, num;
printf ("Program to get the random number from 1 to 100: \n");
srand(time(NULL));
for (; ; ){
num = rand() % 100 + 1; // random number between 1 to 100
printf (" %d\n", num);
if (num%5 == 0)
break;
}
}
Output
On running this code, you will get an output like the one shown here −
To transfer the control out of the switch scope, every case block ends with a break statement. If
not, the program falls through all the case blocks, which is not desired.
In the following code, a series of if-else statements print three different greeting messages based
on the value of a "ch" variable ("m", "a" or "e" for morning, afternoon or evening).
#include <stdio.h>
int main(){
switch(ch) {
case 'm':
printf("Good Morning \n");
break;
case 'a':
printf("Good Afternoon \n");
break;
case 'e':
printf("Good Evening \n");
break;
default:
printf("Hello");
}
}
Output
Here, the break statement breaks the program execution after checking the first case.
Time code: m
Good Morning
Now, comment the break statements and run the code again. You will now get the following
output −
Time code: m
Good Morning
Good Afternoon
Good Evening
Hello
Continue Statement in C
The behaviour of continue statement in C is somewhat opposite to the break statement. Instead
of forcing the termination of a loop, it forces the next iteration of the loop to take place, skipping
the rest of the statements in the current iteration.
The continue statement is used to skip the execution of the rest of the statement within the loop
in the current iteration and transfer it to the next loop iteration. It can be used with all the C
language loop constructs (while, do while, and for).
while (expr){
...
...
if (condition)
continue;
...
}
In case of nested loops, continue will continue the next iteration of the nearest loop.
The continue statement is often used with if statements.
In this program the loop generates 1 to 10 values of the variable "i". Whenever it is an even
number, the next iteration starts, skipping the printf statement. Only the odd numbers are printed.
#include <stdio.h>
int main(){
int i = 0;
}
}
Output
i: 1
i: 3
i: 5
i: 7
i: 9
#include <stdio.h>
#include <string.h>
int main () {
return 0;
}
Output
If a continue statement appears inside an inner loop, the program control jumps to the beginning
of the corresponding loop.
In the example below, there are three for loops one inside the other. These loops are controlled
by the variables i, j, and k respectively. The innermost loop skips the printf statement if k is
equal to either i or j, and goes to its next value of k. The second j loop executes
the continue when it equals i. As a result, all the unique combinations of three digits 1, 2 and 3
are displayed.
#include <stdio.h>
int i, j, k;
Output
123
132
213
231
312
321
The following code detects the blankspaces between the words in a string, and prints each word
on a different line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(){
Output
One of the cases where the continue statement proves very effective is in the problem of writing
a program to find prime factors of a given number.
The given number is successively divided by numbers starting with 2. If the number is divisible,
the given number is reduced to the division, and the resultant number is checked for divisibility
with 2 until it is no longer divisible.
If not by 2, the process is repeated for all the odd numbers starting with 3. The loop runs while
the given number reduces to 1.
#include <stdio.h>
Output
Here, the given number is 64. So, when you run this code, it will produce the following output −
Change the number to 45 and then 90. Run the code again. Now you will get the following
outputs −
The goto statement is used to transfer the program's control to a defined label within the
same function. It is an unconditional jump statement that can transfer control forward or
backward.
The goto keyword is followed by a label. When executed, the program control is redirected to
the statement following the [Link] the label points to any of the earlier statements in a code, it
constitutes a loop. On the other hand, if the label refers to a further step, it is equivalent to a
Jump.
goto label;
...
...
label: statement;
The label is any valid identifier in C. A label must contain alphanumeric characters along with
the underscore symbol (_). As in case of any identifier, the same label cannot be specified more
than once in a program. It is always followed by a colon (:) symbol. The statement after this
colon is executed when goto redirects the program here.
Example 1
In the following program, the control jumps to a given label which is after the current statement.
It prints a given number, before printing the end of the program message. If it is "0", it jumps
over to the printf statement, displaying the message.
#include <stdio.h>
if (n == 0)
goto end;
printf("The number is: %d", n);
end:
printf ("End of program");
return 0;
}
Output
End of program
Example 2
Here is a program to check if a given number is even or odd. Observe how we used
the goto statement in this program −
#include <stdio.h>
int i = 11;
if (i % 2 == 0){
EVEN:
printf("The number is even \n");
goto END;
}
else{
ODD:
printf("The number is odd \n");
}
END:
printf("End of program");
return 0;
}
Output
Since the given number is 11, it will produce the following output −
Change the number and check the output for different numbers.
Example 3
#include <stdio.h>
Output
Hello World
How are you?
.......
.......
The program prints the two strings continuously until forcibly stopped.
Example 4
In this program, we have two goto statements. The second goto statement forms a loop because
it makes a backward jump. The other goto statement jumps out of the loop when the condition is
reached.
#include <stdio.h>
int main(){
int i = 0;
START:
i++;
printf("i: %d\n", i);
if (i == 5)
goto END;
goto START;
END:
printf("End of loop");
return 0;
}
Output
i: 1
i: 2
i: 3
i: 4
i: 5
End of loop
Example 5
The goto statement is used here to skip all the values of a looping variable that matches with that
of others. As a result, all the unique combinations of 1, 2 and 3 are obtained.
#include <stdio.h>
int i, j, k;
label2: ;
}
label1: ;
}
}
return 0;
}
Output
123
132
213
231
312
321
Note that goto in C is considered unstructured, as it allows the program to jump to any location
in the code, it can make the code hard to understand, follow, and maintain. Too many goto
statements sending the program control back and forth can make the program logic difficult to
understand.
Noted computer scientist dsger Dijkstra recommended that goto be removed from all the
programming languages. He observed that if the program control jumps in the middle of a loop,
it may yield unpredictable behaviour. The goto statements can be used to create programs that
have multiple entry and exit points, which can make it difficult to track the flow of control of the
program.
Dijkstra's strong observations against the use of goto statement have been influential, as many
mainstream languages do not support goto statements. However, it is still available in some
languages, such as C and C++.
In general, it is best to avoid using goto statements in C. You can instead effectively use if-
else statements, loops and loop controls, function and subroutine calls, and try-catch-throw
statements. Use goto if and only if these alternatives don’t fulfil the needs of your algorithm.
Functions in C
A function in C is a block of organized reusuable code that is performs a single related action.
Every C program has at least one function, which is main(), and all the most trivial programs can
define additional functions.
When the algorithm of a certain problem involves long and complex logic, it is broken into
smaller, independent and reusable blocks. These small blocks of code are known by different
names in different programming languages such as a module, a subroutine, a function or
a method.
You can divide up your code into separate functions. How you divide up your code among
different functions is up to you, but logically the division is such that each function performs a
specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A
function definition provides the actual body of the function.
The C standard library provides numerous built-in functions that your program can call. For
example, strcat() to concatenate two strings, memcpy() to copy one memory location to another
location, and many more functions.
Modular Programming in C
Functions are designed to perform a specific task that is a part of an entire process. This
approach towards software development is called modular programming.
Each function is a separate, complete and reusable software component. When called, a function
performs a specified task and returns the control back to the calling routine, optionally along
with result of its process.
The main advantage of this approach is that the code becomes easy to follow, develop and
maintain.
Library Functions in C
C offers a number of library functions included in different header files. For example,
the stdio.h header file includes printf() and scanf() functions. Similarly, the math.h header file
includes a number of functions such as sin(), pow(), sqrt() and more.
These functions perform a predefined task and can be called upon in any program as per
requirement. However, if you don't find a suitable library function to serve your purpose, you
can define one.
Defining a Function in C
In C, it is necessary to provide the forward declaration of the prototype of any function. The
prototype of a library function is present in the corresponding header file.
For a user-defined function, its prototype is present in the current program. The definition of a
function and its prototype declaration should match.
After all the statements in a function are executed, the flow of the program returns to the calling
environment. The function may return some data along with the flow control.
Function Declarations in C
A function declaration tells the compiler about a function name and how to call the function.
The actual body of the function can be defined separately.
Parameter names are not important in function declaration only their type is required, so the
following is also a valid declaration −
A function declaration is required when you define a function in one source file and you call that
function in another file. In such cases, you should declare the function at the top of the file
calling the function.
Parts of a Function in C
A function definition in C programming consists of a function header and a function body. Here
are all the parts of a function −
Return Type − A function may return a value. The return_type is the data type of the value
the function returns. Some functions perform the desired operations without returning a
value. In this case, the return_type is the keyword void.
Function Name − This is the actual name of the function. The function name and the
parameter list together constitute the function signature.
Argument List − An argument (also called parameter) is like a placeholder. When a
function is invoked, you pass a value as a parameter. This value is referred to as the actual
parameter or argument. The parameter list refers to the type, order, and number of the
parameters of a function. Parameters are optional; that is, a function may contain no
parameters.
Function Body − The function body contains a collection of statements that defines what
the function does.
A function in C should have a return type. The type of the variable returned by the function must
be the return type of the function. In the above figure, the add() function returns an int type.
#include <stdio.h>
return result;
}
int main(){
printf("Comparing two numbers using max() function: \n");
printf("Which of the two, 75 or 57, is greater than the other? \n");
printf("The answer is: %d", max(75, 57));
return 0;
}
Output
When you runt this code, it will produce the following output −
Calling a Function in C
While creating a C function, you give a definition of what the function has to do. To use a
function, you will have to call that function to perform the defined task.
To call a function properly, you need to comply with the declaration of the function prototype. If
the function is defined to receive a set of arguments, the same number and type of arguments
must be passed.
When a function is defined with arguments, the arguments in front of the function name are
called formal arguments. When a function is called, the arguments passed to it are the actual
arguments.
When a program calls a function, the program control is transferred to the called function. A
called function performs a defined task and when its return statement is executed or when its
function-ending closing brace is reached, it returns the program control back to the main
program.
To call a function, you simply need to pass the required parameters along with the function
name. If the function returns a value, then you can store the returned value. Take a look at the
following example −
#include <stdio.h>
/* function declaration */
int max(int num1, int num2);
return 0;
}
/* function returning the max between two numbers */
int max(int num1, int num2){
return result;
}
Output
We have kept max() along with main() and compiled the source code. While running the final
executable, it would produce the following result −
A C program is a collection of one or more functions, but one of the functions must be named
as main(), which is the entry point of the execution of the program.
From inside the main() function, other functions are called. The main() function can call a library
function such as printf(), whose prototype is fetched from the header file (stdio.h) or any other
user-defined function present in the code.
In C, the order of definition of the program is not material. In a program, wherever there is
main(), it is the entry point irrespective of whether it is the first function or not.
Note: In C, any function can call any other function, any number of times. A function can call
itself too. Such a self-calling function is called a recursive function.
Function Arguments
If a function is to use arguments, it must declare variables that accept the values of the
arguments. These variables are called the formal parameters of the function.
Formal parameters behave like other local variables inside the function and are created upon
entry into the function and destroyed upon exit.
While calling a function, there are two ways in which arguments can be passed to a function −
Call by value
This method copies the actual value of an argument into the
1
formal parameter of the function. In this case, changes made to
the parameter inside the function have no effect on the argument.
Call by reference
This method copies the address of an argument into the formal
2 parameter. Inside the function, the address is used to access the
actual argument used in the call. This means that changes made
to the parameter affect the argument.
By default, C uses call by value to pass arguments. In general, it means the code within a
function cannot alter the arguments used to call the function.
C - Main Function
In a C program, the main() function is the entry point. The program execution starts with
the main() function. It is designed to perform the main processing of the program and clean up
any resources that were allocated by the program. In a C code, there may be any number of
functions, but it must have a main() function. Irrespective of its place in the code, it is the first
function to be executed.
int main(){
//one or more statements;
return 0;
}
Syntax Explained
As a part of its syntax, a function has a name that follows the rules of forming an identifier
(starting with an alphabet or underscore and having alphabet, digit or underscore). The name is
followed by a parenthesis. Typically, the main() function is defined with no arguments, although
it may have argv and argv argument to receive values from the command line.
Valid Signatures of C main() Function
int main() {
..
return 0;
}
Or
int main(void){
..
return 0;
}
Or
#include <stdio.h>
int main() {
// Write code from here
printf("Hello World");
return 0;
}
The program's execution starts from the main() function as it is an entry point of the program, it
starts executing the statements written inside it. Other functions within the source program are
defined to perform certain task. The main function can call any of these functions. When main
calls another function, it passes execution control to the function, optionally passing the requisite
number and type of arguments, so that execution begins at the first statement in the called
function. The called function returns control to main when a return statement is executed or
when the end of the function is reached. Note that return statement is implicitly present as the
last statement when its return type is int.
A program usually stops executing when it returns from or reaches the end of main, although it
can terminate at other points in the program for various reasons. For example, you may want to
force the termination of your program when some error condition is detected. To do so, you can
use the exit function.
The C exit() function is a standard library function used to terminate the calling process. Use
exit(0) to indicate no error, and exit(1) to indicate that the program is exiting with because of an
error encountered.
#include <stdio.h>
#include <stdlib.h>
return 0;
}
Output
Number is 1
Number is 2
exiting ..
Typically, the main() function is defined without any arguments. However, you may define
main() with arguments to let it accept the values from the command line. In this type of usage,
main() function is defined as follows −
Syntax
Argument Definitions
argc − The first argument is an integer that contains the count of arguments that follow in argv.
The argc parameter is always greater than or equal to 1.
argv − The second argument is an array of null−terminated strings representing command-line
arguments entered by the user of the program. By convention, argv[0] is the command with
which the program is invoked. argv[1] is the first command−line argument. The last argument
from the command line is argv[argc − 1], and argv[argc] is always NULL.
#include <stdio.h>
#include <stdlib.h>
if (argc<3){
printf("insufficient arguments");
}
else{
x = atoi(argv[1]);
y = atoi(argv[2]);
z = x+y;
printf("addition : %d", z);
}
return 0;
}
Just compile and build the program as test.c, don’t run from the IDE in which you have edited
and compiled. Go to the command prompt and run the program as follows −
C:\Users\mlath>test 10 20
addition : 30
In this chapter, we learned the importance and syntax of defining a main() function in C. Any C
program must have a main() function. As a convention it should return 0 to indicate successful
execution. You can also define arguments to a main() function, they can be passed from the
command−line.
Function Call by Value in C
In C language, a function can be called from any other function, including itself. There are two
ways in which a function can be called − (a) Call by Value and (b) Call by Reference. By
default, the Call by Value mechanism is employed.
You must know the terminologies to understand how the call by value method works −
Formal arguments − A function needs certain data to perform its desired process. When a
function is defined, it is assumed that the data values will be provided in the form of parameter
or argument list inside the parenthesis in front of the function name. These arguments are the
variables of a certain data type.
Actual arguments − When a certain function is to be called, it should be provided with the
required number of values of the same type and in the same sequence as used in its definition.
Here, the argument variables are called the formal arguments. Inside the function’s scope, these
variables act as its local variables.
int z = x + y;
return z;
The arguments x and y in this function definition are the formal arguments.
If the add() function is called, as shown in the code below, then the variables inside the
parenthesis (a and b) are the actual arguments. They are passed to the function.
Take a look at the following example −
#include <stdio.h>
int z = x + y;
return z;
}
int main(){
Output
When you run this code, it will produce the following output −
Addition: 30
The Call by Value method implies that the values of the actual arguments are copied in the
formal argument variables. Hence, "x" takes the value of "a" and "b" is assigned to "y". The local
variable "z" inside the add() function stores the addition value. In the main() function, the value
returned by the add() function is assigned to "c", which is printed.
Note that a variable in C language is a named location in the memory. Hence, variables are
created in the memory and each variable is assigned a random memory address by the compiler.
Let us assume that the variables a, b and c in the main() function occupy the memory locations
100, 200 and 300 respectively. When the add() function is called with a and b as actual
arguments, their values are stored in x and y respectively.
The variables x, y, and z are the local variables of the add() function. In the memory, they will be
assigned some random location. Let's assume that they are created in memory address 1000,
2000 and 3000, respectively.
Since the function is called by copying the value of the actual arguments to their corresponding
formal argument variables, the locations 1000 and 2000 which are the address of x and y will
hold 10 and 20, respectively. The compiler assigns their addition to the third local
variable z which is returned.
As the control comes back to the main() function, the returned data is assigned to c, which is
displayed as the output of the program.
Example
Call by Value is the default function calling mechanism in C. It eliminates a function’s potential
side effects, making your software simpler to maintain and easy to understand. It is best suited
for a function expected to do a certain computation on the argument received and return the
result.
#include <stdio.h>
/* function declaration */
void swap(int x, int y);
int main(){
/* local variable definition */
int a = 100;
int b = 200;
return 0;
}
int temp;
return;
}
Output
When you run this code, it will produce the following output −
Since the values are copied in different local variables of another function, any manipulation
doesn’t have any effect on the actual argument variables in the calling function.
However, the Call by Value method is less efficient when we need to pass large objects such as
an array or a file to another function. Also, in some cases, we may need the actual arguments to
be manipulated by another function. In such cases, the Call by Value mechanism is not useful.
We have to explore the Call by Reference mechanism for that purpose. Refer the next chapter for
a detailed explanation on the Call by Reference mechanism of C.
The Call by Reference approach involves passing the address of the variable holding the value of
the actual argument. You can devise a calling method that is a mix of Call by Value and Call by
Reference. In this case, some arguments are passed by value and others by reference.
There are two ways in which a function can be called: (a) Call by Value and (b) Call by
Reference. In this chapter, we will explain the mechanism of calling a function by reference.
Let us start this chapter with a brief overview on "pointers" and the "address operator (&)". It is
important that you learn these two concepts in order to fully understand the mechanism of Call
by Reference.
In C language, a variable is a named memory location. When a variable declared, the compiler
allocates a random location in the memory and internally identifies the location with the user-
defined name.
To fetch the address at which the variable has been created, we use the address (&) operator.
Example
#include <stdio.h>
int main(){
int x = 10;
Output
x: 10 Address of x: -1990957196
What is a Pointer in C?
A pointer is a variable that stores the address of another variable. To declare a pointer variable,
its name is prefixed with the * symbol. The type of the pointer variable and its host variable must
be same.
The address is assigned with the & operator. The dereference operator (*) is used with the
pointer. It fetches the value of a variable whose address is assigned to the pointer.
Example
#include <stdio.h>
int main(){
int x = 10;
int *y = &x;
Output
x: 10 Address of x: -1742755108
Address of y: -1742755104
Value at address in y: 10
How Does Call by Reference Work in C?
When a function is called by reference, the address of the actual argument variables passed,
instead of their values.
Let us define the add() function that receives the references of two variables −
int z = *x + *y;
return z;
}
When such a function is called, we pass the address of the actual argument.
Example
Let us call the add() function by reference from inside the main() function −
#include <stdio.h>
/* function declaration */
int add(int *, int *);
int main(){
int z = *x + *y;
return z;
}
Output
When you run this code, it will produce the following output −
Addition: 30
Now let's understand how this code actually works. The main() function passes the address
of a and b to the add() function. The addresses of a and b are assigned to the pointer
variables x and y.
Now focus on the statement "z = *x + *y;" inside the add() function. Remember that x stores the
address of a. The dereference operator in *x and *y fetches the values of a and b respectively,
hence z is the addition of a and b in the main() function.
Let us understand in more detail how the Call by Reference mechanism works, with the help of
the following example that interchanges value of two variables.
#include <stdio.h>
int z;
return 0;
}
int main(){
/* local variable definition */
int a = 10;
int b = 20;
return 0;
}
Output
When you run this code, it will produce the following output −
Explanation
Assume that the variables a and b in the main() function are allotted locations with the memory
address 100 and 200 respectively. As their addresses are passed to x and y (remember that they
are pointers), the variables x, y and z in the swap() function are created at addresses 1000, 2000
and 3000 respectively.
Since "x" and "y" store the address of "a" and "b", "x" becomes 100 and "y" becomes 200, as the
above figure shows.
Inside the swap() function, the first statement "z = *x" causes the value at address in "x" to be
stored in "x" (which is 10). Similarly, in the statement "*x = *y;", the value at the address in "y"
(which is 20) is stored in the location whose pointer is "x".
Finally, the statement "*y = z;" assigns the "z" to the variable pointed to by "y", which is "b" in
the main() function. The values of "a" and "b" now get swapped.
A function in C can have more than one arguments, but can return only one value. The Call by
Reference mechanism is a good solution to overcome this restriction.
Example
In this example, the calculate() function receives an integer argument by value, and two pointers
where its square and cube are stored.
#include <stdio.h>
#include <math.h>
/* function declaration */
int calculate(int, int *, int *);
int main(){
int a = 10;
int b, c;
*y = pow(x,2);
*z = pow(x, 3);
return 0;
}
Output
When you run this code, it will produce the following output −
a: 10
Square of a: 100
Cube of a: 1000
The Call by Reference mechanism is widely used when a function needs to perform memory-
level manipulations such as controlling the peripheral devices, performing dynamic allocation,
etc.
Nested Functions in C
The term nesting, in programming context refers to enclosing a particular programming element
inside another similar element. Just like nested loops, nested structures, etc., a nested function is
a term used to describe the use of one or more functions inside another function.
In C language, defining a function inside another one is not possible. In short, nested functions
are not supported in C. A function may only be declared (not defined) within another function.
When a function is declared inside another function, it is called lexical scoping. Lexical scoping
is not valid in C because the compiler cannot reach the correct memory location of inner
function.
Nested function definitions cannot access local variables of surrounding blocks. They can access
only global variables. In C, there are two nested scopes: local and global. So, nested functions
have limited use.
If you want to create a nested function like the one shown below, then it will generate an error −
#include <stdio.h>
int main(void){
printf("Main Function");
int my_fun(){
printf("my_fun function");
// Nested Function
int nested(){
printf("This is a nested function.");
}
}
nested();
}
Output
Nested functions are supported as an extension in "GNU C". GCC implements taking the address
of a nested function using a technique called trampolines.
A trampoline is a piece of code created at runtime when the address of a nested function is taken.
It requires the function to be prefixed with the keyword auto in the declaration.
Example 1
#include <stdio.h>
int main(){
int nested(){
printf("In the nested function now\n");
}
Output
When you run this code, it will produce the following output −
Example 2
In thi program, a function square() is nested inside another function myfunction(). The nested
function is declared with the auto keyword.
#include <stdio.h>
#include <math.h>
int main(){
double x = 4, y = 5;
printf("Addition of squares of %f and %f = %f", x, y, myfunction(x, y));
return 0;
}
Output
One needs to be aware of the following points while using nested functions −
A nested function can access all the identifiers of the containing function that precede its
definition.
A nested function must not be called before the containing function exits.
A nested function cannot use a goto statement to jump to a label in the containing function.
Nested function definitions are permitted within functions in any block, mixed with the
other declarations and statements in the block.
If you try to call a nested function through its address after the containing function exits, it
throws an error.
A nested function always has no linkage. Declaring one with "extern" or "static" always
produces errors.
Variadic Functions in C
Variadic functions are one of the powerful but very rarely used features in C language. A
function that can take a variable number of arguments is called a variadic function.
The most frequently used library functions in C, i.e., printf() and scanf() are in fact the best-
known examples of variadic functions, as we can put a variable number of arguments after the
format specifier string.
You need to include the stdarg.h header file at the top of the code to handle the variable
arguments. This header file provides the following macros to work with the arguments received
by the ellipsis symbol.
Methods Description
va_copy(va_list dest,
This creates a copy of the arguments in va_list
va_list src)
The following code uses the concept of a variadic function to return the sum of a variable
number of numeric arguments passed to such a function. The first argument to the addition()
function is the count of the remaining arguments.
va_list args;
va_start (args, n);
Since there are "n" number of arguments that follow, fetch the next argument with "va_arg()"
macro for "n" number of times and perform cumulative addition −
va_end (args);
The function ends by returning the sum of all the arguments.
#include <stdio.h>
#include <stdarg.h>
va_list args;
int i, sum = 0;
va_end (args);
return sum;
}
int main(){
return 0;
}
Output
Sum = 15
You can try providing a different set of numbers as the variadic arguments to the addition()
function.
We can extend the concept of variadic function to find the largest number in a given list of
variable number of values.
#include <stdio.h>
#include <stdarg.h>
va_end (args);
return max;
}
int main(){
printf("Largest number in the list = %d ", largest(5, 12, 34, 21, 45, 32));
return 0;
}
Output
When you run this code, it will produce the following output −
Largest number in the list = 45
In the following code, we pass multiple strings to a variadic function that returns a concatenated
string.
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
va_end (args);
return string;
}
int main(){
Output
Hello World
How are you?
User-defined Functions in C
Previous
Next
A function in C is a block of organized, reusable code that is used to perform a single related
action. In any C program, there are one or more functions − classified as library functions and
user-defined functions.
Library functions
User-defined functions
Any C compiler (e.g. GCC compiler, Clang, MSVC compiler, etc.) is distributed with a number
precompiled header files (stdio.h, math.h, etc.), each consisting of one or more predefined library
functions such as printf(), scanf(), pow(), sqrt(), etc. To be able to use the library function, the
corresponding header file must be made available with the #include directive.
However, if you don’t find a suitable library function to serve your purpose, then you can define
a customized function for the program. Normally, we find a C program with a main() function.
Obviously, the main() function is a user-defined function, as it contains the instructions provided
by the user. It can of course call the other library or user-defined functions.
For creating a user-defined function, first you need to understand the purpose of the function,
that is, what do you want the function to do?
A function may need one or more data items to process. The data that the function needs from
the calling environment are called arguments. Inside the body of the function, one or more local
variables may be needed for processing the data. Decide the set of steps that the program will use
to accomplish this goal (the algorithm).
After all the statements in the function are executed, the flow of the program returns to the
calling environment. The function may return some data along with the flow control.
Forward Declaration
In C language, it is necessary to provide the declaration of the prototype of any function. The
prototype of a library function is present in the corresponding header file.
For a user-defined function, its prototype is present in the current program. The definition of a
function and its prototype declaration should match.
If you wish to define a function called add() that performs the addition of two integer arguments
and returns the value as an integer, then the function declaration would be as follows −
Function Definition
The definition of a function and its prototype declaration should match. The definition consists
of a function header that matches the declaration and a function body.
// Function body;
return val;
Using this template, you can write the user-defined function add() as follows −
Note that the order of definition of user-defined functions is not important in a C program.
However, its prototype must be declared before calling the function.
In a program, the main() function is always the entry point, irrespective of whether it is the first
function or not. We needn't provide the prototype declaration of the main() function.
Calling a Function
To call a function, you should use a statement that complies with the declaration of the function
prototype. If the function is defined to receive a certain number of arguments, then the same
number and type of arguments must be passed to call that function.
The following statement calls the add() function that we defined above −
When a function is defined with arguments, the arguments in the parenthesis in front of the
function name are called formal arguments. In the above example, the function is defined with
"int a" and "int b" arguments; they are formal arguments.
When the function is called, the arguments passed to it are called the actual arguments. In the
example below, the variables "x" and "y" are the actual arguments.
A user-defined function may be defined to have any type of variables as formal arguments. It
includes primary types (int, float, char), array, pointer, or struct/union type variables.
A function should return a value to the calling environment. By default, the return type of a
function is int type. However, it can return any data type − primary type, array, pointer, or a
struct as well as a pointer. You can even define a function that returns a void type.
Example
If either the number or the type of actual and formal arguments or the return type as in the
forward declaration of a function and its definition don’t match, then the compiler reports an
error.
#include <stdio.h>
int x = 15, y = 5;
printf("%f", z);
return 0;
}
int c = a/b;
return c;
}
Output
In the code above, the declaration of the divide() function doesn’t match with its definition,
hence the compiler shows the following error −
In C, any function can call any other function, any number of times. A function can call itself
too. Such a self-calling function is called a recursive function.
The following program calls the main() function from inside main() itself −
#include <stdio.h>
int main(){
printf("Hello");
main();
return 0;
}
When executed, the program goes into an infinite loop. In practice, recursion has to be used so
that the program eventually terminates.
Callback Function in C
The callback is basically any executable code that is passed as an argument to other code, that is
expected to call back or execute the argument at a given time. We can define it in other words
like this: If the reference of a function is passed to another function argument for calling, then it
is called a callback function.
The mechanism of callbacks depends on function pointers. A function pointer is a variable that
stores the memory address of a function.
void hello(){
printf("Hello World.");
}
We can now call the function with the help of this function pointer, (*ptr)();
Example
#include <stdio.h>
void hello(){
printf("Hello World\n");
}
main(){
callback(ptr);
}
Output
In the example given below, we have also declared two functions with identical prototypes −
square() and root().
The callback function is defined to receive an argument as well as a function pointer with an
integer argument that matches with the above functions.
int callback(int a, int (*ptr)(int)){
return ret;
In the main() function, we place a call to the callback by passing an integer and the name of the
function (square / root) which becomes the function pointer in callback’s definition.
Example
#include <stdio.h>
#include <math.h>
int main(){
int x = 4;
return 0;
}
Output
Square of x: 4 is 16
Square root of x: 4 is 2
In this chapter, we explained how you can use function pointers so that we can enhance the
flexibility of our C programs. Additionally, we showed how you can create generic callback
functions that are not limited to a specific function pointer type.
Asynchronous Callback − In this case, the calling function triggers the callback but doesn’t
wait for it to finish. Instead, it continues its execution. It results in non-blocking operations. It’s
commonly used in event-driven programming.
Generic callback functions help developers write C programs that are versatile and better
adaptable.
Return Statement in C
The return statement terminates the execution of a function and returns control to the calling
function. Every function should have a return statement as its last statement. While using the
returns statement, the return type and returned value (expression) must be the same.
return value_or_expression;
The following main() function shows return as its last statement −
int main(){
// function body;
return 0;
}
The main() function returning 0 indicates the successful completion of the function. To indicate
failure of the function, a non−zero expression is returned.
A function's return type can be void. In such a case, return statement is optional. It may be
omitted, or return without any expression is used.
Example
#include <stdio.h>
/* function declaration */
void test(){
return;
}
int main() {
test();
printf("end");
return 0;
}
Each function in the program must have a forward declaration of its prototype. By default, each
function returns an integer. However, function of other return types without prototype is not
accepted.
Example
int main(){
test(5);
printf("end");
return 0;
}
float test(int a) {
return 1.1 ;
}
Output
This is because, function without prototype is assumed as of int type, which conflicts with the
definition.
The same error occurs if the return type of a function in the prototype doesn't match with the
type of return expression, an error is reported as below −
float test(int);
int main(){
test(5);
printf("end");
return 0;
}
float test(float a){
return 1.1 ;
}
A function can be defined with more than one arguments, but can return only one value. You can
however use multiple conditional return statements as shown below −
Example
int test(int);
int main() {
test(5);
printf("end");
return 0;
}
It is not possible to return an entire array as an argument to a function. However, you can return
a pointer to an array by specifying the array's name without an index.
Example
The following program shows how to pass an array to a function that returns an array after
performing a certain process.
#include <stdio.h>
int* test(int *);
int main(){
int a[] = {1,2,3,4};
int i;
int *b = test(a);
for (i=0; i<4; i++){
printf("%d\n", b[i]);
}
return 0;
}
int * test(int*a){
int i;
for (i=0; i<4; i++){
a[i] = 2*a[i];
}
return a;
}
Output
2
4
6
8
function can only return a single value using return statement. To return multiple values, we use
pointers or structures
Unlike the return statement, the exit() function is also used to terminate the execution of the
program without transferring the control back to the calling function. It is used inside a function
when the program has finished its execution or when an unrecoverable error occurs. It is a
standard way of handling exception errors in C. When exit() is called, the program control does
not return to the point where exit() was invoked. Instead, the control is handed back to the
operating system.
Syntax
exit() is typically called from the main() function or any other function to terminate the entire
program.
Since it results in termination of the program, exit() does not return a value directly to the caller
function. Instead, it terminates the program and returns a status code. It is an integer that
represents the exit status of the program, indicating success or failure.
Recursion in C
Recursion is the process by which a function calls itself. C language allows writing of such
functions which call itself to solve complicated problems by breaking them down into simple and
easy problems. These functions are known as recursive functions.
A recursive function in C is a function that calls itself. A recursive function is used when a
certain problem is defined in terms of itself. Although it involves iteration, using iterative
approach to solve such problems can be tedious. Recursive approach provides a very concise
solution to seemingly complex problems.
Syntax
int main(){
recursive_function();
}
While using recursion, programmers need to be careful to define an exit condition from the
function, otherwise it will go into an infinite loop.
Recursion is used to perform complex tasks such as tree and graph structure traversals. Popular
recursive programming solutions include factorial, binary search, tree traversal, tower of Hanoi,
eight queens problem in chess, etc.
A recursive program becomes concise, it is not easily comprehendible. Even if the size of the
code may reduce, it needs more resources of the processor, as it involves multiple IO calls to the
function.
Recursive functions are very useful to solve many mathematical problems such as calculating the
factorial of a number, generating Fibonacci series, etc.
n! = n X (n-1)!
It can be seen that we use factorial itself to define factorial. Hence this is a fit case to write a
recursive function. Let us expand the above definition for calculating the factorial value of 5.
5! = 5 X 4!
5 X 4 X 3!
5 X 4 X 3 X 2!
5 X 4 X 3 X 2 X 1!
5X4X3X 2X1
= 120
While we can perform this calculation using a loop, its recursive function involves successively
calling it by decrementing the number till it reaches 1.
The following program shows how you can use a non-recursive function to calculate the factorial
of a number −
#include <stdio.h>
#include <math.h>
// function declaration
int factorial(int);
int main(){
int a = 5;
int f = factorial(a);
Output
When you run this code, it will produce the following output −
a: 5
Factorial of a: 120
The following example calculates the factorial of a given number using a recursive function −
#include <stdio.h>
#include <math.h>
/* function declaration */
int factorial(int i){
Output
a: 5
Factorial of a: 120
When the main() function calls the factorial() function by passing the variable "a", its value is
stored in "i". The factorial() function successively calls itself.
In each call, the value of "i" is multiplied by its earlier value after reducing it by 1, till it reaches
1. As it reaches 1, the product of all the values between the initial value of the argument and 1 is
returned to the main() function.
While we can perform a sequential search for a certain number in the list using a for loop and
comparing each number, the sequential search is not efficient, especially if the list is too long.
The binary search algorithm checks if the index "start" is greater than the index "end". Based on
the value present at the variable "mid", the function is called again to search for the element.
We have a list of numbers arranged in ascending order. Then we find the midpoint of the list and
restrict the checking to either left or right of the midpoint, depending on whether the desired
number is less than or greater than the number at the midpoint.
#include <stdio.h>
if (array[mid] == element)
return mid;
int main(void){
int array[] = {5, 12, 23, 45, 49, 67, 71, 77, 82};
int n = 9;
int element = 67;
int index = bSearch(array, 0, n-1, element);
if(index == -1 ){
printf("Element not found in the array ");
}
else{
printf("Element found at index: %d", index);
}
return 0;
}
Output
In Fibonacci series, a number is the sum of its previous two numbers. To generate Fibonacci
series, the ith number is the addition of i−1 and i−2.
Example
The following example generates the first 10 numbers in the Fibonacci series for a given number
using a recursive function −
#include <stdio.h>
if(i == 0){
return 0;
}
if(i == 1){
return 1;
}
return fibonacci(i-1) + fibonacci(i-2);
}
int main(){
int i;
printf("%d\t\n", fibonacci(i));
}
return 0;
}
Output
When the above code is compiled and executed, it produces the following result −
0
1
1
2
3
5
8
13
21
34
Implementing recursion in a program is difficult for beginners. While any iterative process can
be converted in a recursive process, not all cases of recursion can be easily expressed iteratively.
Scope Rules in C
A scope in any programming is a region of the program where a defined variable can have its
existence and beyond that, the variable cannot be accessed.
Let us understand what are local and global variables, and formal parameters.
Local Variables in C
Variables that are declared inside a function or block are called local variables. They can be used
only by the statements that are inside that function or block of code. Local variables are not
known to functions outside their own.
Example
The following example shows how local variables are used. Here all the variables a, b, and c are
local to the main() function.
#include <stdio.h>
int main(){
/* actual initialization */
a = 10;
b = 20;
c = a + b;
return 0;
}
Output
When you run this code, it will produce the following output −
Global variables are defined outside the function, usually at the top of the program. Global
variables hold their values throughout the lifetime of a program and they can be accessed inside
any of the functions defined for the program.
A global variable can be accessed by any function. That is, a global variable is available for use
throughout your entire program after its declaration.
Example
The following code shows how global variables are used in a C program −
#include <stdio.h>
int main(){
/* actual initialization */
a = 10;
b = 20;
g = a + b;
return 0;
}
Output
A program can have the same name for local and global variables but the value of local variable
inside a function will take preference. Here is an example −
#include <stdio.h>
int main(){
return 0;
}
Output
When the above code is compiled and executed, it produces the following result −
Value of g = 10
Formal Parameters in C
Formal parameters are treated as local variables within a function and they take precedence over
global variables.
Example
#include <stdio.h>
int main(){
return 0;
}
return a + b;
}
Output
When the above code is compiled and executed, it produces the following result −
When a local variable is defined, it is not initialized by the system, you must initialize it yourself.
In contrast, global variables are initialized automatically by the system when you define them as
follows −
int 0
char '\0'
float 0
double 0
pointer NULL
It is a good programming practice to initialize variables properly, otherwise your program may
produce unexpected results, because uninitialized variables will take some garbage value already
available at their memory location.
Static Variables in C
In a C program, if a variable is declared as static, it belongs to the static storage class. Static
variables are initialized only once. The compiler persists with the variable till the end of the
program.
By default, a C variable is classified as an auto storage type. A static variable is useful when
you want to preserve a certain value between calls to different functions. Static variables are also
used to store data that should be shared between multiple functions.
The compiler allocates space to a static variable in the computer’s main memory.
Unlike auto, a static variable is initialized to zero and not garbage.
A static variable is not re-initialized on every function call, if it is declared inside a function.
A static variable has local scope.
Here,
datatype represents the type of variable like int, char, float, etc.
Example 1
#include <stdio.h>
int main(){
if(a != 0)
printf("The sum of static variable and auto variable: %d\n",(b+a));
return 0;
}
Output
When you run this code, it will produce the following output −
Example 2
In this example, x is an auto variable by default and initialized to 0 every time when the
counter() function is called. On each subsequent call, it gets re-initialized.
#include <stdio.h>
int counter();
int main(){
counter();
counter();
counter();
return 0;
}
int counter(){
int x;
printf("Value of x as it enters the function: %d\n", x);
x++;
printf("Incremented value of x: %d\n", x);
}
Output
However, when the variable x in the counter() function is declared as static, it is initialized to "0"
when the counter() function is called for the first time. On each subsequent call, it is not re-
initialized. Instead, it retains the earlier value.
Example 3
Change the declaration of "x" to "static int x = 0;" and run the program again −
#include <stdio.h>
int counter();
int main(){
counter();
counter();
counter();
return 0;
}
int counter(){
static int x = 0;
printf("Value of x as it enters the function: %d\n", x);
x++;
printf("Incremented value of x: %d\n", x);
}
Output
Now, when you run this code, it will produce the following output −
You can pass a static variable to a function. However, a formal parameter cannot be declared as
static, as C uses the function parameters as local auto variables inside a function.
Example 4
In this code, we pass a static variable to a function. However, the change in its value is not
reflected in the calling function.
#include <stdio.h>
int main(){
static int x = 5;
myfunction(x);
printf("in main - x:%d\n", x);
return 0;
}
Output
Incremented value of x: 6
in main - x:5
A static variable has certain similarities with a global variable. Both of them, if not explicitly
initialized, both are initialized to "0" (for numeric types) or "null pointers" (for pointers).
The scope of a static variable is restricted to the function or the block in which it is declared.
This is unlike a global variable, which is accessible throughout the program. Also, a static
variable can be imported in another code file, as we do by using the extern keyword.
Example
You can declare a global variable as static too. Take a look at the following example −
#include <stdio.h>
int myfunction();
static int x = 5;
int main(){
myfunction(x);
printf("Inside the main function, x: %d\n", x);
return 0;
}
int myfunction(){
x++;
printf("Incremented value of x: %d\n", x);
}
Output
When you run this code, it will produce the following output −
Incremented value of x: 6
Inside the main function, x: 6
It is better to use static variables to be accessible only within a file. On the other hand, use global
(with extern) variables to be accessible from anywhere in a program (if declared extern in other
files).
Global Variables in C
Global variables are defined outside a function, usually at the top of a program. Global variables
hold their values throughout the lifetime of a program and they can be accessed inside any of the
functions defined for the program.
If a function accesses and modifies the value of a global variable, then the updated value is
available for other function calls.
If a variable defined in a certain file, then you can still access it inside another code module as a
global variable by using the extern keyword. The extern keyword can also be used to access a
global variable instead of a local variable of the same name.
The following program shows how global variables are used in a program.
#include <stdio.h>
int main(){
/* actual initialization */
a = g * 2;
printf("Value of a = %d, and g = %d\n", a, g);
return 0;
}
Output
When you run this code, it will produce the following output −
Global variables are accessible in all the functions in a C program. If any function updates the
value of a global variable, then its updated value will subsequently be available for all the other
functions.
#include <stdio.h>
int function1();
int function2();
int main(){
function1();
printf("Updated value of Global variable g = %d\n", g);
function2();
printf("Updated value of Global variable g = %d\n", g);
return 0;
}
int function1(){
g = g + 10;
printf("New value of g in function1(): %d\n", g);
return 0;
}
int function2(){
printf("The value of g in function2(): %d\n", g);
g = g + 10;
return 0;
}
Output
Global variables are available to only those functions which are defined after their declaration.
In this example, we declared a global variable (x) before the main() function. There is another
global variable y that is declared after the main() function but before function1(). In such a case,
the variable y, even thought it is a global variable, is not available for use in the main() function,
as it is declared afterwards. As a result, you get an error.
#include <stdio.h>
int function1();
int main(){
printf("value of Global variable x= %d y=%d\n", x, y);
function1();
return 0;
}
int y = 20;
int function1(){
printf ("Value of Global variable x = %d y = %d\n", x, y);
}
Output
If you want to access a global variable when a local variable with same name is also there in the
program, then you should use the extern keyword.
In this C Program, we have a global variable and a local variable with the same name (x). Now,
let's see how we can use the keyword "extern" to avoid confusion −
#include <stdio.h>
// Global variable x
int x = 50;
int main(){
// Local variable x
int x = 10;{
extern int x;
printf("Value of global x is %d\n", x);
}
printf("Value of local x is %d\n", x);
return 0;
}
Output
When you run this code, it will produce the following output −
Value of global x is 50
Value of local x is 10
Global variables can simplify the programming logic. Global variables can be accessed across
functions and you need not use a parameter passing technique to pass variables from one
function to another. However, it is not wise or efficient to have too many global variables in a C
program, as the memory occupied by these variables is not released till the end of the program.
Using global declaration is not considered a good programming practice because it doesn’t
implement structured approach. Global declaration is also not advised from security point of
view, as they are accessible to all the functions. Finally, using global declarations can make a
program difficult to debug, maintain, and scale u
Arrays in C
Arrays in C are a kind of data structure that can store a fixed-size sequential collection of
elements of the same type. Arrays are used to store a collection of data, but it is often more
useful to think of an array as a collection of variables of the same type.
An array in C is a collection of data items of similar data type. One or more values same data
type, which may be primary data types (int, float, char), or user-defined types such as struct or
pointers can be stored in an array. In C, the type of elements in the array should match with the
data type of the array itself.
The size of the array, also called the length of the array, must be specified in the declaration
itself. Once declared, the size of a C array cannot be changed. When an array is declared, the
compiler allocates a continuous block of memory required to store the declared number of
elements.
Suppose we want to store the marks of 10 students and find the average. We declare 10 different
variables to store 10 different values as follows −
These variables will be scattered in the memory with no relation between them. Importantly, if
we want to extend the problem of finding the average of 100 (or more) students, then it becomes
impractical to declare so many individual variables.
Arrays offer a compact and memory-efficient solution. Since the elements in an array are stored
in adjacent locations, we can easily access any element in relation to the current element. As
each element has an index, it can be directly manipulated.
To go back to the problem of storing the marks of 10 students and find the average, the solution
with the use of array would be −
#include <stdio.h>
int main(){
int marks[10] = {50, 55, 67, 73, 45, 21, 39, 70, 49, 51};
int i, sum = 0;
float avg;
Output
Average: 52.000000
Array elements are stored in contiguous memory locations. Each element is identified by an
index starting with "0". The lowest address corresponds to the first element and the highest
address to the last element.
Declaring an Array in C
To declare an array in C, you need to specify the type of the elements and the number of
elements to be stored in it.
type arrayName[size];
The "size" must be an integer constant greater than zero and its "type" can be any valid C data
type. There are different ways in which an array is declared in C.
In such type of declaration, the uninitialized elements in the array may show certain random
garbage values.
int a[5];
Example
#include <stdio.h>
int main(){
int arr[5];
int i;
Output
a[0]: -133071639
a[1]: 32767
a[2]: 100
a[3]: 0
a[4]: 4096
Initializing an Array in C
If a set of comma-separated sequence values put inside curly brackets is assigned in the
declaration, the array is created with each element initialized with their corresponding value.
#include <stdio.h>
int main(){
int arr[5] = {0};
int i;
Output
When you run this code, it will produce the following output −
a[0]: 0
a[1]: 0
a[2]: 0
a[3]: 0
a[4]: 0
Example 2
If the list of values is less than the size of the array, the rest of the elements are initialized with
"0".
#include <stdio.h>
int main(){
int arr[5] = {1,2};
int i;
Output
When you run this code, it will produce the following output −
a[0]: 1
a[1]: 2
a[2]: 0
a[3]: 0
a[4]: 0
Example 3
When an array may be partially initialized, you can specify the element in the square brackets.
#include <stdio.h>
int main(){
int a[5] = {1,2, [4] = 4};
int i;
Output
a[0]: 1
a[1]: 2
a[2]: 0
a[3]: 0
a[4]: 4
Array Size
The compiler allocates a continuous block of memory. The size of the allocated memory depends
on the data type of the array.
If an integer array of 5 elements is declared, the array size in number of bytes would be
"sizeof(int) x 5"
#include <stdio.h>
int main(){
int arr[5] = {1, 2, 3, 4, 5};
printf("Size of array: %ld", sizeof(arr));
return 0;
}
Output
Size of array: 20
The sizeof operator returns the number of bytes occupied by the variable.
The size of each int is 4 bytes. The compiler allocates adjacent locations to each element.
#include <stdio.h>
int main(){
int a[] = {1, 2, 3, 4, 5};
int i;
Output
If we have the array type of double type, then the element at each subscript occupies 8 bytes
#include <stdio.h>
int main(){
double a[] = {1.1, 2.2, 3.3, 4.4, 5.5};
int i;
Output
The length of a "char" variable is 1 byte. Hence, a char array length will be equal to the array
size.
#include <stdio.h>
int main(){
char a[] = "Hello";
int i;
Output
Each element in an array is identified by a unique incrementing index, stating with "0". To
access the element by its index, this is done by placing the index of the element within square
brackets after the name of the array.
The elements of an array are accessed by specifying the index (offset) of the desired element
within the square brackets after the array name. For example −
The above statement will take the 10th element from the array and assign the value to the
"salary".
The following example shows how to use all the three above-mentioned concepts viz.
declaration, assignment, and accessing arrays.
#include <stdio.h>
int main(){
Output
n[0] = 100
n[1] = 101
n[2] = 102
n[3] = 103
n[4] = 104
The index gives random access to the array elements. An array may consist of struct variables,
pointers and even other arrays as its elements.
Arrays in Detail
Arrays, being an important concept in C, need a lot more attention. The following important
concepts related to arrays should be clear to a C programmer −
Multi-dimensional arrays
1 C supports multidimensional arrays. The simplest form of an
multidimensional array is the two-dimensional array.
Pointer to an array
4 You can generate a pointer to the first element of an array by
simply specifying the array name, without any index.
C - Properties of Array
Arrays are a very important data structure in C. Arrays make it easier to handle large amounts of
data. Due to their unique properties, arrays have a number of advantages over singular variables.
An array is a collection of values of same data type, and in a continuous block of memory. Most
of the important properties of arrays are a result of this unique composition.
Read this chapter to learn the properties of arrays that make them so useful in C programming.
All the elements of an array must be of the same data type. It ensures consistent access and
operations on the data.
initialization of 'int' from 'char *' makes integer from pointer without a cast
[-Wint-conversion]|
All the elements of an array are stored in contiguous memory locations, meaning they occupy a
block of memory next to each other. This feature of arrays allows for efficient random access
and memory management.
// This is accepted
#define SIZE = 10
int arr[SIZE];
Since an array can store all the elements of same type, the total memory occupied by it depends
on the data type.
Example
#include<stdio.h>
int main(){
int num[10] = {50, 55, 67, 73, 45, 21, 39, 70, 49, 51};
int size = sizeof(num) / sizeof(int);
return 0;
}
Output
When you run this code, it will produce the following output −
Each element in an array has a unique index, starting from "0". You can access individual
elements using their index within square brackets. Usually, an array is traversed with a for
loop running over its length and using the loop variable as the index.
Example
The following example demonstrates how you can traverse an array using a for loop −
#include <stdio.h>
int main(){
return 0;
}
Output
a[0]: 1
a[1]: 2
a[2]: 3
a[3]: 4
The name of an array is equivalent to a constant pointer to its first element. This feature lets you
use array names and pointers interchangeably in certain contexts.
Example
#include <stdio.h>
int main(){
int num[10] = {50, 55, 67, 73, 45, 21, 39, 70, 49, 51};
return 0;
}
Output
Each element in an array is identified by an index starting with "0". The lower bound of an array
is the index of its first element, which is always "0". The last element in the array "size−1" as its
index.
Example
The following code shows how you can print the elments at the lower bound and at the upper
bound of an array −
#include <stdio.h>
int main(){
int num[10] = {50, 55, 67, 73, 45, 21, 39, 70, 49, 51};
int size = sizeof(num) / sizeof(int);
return 0;
}
Output
When you run this code, it will produce the following output −
Multi−dimensional Arrays in C
When an array is declared with one value of size in square brackets, it is called a one-
dimensional array. In a one-dimensional array, each element is identified by its index or
subscript. However, you can declare an array in C with more number of indices to simulate a
two, three or multidimensional array.
int a[3][3] = {{1, 2, 3}, {11, 22, 33}, {111, 222, 333}};
You can think of a one-dimensional array as a list, and a two dimensional array as a table or a
matrix. Theoretically, there is no limit to the number of dimensions of an array, but in practice,
two-dimensional arrays are used in design of spreadsheets, databases, etc.
We can use an array in the construction of a struct data type to implement data structures such as
stacks, linked lists, and trees. For example, take a look at this stack that we have created using an
array.
Thus, arrays are an important tool in the armoury of a C programmer, as they can be used for
different applications. The concept of arrays in C is implemented by many subsequent
programming languages such as C++, C#, Java, etc.
Multi-dimensional Arrays in C
When an array is declared with one value of size in square brackets, it is called a one-
dimensional array. In a one-dimensional array, each element is identified by its index or
subscript. However, you can declare an array in C with more number of indices to simulate a
two, three or multidimensional array.
Multi-dimensional arrays can be termed as nested arrays. In such a case, each element in the
outer array is an array itself. Such type of nesting can be upto any level. If each element in the
outer array is another one-dimensional array, it forms a two-dimensional array. In turn, if the
inner array is an array of another set of one-dimensional array, it becomes a three-dimensional
array, and so on.
type name[size1][size2]...[sizeN];
int threedim[3][3][3];
Two-dimensional Arrays in C
This array arr has three rows and five columns. In C, a two-dimensional array is a row-major
array. The first square bracket always represents the dimension size of rows, and the second is
the number of columns. Obviously, the array has 3 x 5 = 15 elements. The array is initialized
with 15 comma-separated values put inside the curly brackets.
Elements are read into the array in a row-wise manner, which means the first 5 elements are
stored in the first row, and so on. Hence, the first dimension is optional in the array declaration.
To increase the readability, elements of each row can be optionally put in curly brackets as
follows −
1 2 3 4 5
10 20 30 40 50
5 10 15 20 25
The cell with row index 1 and column index 2 has 30 in it.
Example 1
The program below displays the row and column indices of each element in a 2D array −
#include <stdio.h>
int main(){
return 0;
}
Output
When you run this code, it will produce the following output −
a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8
In case of a two- or multi-dimensional array, the compiler assigns a memory block of the size
which is the product of dimensions multiplied by the size of the data type. In this case, the size is
3 x 5 x 4 = 60 bytes, 4 being the size of "int" data type.
Even though all the elements are stored in consecutive memory locations, we can print the
elements in row and column format with the use of nested loops.
Example 2
#include <stdio.h>
int main(){
return 0;
}
Output
When you run this code, it will produce the following output −
1 2 3 4 5
10 20 30 40 50
5 10 15 20 25
Three-dimensional Arrays in C
Students[hall][row][column]
To locate each student, you need to have three indices − hall number, row and column of the
table in the hall.
Example
#include<stdio.h>
int main(){
int i, j, k;
int arr[3][3][3]= {
{
{11, 12, 13},
{14, 15, 16},
{17, 18, 19}
},
{
{21, 22, 23},
{24, 25, 26},
{27, 28, 29}
},
{
{31, 32, 33},
{34, 35, 36},
{37, 38, 39}
},
};
for(i=0;i<3;i++){
for(j=0;j<3;j++){
for(k=0;k<3;k++){
printf("%4d",arr[i][j][k]);
}
printf("\n");
}
printf("\n");
}
return 0;
}
Output
When you run this code, it will produce the following output −
21 22 23
24 25 26
27 28 29
31 32 33
34 35 36
37 38 39
In this program, the sum of integer elements in each row of a two-dimensional array is displayed
−
#include <stdio.h>
int main(){
return 0;
}
Output
When you run this code, it will produce the following output −
Sum of row 0: 15
Sum of row 1: 150
Sum of row 2: 75
Matrix Multiplication
The product of two compatible matrices is equal to the dot products between rows of the first
matrix and columns of the second matrix.
If the two matrices are of size "a[m][n]" and "b[p][q]", the result of their multiplication is a
matrix of the size (the multiplication is possible only if "n" is equal to "p") is c[m][q].
The product of two matrices is the sum of the products across some row of matrix A with the
corresponding entries down some column of matrix B.
Example
#include<stdio.h>
int main(){
printf("\nMatrix 1 ...\n");
for(i = 0; i < 3; i++){
for(j = 0; j < 3; j++)
printf("%d\t", mat1[i][j]);
printf("\n");
}
printf("\nMatrix 2 ...\n");
for(i = 0; i < 3; i++){
for(j = 0; j < 3; j++)
printf("%d\t", mat2[i][j]);
printf("\n");
}
printf("\n");
}
return 0;
}
Output
When you run this code, it will produce the following output −
Matrix 1 ...
2 4 1
2 3 9
3 1 8
Matrix 2 ...
1 2 3
3 6 1
2 4 7
If you want to pass an array to a function, you can use either call by value or call by
reference method. In "call by value" method, the argument to the function should be an
initialized array. Here, an array of fixed size equal to the size of the array to be passed. In "call
by reference" method, the function argument is a pointer to the array.
In the following code, the main() function has an array of integers. A user-defined function
average() is called by passing the array to it. The average() function receives the array and adds
its elements using a for loop. It returns a float value representing the average of numbers in the
array.
Example 1
#include <stdio.h>
int main(){
int sum = 0;
int i;
Output
When you run this code, it will produce the following output −
arr[0]: 10
arr[1]: 34
arr[2]: 21
arr[3]: 78
arr[4]: 5
Average: 29.600000
In the following variation, the average() function is defined with two arguments, an uninitialized
array without any size specified. The length of the array declared in the main() function is
obtained by divising the size of the array with the size of int data type.
Example 2
#include <stdio.h>
int main(){
int sum = 0;
int i;
for(i = 0; i < length; i++){
printf("arr[%d]: %d\n", i, arr[i]);
sum += arr[i];
}
return (float)sum/length;
}
Output
When you run this code, it will produce the following output −
arr[0]: 10
arr[1]: 34
arr[2]: 21
arr[3]: 78
arr[4]: 5
Average: 29.600000
To use this approach, we should understand that the elements in an array are of similar data type
stored in continuous memory locations, and the array size depends on the data type. Also, the
address of the 0th element is the pointer to the array.
int *x = a;
Here x is the pointer to the array. It points to the 0th element. If the pointer is incremented by 1,
it points to the next element.
Example 1
#include <stdio.h>
int main(){
Output
When you run this code, it will produce the following output −
1
2
3
4
5
Let us use this characteristics for passing the array by reference. In the main() function, we
declare an array and pass its address to the max() function. The max() function traverses the
array using the pointer and returns the largest number in the array, back to the main() function.
Example 2
#include <stdio.h>
int main(){
Output
When you run this code, it will produce the following output −
arr[0]: 10
arr[1]: 34
arr[2]: 21
arr[3]: 78
arr[4]: 5
max: 78
The max() function receives the address of the array from main() in the pointer arr. Each time,
when it is incremented, it points to the next element in the original array.
The max() function can also access the array elements as a normal subscripted array as in the
following definition −
You can also pass the pointer of a two-dimensional array to a function. Inside the function, the
two-dimensional array is traversed with a nested for loop construct.
Example
#include <stdio.h>
int main(){
When you run this code, it will produce the following output −
10 34 21
5 25 16
In the following program, two strings are passed to the compare() function. In C, a string is an
array of char data type. We use the strlen() function to find the length of a string which is the
number of characters in it.
Example
#include <stdio.h>
#include <string.h>
int main(){
char a[] = "BAT";
char b[] = "BALL";
int ret = compare(a, b);
return 0;
}
When you run this code, it will produce the following output −
The length of string 'a' is less than the length of string 'b'
Return an Array from a Function in C
Functions in C help programmers to apply modular program design. A function can be defined to
accept one or more than one arguments but it can return a single value to the calling
environment. However, the function can be defined to return an array of values.
We implement these methods to calculate the square, the cube, and the square root of a given
number.
In the following example, we declare an uninitialized array in main() and pass it to a function
along with an integer. Inside the function, the array is filled with the square, cube, and square
root. The function returns the pointer of this array, using which the values are access and printed
in the main() function.
Example
#include <stdio.h>
#include <math.h>
int main(){
int x = 100;
float arr[3];
arrfunction(x, arr);
return 0;
}
Output
When you run this code, it will produce the following output −
Instead of passing an empty array from main(), we can declare an array inside the called function
itself, fill it with the required values, and return its pointer. However, returning a pointer of a
local variable is not acceptable, as it points to a variable that no longer exists.
Note that a local variable ceases to exist as soon as the scope of the function is over. Hence, we
need to use a static array inside the called function (arrfunction) and return its pointer back to the
main() function.
Example 1
#include <stdio.h>
#include <math.h>
float * arrfunction(int);
int main(){
int x = 100, i;
float *arr = arrfunction(x);
return 0;
}
return arr;
}
Output
When you run this code, it will produce the following output −
Example 2
Now, consider the following function which will generate 10 random numbers and return them
using an array and call this function as follows −
#include <stdio.h>
/* function to generate and return random numbers */
int * getRandom(){
static int r[10];
int i;
/* a pointer to an int */
int *p;
int i;
p = getRandom();
for(i = 0; i < 10; i++){
printf("*(p + %d): %d\n", i, *(p + i));
}
return 0;
}
Output
When the above code is compiled together and executed, it produces the following output −
r[0] = 2110147662
r[1] = 1427553496
r[2] = 1243625529
r[3] = 857484361
r[4] = 513293736
r[5] = 964923407
r[6] = 36104419
r[7] = 1248464892
r[8] = 1838450240
r[9] = 2096489563
*(p + 0): 2110147662
*(p + 1): 1427553496
*(p + 2): 1243625529
*(p + 3): 857484361
*(p + 4): 513293736
*(p + 5): 964923407
*(p + 6): 36104419
*(p + 7): 1248464892
*(p + 8): 1838450240
*(p + 9): 2096489563
The malloc() function is available as a library function in the stdlib.h header file. It dynamically
allocates a block of memory during the runtime of a program. Normal declaration of variables
causes the memory to be allocated at the compile time.
The malloc() function returns a generic void pointer. To assign values of a certain data type in
the allocated memory, it must be typecast to the required type. For example, to store "int" data, it
must be typecast to "int *" as follows −
Example
Let us allocate a block of memory sufficient to store three float values corresponding to the
square, cube and square root of a number, and return the float pointer to main(), inside which the
computed values are displayed.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
float * arrfunction(int);
int main(){
int x = 16, i;
float *arr = arrfunction(x);
return 0;
}
return arr;
}
Output
When you run this code, it will produce the following output −
In this method, we will declare a struct, inside which there is a float array as its element. The
called function (myfunction) declares a struct variable, populates the array element with square,
cube and the square root of the argument received by it, and returns it to the main() function.
Example
#include <stdio.h>
#include <math.h>
struct mystruct{
float arr[3];
};
int main(){
int x = 9;
struct mystruct s = myfunction(x);
printf("Square of %d: %f\n", x, [Link][0]);
printf("Cube of %d: %f\n", x, [Link][1]);
printf("Square root of %d: %f\n", x, [Link][2]);
return 0;
}
return s1;
}
Output
When you run this code, it will produce the following output −
Square of 9: 81.000000
Cube of 9: 729.000000
Square root of 9: 3.000000
Using the same approaches, you can pass and return a string to a function. A string in C is an
array of char type. In the following example, we pass the string with a pointer, manipulate it
inside the function, and return it back to the main() function.
Inside the called function, there is a local string. The string passed is concatenated with the local
string before returning.
Example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char * name = "TutorialsPoint";
char *arr = hellomsg(name);
printf("%s\n", arr);
return 0;
}
return arr;
}
Output
When you run this code, it will produce the following output −
Hello TutorialsPoint
Variable Length Arrays in C
int arr[10];
The size of an array, once declared, remains fixed during the execution of a program and cannot
be changed during its runtime. However, in case of a Variable Length Array (VLA), the compiler
allocates the memory with automatic storage duration on the stack. The support for VLAs was
added in the C99 standard.
int arr[length];
};
Example
The following example demonstrates how you can create a variable length array −
#include <stdio.h>
int main(){
int i, j;
int size; // variable to hold size of one-dimensional array
printf("Enter the size of one-dimensional array: ");
scanf("%d", &size);
int arr[size];
return 0;
}
Output
When you run this code, it will ask you enter the size of the array. Notice that the length of the
array is not fixed at the time of declaration. You define its size at runtime.
a[0]: 1
a[1]: 5
a[2]: 7
a[3]: 8
a[4]: 7
Example 1
#include <stdio.h>
int main(){
int i, j, x;
int arr2D[row][col];
for(i = 0; i < row; ++i){
for(j = 0; j < col; ++j){
printf("Enter a number: ");
scanf("%d", &x);
arr2D[i][j] = x;
}
}
return 0;
}
Output
Example 2
The following code declares a variable length one-dimensional array and populates it with
incrementing numbers −
#include <stdio.h>
int main(){
int n;
int arr[n];
return 0;
}
Output
Example 3
The following code fills the variable length array with randomly generated numbers using the
functions srand() and rand() from the stdlib.h header file.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// function prototype
void twoDArray(int row, int col, int a[row][col]);
// function prototype
int main(){
int i, j;
// counter variable
int size;
// declaring arrays
int arr[size];
// 2-D array
int arr2D[row][col];
// printing arrays
printf("One-dimensional array:\n");
// oneDArray(size, arr);
for(i = 0; i < size; ++i)
printf("a[%d]: %d\n", i, arr[i]);
printf("\nTwo-dimensional array:\n");
Output
Two-dimensional array:
92 19 79 23
56 21 44 98
8 22 89 54
93 1 63 38
Jagged Array
A jagged array is a collection of two or more arrays of similar data types of variable length. In C,
the concept of jagged array is implemented with the help of pointers of arrays.
In this program, we declare three one-dimensional arrays of different sizes and store their
pointers in an array of pointers that acts as a jagged array.
#include <stdio.h>
int main(){
int l1 = sizeof(a)/sizeof(int),
l2 = sizeof(b)/sizeof(int),
l3 = sizeof(c)/sizeof(int);
return 0;
}
Output
When you run this code, it will produce the following output −
1 2
3 4 5
6 7 8 9
VLA is a fast and more straightforward option compared to heap allocation. VLAs are supported
by most modern C compilers such as GCC, Clang etc. and are used by most compilers.
Pointers in C
Pointers in C are easy and fun to learn. Some complex C programming tasks can be performed
more easily with pointers, while some other tasks such as dynamic memory allocation cannot be
performed without using pointers. So it becomes necessary to learn pointers to become a perfect
C programmer.
With pointers, you can access and modify the data located in the memory, pass the data
efficiently between the functions, and create dynamic data structures like linked lists, trees, and
graphs.
As you know, every variable is a memory location and every memory location has its address
defined which can be accessed using the ampersand (&) operator, which denotes an address in
memory.
Consider the following example, which prints the address of the variables defined −
#include <stdio.h>
int main(){
int var1;
char var2[10];
return 0;
}
Output
When the above code is compiled and executed, it will print the address of the variables −
A pointer is a variable that stores the reference to another variable, which may be of any type
such as int, float or char, an array (one or multidimensional), struct or union, or even a pointer
type itself.
A pointer is a variable whose value is the address of another variable, i.e., the direct address of a
memory location. Like any variable or constant, you must declare a pointer before using it to
store any variable address. The general form of a pointer variable declaration is −
type *var-name;
Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of
the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for
multiplication. However, in this statement the asterisk is being used to designate a variable as a
pointer. Take a look at some of the valid pointer declarations −
A pointer references a location in memory. Obtaining the value stored at that location is known
as dereferencing the pointer.
In C, it is important to understand the purpose of the following two operators in the context of
pointer mechanism −
The & Operator − It is also known as the "Address-of operator". It is used for Referencing
which means taking the address of an existing variable (using &) to set a pointer variable.
The * Operator − It is also known as the "dereference operator". Dereferencing a pointer
is carried out using the * operator to get the value from the memory address that is pointed
by the pointer.
Pointers are used to pass parameters by reference. This is useful if a programmer wants a
function's modifications to a parameter to be visible to the function's caller. This is also useful
for returning multiple values from a function.
There are a few important operations, which we will do with the help of pointers very
frequently. (a) We define a pointer variable, (b) assign the address of a variable to a pointer
and (c) finally access the value at the address available in the pointer variable. This is done by
using unary operator * that returns the value of the variable located at the address specified by its
operand.
The following example shows how you can use the & and * operators to carry out pointer-related
opeartions in C −
#include <stdio.h>
int main(){
return 0;
}
Output
type *var;
The data type indicates the type of variable the address of which it can store. For example, "int
*x;". Here, the variable "x" is meant to store the address of another int variable.
Similarly, in "float *y; the variable "y" is a pointer that stores the memory location of a float
variable.
The & operator returns the address of an existing variable. We can assign it to the pointer
variable. Take a look at the following code snippet −
int a;
int *x = &a;
Assuming that the compiler creates the variable "a" at the address 1000 and "x" at the address
2000, then the address of "a" is stored in "x".
The deference operator returns the value at the address stored in the pointer variable. Here "*x"
will return the value of "a", i.e., the value stored in the memory address 1000, which in fact is the
value of "x". Let us understand this with the help of the following example.
Example 2
We will declare an int variable and display its value and address −
#include <stdio.h>
int main(){
Output
Example 3
We can also use %p format specifier to obtain the hexadecimal number of the memory address.
#include <stdio.h>
int main(){
Output
Variable: 100
Address: 000000000061FE1C
Example 4
In this example, the address of var is stored in the intptr variable with & operator
#include <stdio.h>
int main(){
Output
Variable: 100
Address of Variable: 2043225868
intptr: 140722351712012
Address of intptr: 2043225872
Example 5
Now let's take an example of a float variable and find its address −
#include <stdio.h>
int main(){
Output
var1: 10.550000
Address of var1: 1512452612
We can see that the address of this variable (any type of variable for that matter) is an integer.
So, if we try to store it in a pointer variable of "float" type, see what happens −
The compiler doesn’t accept this, and reports the following error −
Note: The type of a variable and the type of its pointer must be same.
In C, variables have specific data types that define their size and how they store values.
Declaring a pointer with a matching type (e.g., float *) enforces "type compatibility" between the
pointer and the data it points to.
Different data types occupy different amounts of memory space in C. For example, an "int"
typically takes 4 bytes, while a "float" might take 4 or 8 bytes depending on the system. Adding
or subtracting integers from pointers moves them in memory based on the size of the data they
point to.
Example 6
#include <stdio.h>
int main(){
Output
var1: 10.550000
Address of var1: 443414940
floatptr: 443414940
Address of floatptr: 443414944
The * operator is called the dereference operator. It returns the value of the variable that the
pointer is pointing to.
Example 7
#include <stdio.h>
int main(){
Output
var1: 10.550000
Address of var1: 451729484
floatptr: 451729484
Address of floatptr: 451729488
var1: 10.550000
Value at floatptr: 10.550000
We may have a pointer variable that stores the address of another pointer itself.
In the above figure, "a" is a normal "int" variable, whose pointer is "x". In turn, the variable
stores the address of "x".
Note that "y" is declared as "int **" to indicate that it is a pointer to another pointer variable.
Obviously, "y" will return the address of "x" and "*y" is the value in "x" (which is the address of
"a").
To obtain the value of "a" from "y", we need to use the expression "**y". Usually, "y" will be
called as the pointer to a pointer.
Example 8
Take a look at the following example −
#include <stdio.h>
int main(){
return 0;
}
Output
var: 10
Address of var: 951734452
inttptr: 951734452
Address of inttptr: 951734456
var: 10
Value at intptr: 10
ptrptr: 951734456
Address of ptrtptr: 951734464
intptr: 951734452
Value at ptrptr: 951734452
var: 10
*intptr: 10
**ptrptr: 10
You can have a pointer to an array as well as a derived type defined with struct. Pointers have
important applications. They are used while calling a function by passing the reference. Pointers
also help in overcoming the limitation of a function’s ability to return only a single value. With
pointers, you can get the effect of returning multiple values or arrays.
NULL Pointers
It is always a good practice to assign a NULL value to a pointer variable in case you do not have
an exact address to be assigned. This is done at the time of variable declaration. A pointer that is
assigned NULL is called a null pointer.
The NULL pointer is a constant with a value of "0" defined in several standard libraries.
Example
#include <stdio.h>
int main(){
return 0;
}
Output
When the above code is compiled and executed, it produces the following result −
The memory address "0" has a special significance; it signals that the pointer is not intended to
point to an accessible memory location. But by convention, if a pointer contains the null (zero)
value, it is assumed to point to nothing.
Pointers in Detail
Pointers have many but easy concepts and they are very important to C programming. The
following important pointer concepts should be clear to any C programmer −
Pointer arithmetic
1 There are four arithmetic operators that can be used in pointers:
++, --, +, -
Array of pointers
2
You can define arrays to hold a number of pointers.
Pointer to pointer
3
C allows you to have pointer on a pointer and so on.
A pointer variable in C stores the address of another variable. The address is always an integer.
So, can we perform arithmetic operations such as addition, subtraction etc. on the pointers? In
this chapter, we discuss which arithmetic operators use pointers in C as operands, and which
operations are not defined to be performed with pointers.
Increment/decrement operators
We know that the symbols ++ and -- are defined as increment and decrement operators in C.
They are unary operators, used in prefix or postfix manner with numeric variable operands, and
increment or decrement the value of the variable by one.
Assume that an integer variable x is created at address 1000 in the memory, with 10 as its value.
The x++ statement makes x as 11.
What happens if we declare y as pointer to x and increment y by 1 (with y++)? Assume that the
address of y itself is 2000.
Since the variable y stores 1000 (the address of x), we expect it to become 1001 because of ++
operator, but increment by 4, which is the size of int variable.
The reason behind this is, if address of x 1000, it occupies 4 bytes 1000, 1001, 1002 and 1003.
Hence, the next integer can be put only in 1004 and not before it. Hence y the pointer to x
becomes 1004 when incremented.
Example
#include <stdio.h>
int main(){
int x = 10;
int *y = &x;
printf("value of y before increment: %d\n", y);
y++;
printf("value of y after increment: %d", y);
}
Output
Similarly, the -- operator decrements the value by the size of the data type. Let us change the
types of x and y to double and float * and see the effect of decrement operator.
Example
#include <stdio.h>
int main(){
double x = 10;
double *y = &x;
printf("value of y before decrement: %ld\n", y);
y--;
printf("value of y after decrement: %ld", y);
}
Output
When an array is declared, the elements are stored in adjacent memory locations. In case of int
array, each array subscript is placed apart by 4 bytes, as the following figure shows −
Hence, if a variable stores the address of 0th element of the array, increment takes it to the 1st
element. Likewise, we can traverse the array by incrementing the pointer successively.
Example
#include <stdio.h>
int main(){
int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int len = sizeof(a)/sizeof(int);
int *x = a;
int i = 0;
for (i=0; i<len; i++){
printf("Address of subscript %d = %d Value = %d\n", i, x, *x);
x++;
}
return 0;
}
Output
Addition/subtraction of pointers
We are familiar with + and − operators when used with normal numeric operands. When used
with pointers, their behaviour is a little different.
Since the pointers are fairly large integers (especially in modern 64 bit systems), addition of two
pointers is meaningless. When we add a 1 to a pointer, it points to next location where an integer
may be stored. Obviously, when we add a pointer (itself a large integer), the location it points,
may not be in the memory layout.
However, subtraction of two pointers is realistic. It returns the number of data types that can fit
in the two pointers.
Let us the array in the previous example, and perform the subtraction of pointers of a[0] and a[9]
Example
#include <stdio.h>
int main(){
int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int *x = &a[0]; //zeroth element
int *y = &a[9]; //last element
printf("Add of a[0]: %ld add of a[9]: %ld\n", x, y);
printf("subtraction of two pointers: %ld", y-x);
}
Output
It can be seen that the numerical difference between the two integers is 36, it tells that the
subtraction is 9, because it can accommodate 9 integers between the two pointers.
Pointer Comparisons
Pointers may be compared by using relational operators, such as ==, <, and >. If p1 and p2 point
to variables that are related to each other, such as elements of the same array, then p1 and p2 can
be meaningfully compared.
The following program modifies the previous example − one by incrementing the variable
pointer so long as the address to which it points is either less than or equal to the address of the
last element of the array, which is &var[MAX − 1]
Example
#include <stdio.h>
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr;
Output
A pointer In C is a variable that stores the address of another variable. The pointer acts as a
reference to the original variable. A pointer can be passed to a function, just like any other is
passed. A function in C can be called in two ways −
To call a function by reference, you need to define it to receive the pointer to a variable in the
calling function.
Syntax
When a function is called by reference, the pointer of the actual argument variables passed,
instead of their values.
It overcomes the limitation of pass by value. Changes to the value inside the called function
are done directly at the address stored in the pointer. Hence, we can manipulate the
variables in one scope from another.
It also overcomes the limitation of a function that it is able to return only one expression.
By passing pointers, the effect of processing of a function takes place directly at the
address. Secondly, imore than one values can be returned if we return pointer of an array
or struct variable.
In this chapter, we shall see how to −
Let us define add() function that receives the references of two variables. When such a function
is called, we pass the address of the actual argument. Let us call add() function by reference from
inside main() function.
Example
#include <stdio.h>
/* function declaration */
int add(int *, int *);
int main(){
int a=10, b=20;
int c = add(&a, &b);
printf("addition : %d", c);
}
int add(int *x, int *y){
int z = *x + *y;
return z;
}
Output
addition :30
One of the most cited applications of passing a pointer to a function is how we can swap the
values of two variables.
The following function receives the reference of two variables whose values are to be swapped.
return 0;
}
The main() function has two variables a and b, their addresses are passes as arguments to swap()
function.
Example
#include <stdio.h>
int swap(int *x, int *y){
int z;
z = *x;
*x = *y;
*y = z;
}
int main () {
return 0;
}
Output
In C, the name of array is the address of the first element of the array, or in other words, the
pointer to array. In the following example, we declare an uninitialized array in main() and pass
its pointer to a function, along with an integer. Inside the function, the array is filled with the
square, cube and square root. The function returns the pointer of this array, using which the
values are access and printed in main() function.
Example
#include <stdio.h>
#include <math.h>
int arrfunction(int, float *);
int main(){
int x=100;
float arr[3];
arrfunction(x, arr);
printf("Square of %d: %f\n", x, arr[0]);
printf("cube of %d: %f\n", x, arr[1]);
printf("Square root of %d: %f\n", x, arr[2]);
return 0;
}
int arrfunction(int x, float *arr){
arr[0]=pow(x,2);
arr[1]=pow(x, 3);
arr[2]=pow(x, 0.5);
}
Output
Let us have a look at another example, where pointers are passed to a function. In the following
program, two strings are passed to compare() functions. In C, as string is an array of char data
type. We use strlen() function to find the length of string which is the number of characters in it.
Example
#include <stdio.h>
#include <string.h>
int compare( char *, char *);
int main() {
char a[] = "BAT";
char b[] = "BALL";
int ret = compare(a, b);
return 0;
}
int compare (char *x, char *y){
int val;
if (strlen(x)>strlen(y)){
printf("length of string a is greater than or equal to length of string b");
}
else{
printf("length of string a is less than length of string b");
}
}
Output
In C, a structure is a heterogenous data type, with its elements of different data types. In the
example explained below, a struct variable of rectangle type is declared in main() and its address
is passed to a user−defined function − area(). When called, the area() function is able to use the
elements of the variable with the indirection operator −>. It computes the result and assigns it to
the area element r−>area.
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
double area;
};
int area(struct rectangle *);
int main () {
struct rectangle s;
printf("Input length and breadth of a rectangle");
scanf("%f %f", &[Link], &[Link]);
area(&s);
return 0;
}
int area(struct rectangle *r){
r->area = (double)(r->len*r->brd);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", r->len, r->brd, r->area);
return 0;
}
Output
The logical extension of the concept of passing pointer to a function leads to passing Union
pointer, pointer of a multi−dimensional array, passing pointer of a self−referential structure etc.,
all these have important uses in different application areas such as complex data structures,
hardware control programming etc.
C - Strings
Strings are actually one-dimensional array of characters terminated by a null character '\0'. Thus
a null-terminated string contains the characters that comprise the string followed by a null.
The following declaration and initialization create a string consisting of the word "Hello". To
hold the null character at the end of the array, the size of the character array containing the string
is one more than the number of characters in the word "Hello."
If you follow the rule of array initialization then you can write the above statement as follows −
Actually, you do not place the null character at the end of a string constant. The C compiler
automatically places the '\0' at the end of the string when it initializes the array. Let us try to print
the above mentioned string −
Live Demo
#include <stdio.h>
int main () {
When the above code is compiled and executed, it produces the following result −
strcpy(s1, s2);
1
Copies string s2 into string s1.
strcat(s1, s2);
2
Concatenates string s2 onto the end of string s1.
strlen(s1);
3
Returns the length of string s1.
strcmp(s1, s2);
4 Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater
than 0 if s1>s2.
strchr(s1, ch);
5 Returns a pointer to the first occurrence of character ch in string
s1.
strstr(s1, s2);
6
Returns a pointer to the first occurrence of string s2 in string s1.
Live Demo
#include <stdio.h>
#include <string.h>
int main () {
return 0;
}
When the above code is compiled and executed, it produces the following result −
C - Array of Strings
or
Let us declare and initialize an array of strings to store names of Ten computer languages, each
with the maximum length of fifteen characters.
How is this array stored in the memory? We know that each char type occupies 1 byte in the
memory. Hence, this array will be allocated a block of 150 bytes. Although this block is
contagious memory locations, each group of 15 bytes constitutes a row.
Assuming that the array is situated at memory address 1000, the logical layout of this array can
be shown as in the following figure −
Example
#include <stdio.h>
int main () {
char langs [10][15] = {
"PYTHON",
"JAVASCRIPT",
"PHP",
"NODE JS",
"HTML",
"KOTLIN",
"C++",
"REACT JS",
"RUST",
"VBSCRIPT"
};
int i;
for (i=0; i<10; i++){
printf("%s\n", langs[i]);
}
return 0;
}
Output
PYTHON
JAVASCRIPT
PHP
NODE JS
HTML
KOTLIN
C++
REACT JS
RUST
VBSCRIPT
Note that, the size of each string is not equal to the row size in the declaration of the array. The
\0 symbol signals the termination of the string, and the remaining cells in the row are empty.
Thus a substantial part of the memory allocated to the array is unused and thus wasted.
To use the memory more efficiently, we can use the pointers. Instead of a two−dimensional char
array, we declare a one−dimensional array of char * type.
In the two−dimensional array of characters, the strings occupied 150 bytes. As against this, in
array of pointers, the strings occupy far less number of bytes, as each string is randomly
allocated memory as shown below −
We can use the for loop as follows to print the array of strings −
Example
#include <stdio.h>
int main(){
char *langs [10] = {
"PYTHON",
"JAVASCRIPT",
"PHP",
"NODE JS",
"HTML",
"KOTLIN",
"C++",
"REACT JS",
"RUST",
"VBSCRIPT"
};
int i;
for (i=0; i<10; i++)
printf("%s\n", langs[i]);
return 0;
}
Output
PYTHON
JAVASCRIPT
PHP
NODE JS
HTML
KOTLIN
C++
REACT JS
RUST
VBSCRIPT
The langs is a pointer to an array of 10 strings. Therefore, if langs[0] points to address 5000 then
langs+1 will point to address 5004 which stores the pointer to the second string..
Hence, we can also use the following variation of the loop to print the array of strings.
int i;
for (i=0; i<10; i++){
printf("%s\n", *(langs+i));
}
When strings are stored in array, there are a lot use cases. Let study some of the use cases.
We store the length of first string and its position (which is 0) in the variables l and p
respectively. Inside a for loop, we update these variables whenever a string of larger length is
found.
Example
#include <stdio.h>
#include <string.h>
int main () {
char langs [10][15] = {
"PYTHON",
"JAVASCRIPT",
"PHP",
"NODE JS",
"HTML",
"KOTLIN",
"C++",
"REACT JS",
"RUST",
"VBSCRIPT"
};
int i;
int l = strlen(langs[0]); int p = 0;
for (i=0; i<10; i++){
if (strlen(langs[i])>=l){
l=strlen(langs[i]);
p=i;
}
}
printf("Language with longest name: %s Length: %d", langs[p], l);
return 0;
}
Output
We need to use the strcmp() function for comparison of two strings. If the value of comparison
of strings is greater than 0, it means that the first argument string appears later than the second in
alphabetical order. We then swap these two strings with strcmp() function.
Example
#include <stdio.h>
#include <string.h>
int main () {
char langs [10][15] = {
"PYTHON",
"JAVASCRIPT",
"PHP",
"NODE JS",
"HTML",
"KOTLIN",
"C++",
"REACT JS",
"RUST",
"VBSCRIPT"
};
int i, j;
char temp[15];
for (i=0; i<9; i++){
for (j=i+1; j<10; j++){
if (strcmp(langs[i], langs[j])>0){
strcpy(temp, langs[i]);
strcpy(langs[i], langs[j]);
strcpy(langs[j], temp);
}
}
}
for (i=0; i<10; i++){
printf("%s\n", langs[i]);
}
return 0;
}
Output
C++
HTML
JAVASCRIPT
KOTLIN
NODE JS
PHP
PYTHON
REACT JS
RUST
VBSCRIPT
In this chapter, we have learned how to declare an array of strings, and how to manipulate it with
the help of string functions. The string.h header file provides a number of library functions for
string manipulations. These functions will be discussed in a separate chapter in this tutorial.
Structures in C
A structure in C is a derived or user-defined data type. We use the keyword struct to define a
custom data type that groups together the elements of different types. The difference between an
array and a structure is that an array is a homogenous collection of similar types, whereas a
structure can have elements of different type stored adjacently and identified by a name.
We are often required to work with values of different data types having certain relationship
among them. For example, a book is described by
its title (string), author (string), price (double), number of pages (integer), etc. Instead of using
four different variables, these values can be stored in a single struct variable.
Defining a Structure
To define a structure, you must use the struct statement. The struct statement defines a new data
type, with more than one member.
The structure tag is optional and each member definition is a normal variable definition, such as
"int i;" or "float f;" or any other valid variable definition.
At the end of the structure's definition, before the final semicolon, you can specify one or more
structure variables but it is optional.
struct book{
char title[50];
char author[50];
double price;
int pages;
} book1;
Here, we declared the structure variable book1 at the end of the structure definition. However,
you can do it separately in a different statement.
Usually, a structure is declared before the first function is defined in the program, after
the include statements. That way, the derived type can be used for declaring its variable inside
any function.
The initialization of a struct variable is done by placing the value of each element inside curly
brackets.
The four elements of the struct variable book1 are accessed with the dot (.) operator. Hence,
"[Link]" refers to the title element, "[Link]" is the author name, "[Link]" is the
price, "[Link]" is the fourth element (number of pages).
Example 1
#include <stdio.h>
struct book{
char title[10];
char author[20];
double price;
int pages;
};
int main(){
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325};
Output
Title: Learn C
Author: Dennis Ritchie
Price: 675.500000
Pages: 325
Size of book struct: 48
Example 2
In the above program, we will make a small modification. Here, we will put the type
definition and the variable declaration together, like this −
struct book{
char title[10];
char author[20];
double price;
int pages;
} book1;
Note that if you a declare a struct variable in this way, then you cannot initialize it with curly
brackets. Instead, the elements need to be assigned individually.
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
char author[20];
double price;
int pages;
} book1;
int main(){
strcpy([Link], "Learn C");
strcpy([Link], "Dennis Ritchie");
[Link] = 675.50;
[Link] = 325;
Output
When you execute this code, it will produce the following output −
Title: Learn C
Author: Dennis Ritchie
Price: 675.500000
Pages: 325
The "= operator" can be used to assign one struct variable to another. Let's have two struct book
variables, book1 and book2. The variable book1 is initialized with declaration, and we wish to
assign the same values of its elements to that of book2.
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}, book2;
strcpy([Link], [Link]);
strcpy([Link], [Link]);
[Link] = [Link];
[Link] = [Link];
Note the use of strcpy() function to assign the value to a string variable instead of using the "=
operator".
Example 3
You can also assign book1 to book2 so that all the elements of book1 are respectively assigned
to the elements of book2. Take a look at the following program code −
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
char author[20];
double price;
int pages;
};
int main(){
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}, book2;
book2 = book1;
Output
Title: Learn C
Author: Dennis Ritchie
Price: 675.500000
Pages: 325
Size of book struct: 48
You can pass a structure as a function argument in the same way as you pass any other variable
or pointer.
Example
Take a look at the following program code. It demonstrates how you can pass a structure as a
function argument −
#include <stdio.h>
#include <string.h>
struct Books{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* function declaration */
void printBook(struct Books book);
int main(){
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
strcpy([Link], "C Programming");
strcpy([Link], "Nuha Ali");
strcpy([Link], "C Programming Tutorial");
Book1.book_id = 6495407;
/* book 2 specification */
strcpy([Link], "Telecom Billing");
strcpy([Link], "Zara Ali");
strcpy([Link], "Telecom Billing Tutorial");
Book2.book_id = 6495700;
Output
When the above code is compiled and executed, it produces the following result −
Pointers to Structures
You can define pointers to structures in the same way as you define pointers to any other
variable −
You can store the address of a structure variable in the above pointer variable struct_pointer. To
find the address of a structure variable, place the '&' operator before the structure's name as
follows −
struct book{
char title[10];
char author[20];
double price;
int pages;
};
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325},
struct book *strptr;
To access the members of a structure using a pointer to that structure, you must use the →
operator as follows −
struct_pointer->title;
C defines the → symbol to be used with struct pointer as the indirection operator (also
called struct dereference operator). It helps to access the elements of the struct variable to
which the pointer reference to.
Example
In this example, strptr is a pointer to struct book book1 variable. Hence, strrptr→title returns
the title, just like [Link] does.
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
char author[20];
double price;
int pages;
};
When you run this code, it will produce the following output −
Title: Learn C
Author: Dennis Ritchie
Price: 675.500000
Pages: 325
Note: The dot (.) operator is used to access the struct elements via the struct variable. To access
the elements via its pointer, we must use the indirection (->) operator
A struct variable is like a normal variable of primary type, in the sense that you can have an array
of struct, you can pass the struct variable to a function, as well as return a struct from a function.
You may have noted that you need to prefix "struct type" to the name of the variable or pointer at
the time of declaration. This can be avoided by creating a shorthand notation with the help
of typedef keyword, which we will explain in a subsequent chapter.
Structures are used in different applications such as databases, file management applications, and
for handling complex data structures such as tree and linked lists.
Bit Fields
Bit Fields allow the packing of data in a structure. This is especially useful when memory or data
storage is at a premium. Typical examples include −
Packing several objects into a machine word, for example, 1-bit flags can be compacted.
Reading external file formats − non-standard file formats could be read in, for example, 9-
bit integers.
C allows us to do this in a structure definition by putting :bit length after the variable. For
example −
struct packed_struct{
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
Here, the packed_struct contains 6 members: Four 1 bit flags f1..f3, a 4-bit type and a 9-bit
my_int.
C automatically packs the above bit fields as compactly as possible, provided that the maximum
length of the field is less than or equal to the integer word length of the computer. If this is not
the case, then some compilers may allow memory overlap for the fields while others would store
the next field in the next word.
In C, struct is a derived data type. Just as we can pass arguments of primary data types, a variable
of struct data type can also be passed to a function. You can also pass structures using call by
value as well as call by reference methods. A function in C may also return a struct data type.
A derived type is a combination of one or more elements of any of the primary types as well as
the same or different derived type. It is possible to pass elements to a function, either by value or
by reference.
In the following example, a derived type called rectangle with two elements. A struct variable r
with has the elements [Link] and [Link], and they are passed to a function. The area() function then
computes the area of rectangle.
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
};
int area(float, float);
int main () {
struct rectangle r;
printf("Input length and breadth of a rectangle\n");
//scanf("%f %f", &[Link], &[Link]);
[Link]=10.50; [Link]=20.5;
area([Link], [Link]);
return 0;
}
int area(float a, float b){
double area = (double)(a*b);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", a, b, area);
return 0;
}
Output
Let us modify the above example, to pass the struct variable itself (instead of its elements) to the
area() function. The rectangle struct type also has an additional element called area. Inside the
function, the elements of the struct variable are accessed though the dot operator, and the area is
calculated.
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
double area;
};
int area(struct rectangle);
int main () {
struct rectangle r;
printf("Input length and breadth of a rectangle\n");
//scanf("%f %f", &[Link], &[Link]);
[Link]=10.50; [Link]=20.5;
area(r);
return 0;
}
int area(struct rectangle r){
[Link] = (double)([Link]*[Link]);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", [Link], [Link], [Link]);
return 0;
}
Output
We know that a function in C is able to return a value of any of the types. In this example, the
area() function is defined to return a struct variable.
In main(), inputs are accepted from the user for length and breadth, and are passed to the
function. Inside the function, the area is computed, and a struct variable is populated and
returned to the main() function, where its elements are displayed.
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
double area;
};
struct rectangle area(float x, float y);
int main () {
struct rectangle r;
float x, y;
printf("Input length and breadth of a rectangle\n");
//scanf("%f %f", &x, &y);
x=10.5; y=20.5;
r=area(x, y);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", [Link], [Link], [Link]);
return 0;
}
struct rectangle area(float x, float y){
double area = (double)(x*y);
struct rectangle r = {x, y, area};
return r;
}
Output
In C, a function may be defined to have its arguments passed by value or reference. A reference
is the pointer to an existing variable. In the example explained below, a struct variable of
rectangle type is declared in main() and its address is passed to a user−defined function − area().
When called, the area() function is able to use the elements of the variable with the indirection
operator −>. It computes the result and assigns it to the area element r−>area.
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
double area;
};
int area(struct rectangle *);
int main () {
struct rectangle r;
printf("Input length and breadth of a rectangle\n");
//scanf("%f %f", &[Link], &[Link]);
[Link]=10.50; [Link]=20.5;
area(&r);
return 0;
}
int area(struct rectangle *r){
r->area = (double)(r->len*r->brd);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", r->len, r->brd, r->area);
return 0;
}
Output
Let us rewrite the above code to define the area() function and return a pointer to a struct
rectangle data type. The area() function has two call by value arguments. The main() function
reads the length and breadth from the user and passes them to the area() function, which
populates a struct variable and passes its reference back to main().
Example
#include <stdio.h>
#include <string.h>
struct rectangle{
float len, brd;
double area;
};
struct rectangle * area(float x, float y);
int main (){
struct rectangle *r;
float x, y;
printf("Input length and breadth of a rectangle\n");
//scanf("%f %f", &x, &y);
x=10.5; y=20.5;
r=area(x, y);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", r->len, r->brd, r->area);
return 0;
}
struct rectangle * area(float x, float y){
double area = (double)(x*y);
static struct rectangle r;
[Link] = x; [Link]=y; [Link]=area;
return &r;
}
Output
In C, the struct keyword is used to define a derived data type. Once defined, you can declare an
array of struct variables, just like an array of int, float or char types is declared. An array of struct
has a number of use cases, such as in storing records similar to a database table, where you have
each row with different data types.
Usually, a struct type is defined in the beginning of the code, so that its type can be used inside
any of the functions. You can declare an array of structure and later on fill data in it, or you can
initialize it at the time of declaration itself.
struct book{
char title[10];
double price;
int pages;
};
During the program, you can declare an array and initialize it by giving the values of each
element inside curly brackets. Each element in the struct array is a struct value itself. Hence, we
have the nested curly brackets as shown below −
How does the compiler allocate the memory? Since we have an array of three elements, of struct
whose size is 32 bytes, the array occupies 32X3 bytes. Each block of 32 bytes will accommodate
a title, price and pages element.
L E A R N C 675.50 325
C P O I N T E R S 175 225
C P E A R L S 250 250
You can also declare an empty struct array. Afterwards, you can either read the data in it with
scanf() statements, or assign value to each element as shown below −
We can also accept data from the user to fill the array
Example
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
double price;
int pages;
};
int main (){
struct book b[3];
strcpy(b[0].title, " Learn C ");
b[0].price = 650.50;
b[0].pages=325;
strcpy(b[1].title, " C Pointers ");
b[1].price = 175;
b[1].pages=225;
strcpy(b[2].title, "C Pearls ");
b[2].price = 250;
b[2].pages=325;
printf("\nList of books\n");
for (int i=0; i<3; i++){
printf("Title: %s Price: %7.2lf No of Pages: %d\n", b[i].title, b[i].price, b[i].pages);
}
return 0;
}
Output
List of books
Title: Learn C Price: 650.50 No of Pages: 325
Title: C Pointers Price: 175.00 No of Pages: 225
Title: C Pearls Price: 250.00 No of Pages: 325
Example
In the example below, a struct type call student is defined. Its elements are name, marks in phy,
che and maths; and the percentage. An array of three struct student types is declared and first
four elements are populated by user input, with a for loop. Inside the loop itself, the percent
element of each subscript is computed.
Finally, an array of students with their names, marks and percentage is printed to show the
marklist.
#include <stdio.h>
#include <string.h>
struct student{
char name[10];
int physics, chem, math;
double percent;
};
int main (){
struct student s[3];
strcpy(s[0].name, " Ravi ");
s[0].physics = 50;
s[0].chem = 60;
s[0].math =70;
int i;
for (i=0; i<3; i++){
s[i].percent = (double)(s[i].physics + s[i].math + s[i].chem)/3;
}
printf("\nName\tPhy\tChe\t\Maths\tPercent\n");
for (i=0; i<3; i++) {
printf("%s\t%d\t%d\t%d\t%5.2lf\n", s[i].name, s[i].physics, s[i].chem, s[i].math,
s[i].percent);
}
return 0;
}
Output
Let us take another example of struct array. The assay of book struct type is sorted in ascending
order of the price by implementing bubble sort technique. Note that elements of one struct
variable can be directly assigned to other struct variable directly with assignment operator.
Example
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
double price;
int pages;
};
int main (){
struct book b[3] ={
{"Learn C", 650.50, 325}, {"C Pointers", 175, 225}, {"C Pearls", 250, 250}
};
int i, j;
struct book temp;
for (i=0; i<2; i++){
for (j=i; j<3; j++){
if (b[i].price>b[j].price){
temp = b[i];
b[i] = b[j];
b[j] = temp;
}
}
}
printf("\nList of books in ascending order of price\n");
for (i=0; i<3; i++){
printf("Title: %s Price: %7.2lf No of Pages: %d\n", b[i].title, b[i].price, b[i].pages);
}
return 0;
}
Output
We can also declare a pointer to struct array. C uses −> operator as the indirection operator to
access internal elements of the struct variables.
Example
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
double price;
int pages;
};
int main () {
struct book b[3] ={
{"Learn C", 650.50, 325}, {"C Pointers", 175, 225}, {"C Pearls", 250, 250}
};
struct book *ptr = b;
int i;
for (i=0; i<3; i++){
printf("Title: %s Price: %7.2lf No of Pages: %d\n", ptr->title, ptr->price, ptr->pages);
ptr++;
}
return 0;
}
Output
In C, a pointer is a variable that holds the address of another variable. If you have defined a
derived data type with the struct keyword, you can declare a variable of this type, and hence you
can also declare a pointer variable to store its address. A pointer to struct is thus a variable that
refers to a struct variable.
A new derived data type is defined with struct keyword as following syntax −
struct type{
type var1;
type var2;
type var3;
...
...
};
You can then declare a pointer variable and store the address of var. We know that to declare a
variable as a pointer, it must be prefixed by *, and to obtain the address of a variable, we use the
& operator.
struct type *ptr = &var;
To access the elements of the structure with pointer, we use a special operator called as an
indirection operator ( −>> ).
A user−defined struct type book is defined below. We declare a book variable and a pointer.
struct book{
char title[10];
double price;
int pages;
};
struct book b1 = {"Learn C", 675.50, 325},
struct book *strptr;
strptr = &b1;
C defines −>: symbol to be used with struct pointer as indirection operator (also called struct
dereference operator). It helps to access the elements of the struct variable to which the pointer
reference to.
To access an individual element in the struct, the indirection operator is used as follows
Ptr-> membername;
For example −
The struct pointer uses indirection operator or dereference operator to fetch the values of the
struct elements of a struct variable. The dot operator is used to fetch the values with reference to
the struct variable.
Hence
Example
#include <stdio.h>
#include <string.h>
struct book{
char title[10];
double price;
int pages;
};
int main () {
struct book b1 = {"Learn C", 675.50, 325};
struct book *strptr;
strptr = &b1;
printf("Title: %s\n", strptr->title);
printf("Price: %lf\n", strptr->price);
printf("No of Pages: %d\n", strptr->pages);
return 0;
}
Output
Title: Learn C
Price: 675.500000
No of Pages: 325
The dot operator (.) is used to access the struct elements via the struct variable.
To access the elements via its pointer, we must use the indirection (−>) operator.
Example
Consider another example which explains the functioning of pointers to structures. A new
derived data type person is defined with the struct keyword. A variable of its type and a pointer
is declared.
The user is asked to input name, age and weight. The values are stored in the structure elements
by accessing them with the indirection operator −>
#include <stdio.h>
#include <string.h>
struct person{
char *name;
int age;
float weight;
};
int main(){
struct person *personPtr, person1;
strcpy([Link], "Meena");
[Link] = 40;
[Link] = 60;
personPtr = &person1;
printf("Displaying: \n");
printf("Name: %s\n", personPtr->name);
printf("Age: %d\n", personPtr->age);
printf("weight: %f", personPtr->weight);
return 0;
}
Output
Let us run the above program that will produce the following result −
Displaying:
Name: Meena
Age: 40
weight: 60.000000
C allows you to declare an array of struct, as well as an array of pointers. Here, each element in
the struct pointer array is a reference to a struct variable.
A struct variable is like a normal variable of primary type, in the sense that you can have an array
of struct, you can pass the struct variable to a function, as well as return a struct from the
function.
You may have noted that you need to prefix struct type to the name of the variable or pointer at
the time of declaration. This can be avoided by creating a shorthand notation with the help of
typedef keyword, which we shall learn in a latter chapter.
Pointers to structures are very important, as they are employed to create complex and dynamic
data structures such as linked lists, trees, graphs, etc. Such data structures use self−referential
structs, where we define a struct type that has one of its elements as a pointer to the same type.
An example of a self−referential structure with a pointer to an element of its own type is defined
as follows −
struct mystruct{
int a;
struct mystruct *b;
};
C - Self-referential Structures
As the name suggests, a self−referential structure is a struct data type in C, where one or more of
its elements are pointer to variables of its own type. Self−referential user−defined types are of
immense use in C programming. They are extensively used to build complex and dynamic data
structures such as linked lists, and trees etc. In C, an array is allocated the required memory at
the compile−time, and the array size cannot be modified during the runtime. Self−referential
structures let you emulates the arrays by handling the size dynamically.
The file management systems in OS software are built upon dynamically constructed tree
structures, which are manipulated by self−referential structures. Self−referential structures are
also employed in many complex algorithms.
strut typename{
type var1;
type var2;
..
struct typename *var3;
}
Let us understand how self−referential structure is used, with the help of the following example
−
We define a struct type called mystruct. It has an int element a, and b is the pointer to mystruct
type itself.
Next, we declare three mystruct pointers and assign references to x,y and z to them.
p1=&x;
p2=&y;
p3=&z;
The variables x, y and z are unrelated, as they will be located at random locations, unlike the
array where all its elements are in adjacent locations. To explicitly establish link between them,
we can store address of y in x, and address of z in y.
Example
#include <stdio.h>
struct mystruct{
int a;
struct mystruct *b;
};
int main(){
struct mystruct x = {10, NULL}, y = {20, NULL}, z = {30, NULL};
struct mystruct * p1, *p2, *p3;
p1=&x;
p2=&y;
p3=&z;
x.b = p2;
y.b = p3;
printf("Add of x: %d a: %d add of next: %d\n", p1, x.a, x.b);
printf("add of y: %d a: %d add of next: %d\n", p2, y.a, y.b);
printf("add of z: %d a: %d add of next: %d\n", p3, z.a, z.b);
return 0;
}
Output
Let us refine the above program further. Instead of declaring variables and then storing their
address in pointers, we shall use malloc() function to dynamically allocate memory whose
address is stored in pointer variables. We then establish links between the three nodes as shown
below −
Example
#include <stdio.h>
#include <stdlib.h>
struct mystruct{
int a;
struct mystruct *b;
};
int main(){
struct mystruct *p1, *p2, *p3;
p1=(struct mystruct *)malloc(sizeof(struct mystruct));
p2=(struct mystruct *)malloc(sizeof(struct mystruct));
p3=(struct mystruct *)malloc(sizeof(struct mystruct));
p1->a=10; p1->b=NULL;
p2->a=20; p2->b=NULL;
p3->a=30; p3->b=NULL;
p1->b = p2;
p2->b = p3;
printf("Add of x: %d a: %d add of next: %d\n", p1, p1->a, p1->b);
printf("add of y: %d a: %d add of next: %d\n", p2, p2->a, p2->b);
printf("add of z: %d a: %d add of next: %d\n", p3, p3->a, p3->b);
return 0;
}
Output
We can reach the next element in the link from its address stored in the earlier element, as p1−>b
points to the address of p2. This while loop displays the linked list −
Example
#include <stdio.h>
#include <stdlib.h>
struct mystruct{
int a;
struct mystruct *b;
};
int main(){
struct mystruct *p1, *p2, *p3;
p1=(struct mystruct *)malloc(sizeof(struct mystruct));
p2=(struct mystruct *)malloc(sizeof(struct mystruct));
p3=(struct mystruct *)malloc(sizeof(struct mystruct));
p1->a=10; p1->b=NULL;
p2->a=20; p2->b=NULL;
p3->a=30; p3->b=NULL;
p1->b = p2;
p2->b = p3;
while (p1!=NULL){
printf("Add of current: %d a: %d add of next: %d\n", p1, p1->a, p1->b);
p1=p1->b;
}
return 0;
}
Output
Linked List
In the above examples, the dynamically constructed list has three discrete elements linked with
pointers. We can use a for loop to set up required number of elements by allocating memory
dynamically, and store the address of next element in the previous node. The following example
is a more generalized solution of creating a linked list with self−referential structure.
Example
#include <stdio.h>
#include <stdlib.h>
struct mystruct{
int a;
struct mystruct *b;
};
int main(){
struct mystruct *p1, *p2, *start;
int i;
p1=(struct mystruct *)malloc(sizeof(struct mystruct));
p1->a=10; p1->b=NULL;
start=p1;
for (i=1; i<=5; i++){
p2=(struct mystruct *)malloc(sizeof(struct mystruct));
p2->a=i*2;
p2->b=NULL;
p1->b=p2;
p1=p2;
}
p1=start;
while (p1!=NULL){
printf("Add of current: %d a: %d add of next: %d\n", p1, p1->a, p1->b);
p1=p1->b;
}
return 0;
}
Output
This is linked list is traversed from beginning till it reaches NULL. You can also construct a
doubly linked list, where the structure has two pointers, each referring to the address of previous
and next element.
struct node {
int data;
int key;
struct node *next;
struct node *prev;
};
Tree
Self−referential structures are also used to construct non−linear data structures as trees. A binary
search tree is logically represented by the following figure −
struct node {
int data;
struct node *leftChild;
struct node *rightChild;
};
To learn these complex data structure in detail, you can visit the DSA tutorial
− [Link]
C - Nested Structures
In the programming context, the term “nesting” refers to enclosing a particular programming
element inside the similar element. For example, nested loops and nested conditional statements,
etc. In this chapter, we shall learn about nested structures. When one of the elements in the
definition of a struct type is of another struct type, the we call it as nested structure in C.
Nested structures are defined when one of the elements of a struct type is itself a composite
representation of one or more types.
struct struct1{
type var1;
type var2;
struct struct2 strvar;
}
We can think of nested structures in the following situation.
If we want to define a struct type representing a student with name and age as its elements, and
other element is the course that is characterized by the course ID, the title, and the credit points.
Here, the student structure has an inner course structure.
struct student{
char *name;
int age;
struct course c1;
};
Method 1
In this method, we shall define an employee data type, with one of its elements being date of
birth. C doesn’t have a built−in date type. We shall declare the dob struct with three int types d,
m and y inside the employee structure and its variable d1 is one of the elements of the outer type.
Example
#include <stdio.h>
#include <string.h>
struct employee{
char name[10];
float salary;
struct dob{
int d, m, y;
} d1;
};
int main(){
struct employee e1 = {"Kiran", 25000, {12, 5, 1990}};
printf("Name: %s\n", [Link]);
printf("Salary: %f\n", [Link]);
printf("Date of Birth: %d-%d-%d\n", e1.d1.d, e1.d1.m, e1.d1.y);
return 0;
}
Output
Name: Kiran
Salary: 25000.000000
Date of Birth: 12-5-1990
You can see that the variable of employee type is initialized with its date element having another
pair of curly brackets.
Method 2
The other approach for using nested structures is to define the inner struct type first, and then use
its variable as one of the elements in the outer struct type, which is defined afterwards.
Here, the dob type is defined in the beginning, it has three int elements − d, m and y. The
employee struct type is defined afterwards. Since dob is already defined, we can have an element
of its type inside employee.
Example
#include <stdio.h>
#include <string.h>
struct dob{
int d, m, y;
};
struct employee{
char name[10];
float salary;
struct dob d1;
};
int main(){
struct employee e1 = {"Kiran", 25000, {12, 5, 1990}};
printf("Name: %s\n", [Link]);
printf("Salary: %f\n", [Link]);
printf("Date of Birth: %d-%d-%d\n", e1.d1.d, e1.d1.m, e1.d1.y);
return 0;
}
Output
Name: Kiran
Salary: 25000.000000
Date of Birth: 12-5-1990
Note that the inner struct type should be defined before the outer type. We can also declare a
variable of dob type and then include it in the initialization of employee type variable, as shown
below −
Example
In the following code, the nesting of structure goes upto two levels. In other words, the outer
struct type employee has one element that is a variable of experience struct type. In turn, the
experience structure has two elements of another struct type called date.
Hence, the memory allocation for employee variable can be understood with the following
illustration −
Example
#include <stdio.h>
#include <string.h>
struct date{
int d, m, y;
};
struct experience{
char designation[10];
struct date from;
struct date to;
};
struct employee{
char name[10];
float salary;
struct experience exp;
};
int main(){
struct date d1 = {12, 5, 1990};
struct date d2 = {31, 3, 2021};
struct experience exp = {"Clerk", d1, d2};
struct employee e1 = {"Kiran", 25000, exp};
printf("Name: %s\n", [Link]);
printf("Salary: %f\n", [Link]);
printf("Experience: Designation: %s\n", [Link]);
printf("From : %d-%d-%d\n", [Link].d,[Link].m, [Link].y );
printf("To : %d-%d-%d\n", [Link].d, [Link].m, [Link].y );
return 0;
}
Output
Name: Kiran
Salary: 25000.000000
Experience: Designation: Clerk
From : 12-5-1990
To : 31-3-2021
We know that the address of a struct variable can be stored in a pointer variable. Further, C uses
the indirection operator -> to access the elements of a variable that is referenced by the pointer.
In case of the nested structure, the elements of the inner struct elements are accessed by ptr-
>inner_struct_var.element;
In the example below, we have declared a pointer ptr to an employee struct variable. the date,
month and year elements of inner dob struct variable are accessed as ptr->d1.d, ptr->d1.m and
ptr->d1.y expressions.
Example
#include <stdio.h>
#include <string.h>
struct employee{
char name[10];
float salary;
struct dob{
int d, m, y;
} d1;
};
int main(){
struct employee e1 = {"Kiran", 25000, {12, 5, 1990}};
struct employee *ptr = &e1;
printf("Name: %s\n", ptr->name);
printf("Salary: %f\n", ptr->salary);
printf("Date of Birth: %d-%d-%d\n", ptr->d1.d, ptr->d1.m, ptr->d1.y);
return 0;
}
Output
Name: Kiran
Salary: 25000.000000
Date of Birth: 12-5-1990
Unions in C
A union is a special data type available in C that allows to store different data types in the same
memory location. You can define a union with many members, but only one member can contain
a value at any given time. Unions provide an efficient way of using the same memory location
for multiple purpose.
All the members of a union share the same memory location. Therefore, if we need to use the
same memory location for two or more members, then union is the best data type for that. The
largest union member defines the size of the union.
Defining a Union
Union variables are created in same manner as structure variables. The keyword union is used to
define unions in C language.
The "union tag" is optional and each member definition is a normal variable definition, such as
"int i;" or "float f;" or any other valid variable definition.
At the end of the union's definition, before the final semicolon, you can specify one or more
union variables.
Both structures and unions are composite data types in C programming. The most significant
difference between a structure and a union is the way they store their data. A structure stores
each member in separate memory locations, whereas a union stores all its members in the same
memory location.
union myunion{
int a;
double b;
char c;
};
The definition of a union is similar to the definition of a structure. A definition of "struct type
mystruct" with the same elements looks like this −
struct mystruct{
int a;
double b;
char c;
};
The main difference between a struct and a union is the size of the variables. The compiler
allocates the memory to a struct variable, to be able to store the values for all the elements.
In mystruct, there are three elements − an int, a double, and char, requiring 13 bytes (4 + 8 + 1).
Hence, sizeof(struct mystruct) returns 13.
On the other hand, for a union type variable, the compiler allocates a chunk of memory of the
size enough to accommodate the element of the largest byte size. The myunion type has an int, a
double and a char element. Out of the three elements, the size of the double variable is the
largest, i.e., 8. Hence, sizeof(union myunion) returns 8.
Another point to take into consideration is that a union variable can hold the value of only one its
elements. When you assign value to one element, the other elements are undefined. If you try to
use the other elements, it will result in some garbage.
In the code below, we define a union type called Data having three members i, f, and str. A
variable of type Data can store an integer, a floating point number, or a string of characters. It
means a single variable, i.e., the same memory location, can be used to store multiple types of
data. You can use any built-in or user-defined data types inside a union, as per your requirement.
The memory occupied by a union will be large enough to hold the largest member of the union.
For example, in the above example, Data will occupy 20 bytes of memory space because this is
the maximum space which can be occupied by a character string.
The following example displays the total memory size occupied by the above union −
#include <stdio.h>
#include <string.h>
union Data{
int i;
float f;
char str[20];
};
int main(){
union Data data;
printf("Memory occupied by Union Data: %d \n", sizeof(data));
return 0;
}
Output
When you compile and execute the code, it will produce the following output −
Now, let's create a structure with the same elements and check how much space it occupies in the
memory.
#include <stdio.h>
#include <string.h>
struct Data{
int i;
float f;
char str[20];
};
int main(){
struct Data data;
printf("Memory occupied by Struct Data: %d \n", sizeof(data));
return 0;
}
Output
This stucture will occupy 28 bytes (4 + 4 + 20). Run the code and check its output −
To access any member of a union, we use the member access operator (.). The member access
operator is coded as a period between the union variable name and the union member that we
wish to access. You would use the keyword union to define variables of union type. The
following example shows how to use unions in a program −
Example 1
#include <stdio.h>
#include <string.h>
union Data{
int i;
float f;
char str[20];
};
int main(){
union Data data;
data.i = 10;
data.f = 220.5;
strcpy([Link], "C Programming");
Output
When the above code is compiled and executed, it produces the following result −
data.i: 1917853763
data.f: 4122360580327794860452759994368.000000
[Link]: C Programming
Here, we can see that the values of i and f (members of the union) show garbage values because
the final value assigned to the variable has occupied the memory location and this is the reason
that the value of str member is getting printed very well.
Example 2
Now let's look at the same example once again where we will use one variable at a time which is
the main purpose of having unions −
#include <stdio.h>
#include <string.h>
union Data{
int i;
float f;
char str[20];
};
int main(){
data.i = 10;
printf("data.i: %d \n", data.i);
data.f = 220.5;
printf("data.f: %f \n", data.f);
Output
When the above code is compiled and executed, it produces the following result −
data.i: 10
data.f: 220.500000
[Link]: C Programming
Here, the values of all the Union members are getting printed very well because one member is
being used at a time.
C - Bit Fields
struct {
unsigned int widthValidated;
unsigned int heightValidated;
} status;
This structure requires 8 bytes of memory space but in actual, we are going to store either 0 or 1
in each of the variables. The C programming language offers a better way to utilize the memory
space in such situations.
If you are using such variables inside a structure then you can define the width of a variable
which tells the C compiler that you are going to use only those number of bytes. For example,
the above structure can be re-written as follows −
struct {
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
The above structure requires 4 bytes of memory space for status variable, but only 2 bits will be
used to store the values.
If you will use up to 32 variables each one with a width of 1 bit, then also the status structure will
use 4 bytes. However as soon as you have 33 variables, it will allocate the next slot of the
memory and it will start using 8 bytes. Let us check the following example to understand the
concept −
Live Demo
#include <stdio.h>
#include <string.h>
int main( ) {
printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
return 0;
}
When the above code is compiled and executed, it produces the following result −
struct {
type [member_name] : width ;
};
type
1 An integer type that determines how a bit-field's value is
interpreted. The type may be int, signed int, or unsigned int.
member_name
2
The name of the bit-field.
width
3 The number of bits in the bit-field. The width must be less than
or equal to the bit width of the specified type.
The variables defined with a predefined width are called bit fields. A bit field can hold more
than a single bit; for example, if you need a variable to store a value from 0 to 7, then you can
define a bit field with a width of 3 bits as follows −
struct {
unsigned int age : 3;
} Age;
The above structure definition instructs the C compiler that the age variable is going to use only
3 bits to store the value. If you try to use more than 3 bits, then it will not allow you to do so. Let
us try the following example −
Live Demo
#include <stdio.h>
#include <string.h>
struct {
unsigned int age : 3;
} Age;
int main( ) {
[Link] = 4;
printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
printf( "[Link] : %d\n", [Link] );
[Link] = 7;
printf( "[Link] : %d\n", [Link] );
[Link] = 8;
printf( "[Link] : %d\n", [Link] );
return 0;
}
When the above code is compiled it will compile with a warning and when executed, it produces
the following result −
Sizeof( Age ) : 4
[Link] : 4
[Link] : 7
[Link] : 0
C - typedef
The C programming language provides a keyword called typedef, which you can use to give a
type a new name. Following is an example to define a term BYTE for one-byte numbers −
After this type definition, the identifier BYTE can be used as an abbreviation for the
type unsigned char, for example..
BYTE b1, b2;
By convention, uppercase letters are used for these definitions to remind the user that the type
name is really a symbolic abbreviation, but you can use lowercase, as follows −
You can use typedef to give a name to your user defined data types as well. For example, you
can use typedef with structure to define a new data type and then use that data type to define
structure variables directly as follows −
Live Demo
#include <stdio.h>
#include <string.h>
int main( ) {
Book book;
return 0;
}
When the above code is compiled and executed, it produces the following result −
typedef vs #define
#define is a C-directive which is also used to define the aliases for various data types similar
to typedef but with the following differences −
typedef is limited to giving symbolic names to types only where as #define can be used to
define alias for values as well, q., you can define 1 as ONE etc.
typedef interpretation is performed by the compiler whereas #define statements are
processed by the pre-processor.
Live Demo
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int main( ) {
printf( "Value of TRUE : %d\n", TRUE);
printf( "Value of FALSE : %d\n", FALSE);
return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of TRUE : 1
Value of FALSE : 0
C - Input and Output
When we say Input, it means to feed some data into a program. An input can be given in the
form of a file or from the command line. C programming provides a set of built-in functions to
read the given input and feed it to the program as per requirement.
When we say Output, it means to display some data on screen, printer, or in any file. C
programming provides a set of built-in functions to output the data on the computer screen as
well as to save it in text or binary files.
The file pointers are the means to access the file for reading and writing purpose. This section
explains how to read values from the screen and how to print the result on the screen.
The int getchar(void) function reads the next available character from the screen and returns it
as an integer. This function reads only single character at a time. You can use this method in the
loop in case you want to read more than one character from the screen.
The int putchar(int c) function puts the passed character on the screen and returns the same
character. This function puts only single character at a time. You can use this method in the loop
in case you want to display more than one character on the screen. Check the following example
−
#include <stdio.h>
int main( ) {
int c;
return 0;
}
When the above code is compiled and executed, it waits for you to input some text. When you
enter a text and press enter, then the program proceeds and reads only a single character and
displays it as follows −
$./[Link]
Enter a value : this is test
You entered: t
The char *gets(char *s) function reads a line from stdin into the buffer pointed to by s until
either a terminating newline or EOF (End of File).
The int puts(const char *s) function writes the string 's' and 'a' trailing newline to stdout.
NOTE: Though it has been deprecated to use gets() function, Instead of using gets, you want to
use fgets().
#include <stdio.h>
int main( ) {
char str[100];
return 0;
}
When the above code is compiled and executed, it waits for you to input some text. When you
enter a text and press enter, then the program proceeds and reads the complete line till end, and
displays it as follows −
$./[Link]
Enter a value : this is test
You entered: this is test
The int scanf(const char *format, ...) function reads the input from the standard input
stream stdin and scans that input according to the format provided.
The int printf(const char *format, ...) function writes the output to the standard output
stream stdout and produces the output according to the format provided.
The format can be a simple constant string, but you can specify %s, %d, %c, %f, etc., to print or
read strings, integer, character or float respectively. There are many other formatting options
available which can be used based on requirements. Let us now proceed with a simple example
to understand the concepts better −
#include <stdio.h>
int main( ) {
char str[100];
int i;
return 0;
}
When the above code is compiled and executed, it waits for you to input some text. When you
enter a text and press enter, then program proceeds and reads the input and displays it as follows
−
$./[Link]
Enter a value : seven 7
You entered: seven 7
Here, it should be noted that scanf() expects input in the same format as you provided %s and
%d, which means you have to provide valid inputs like "string integer". If you provide "string
string" or "integer integer", then it will be assumed as wrong input. Secondly, while reading a
string, scanf() stops reading as soon as it encounters a space, so "this is test" are three strings for
scanf().
C - File I/O
The last chapter explained the standard input and output devices handled by C programming
language. This chapter cover how C programmers can create, open, close text or binary files for
their data storage.
A file represents a sequence of bytes, regardless of it being a text file or a binary file. C
programming language provides access on high level functions as well as low level (OS level)
calls to handle file on your storage devices. This chapter will take you through the important
calls for file management.
Opening Files
You can use the fopen( ) function to create a new file or to open an existing file. This call will
initialize an object of the type FILE, which contains all the information necessary to control the
stream. The prototype of this function call is as follows −
Here, filename is a string literal, which you will use to name your file, and access mode can
have one of the following values −
r
1
Opens an existing text file for reading purpose.
w
Opens a text file for writing. If it does not exist, then a new file
2
is created. Here your program will start writing content from the
beginning of the file.
a
Opens a text file for writing in appending mode. If it does not
3
exist, then a new file is created. Here your program will start
appending content in the existing file content.
r+
4
Opens a text file for both reading and writing.
w+
Opens a text file for both reading and writing. It first truncates
5
the file to zero length if it exists, otherwise creates a file if it
does not exist.
a+
Opens a text file for both reading and writing. It creates the file
6
if it does not exist. The reading will start from the beginning but
writing can only be appended.
If you are going to handle binary files, then you will use following access modes instead of the
above mentioned ones −
Closing a File
To close a file, use the fclose( ) function. The prototype of this function is −
int fclose( FILE *fp );
The fclose(-) function returns zero on success, or EOF if there is an error in closing the file. This
function actually flushes any data still pending in the buffer to the file, closes the file, and
releases any memory used for the file. The EOF is a constant defined in the header file stdio.h.
There are various functions provided by C standard library to read and write a file, character by
character, or in the form of a fixed length string.
Writing a File
The function fputc() writes the character value of the argument c to the output stream referenced
by fp. It returns the written character written on success otherwise EOF if there is an error. You
can use the following functions to write a null-terminated string to a stream −
The function fputs() writes the string s to the output stream referenced by fp. It returns a non-
negative value on success, otherwise EOF is returned in case of any error. You can use int
fprintf(FILE *fp,const char *format, ...) function as well to write a string into a file. Try the
following example.
Make sure you have /tmp directory available. If it is not, then before proceeding, you must
create this directory on your machine.
#include <stdio.h>
main() {
FILE *fp;
fp = fopen("/tmp/[Link]", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
fclose(fp);
}
When the above code is compiled and executed, it creates a new file [Link] in /tmp directory
and writes two lines using two different functions. Let us read this file in the next section.
Reading a File
Given below is the simplest function to read a single character from a file −
The fgetc() function reads a character from the input file referenced by fp. The return value is the
character read, or in case of any error, it returns EOF. The following function allows to read a
string from a stream −
The functions fgets() reads up to n-1 characters from the input stream referenced by fp. It copies
the read string into the buffer buf, appending a null character to terminate the string.
If this function encounters a newline character '\n' or the end of the file EOF before they have
read the maximum number of characters, then it returns only the characters read up to that point
including the new line character. You can also use int fscanf(FILE *fp, const char *format,
...) function to read strings from a file, but it stops reading after encountering the first space
character.
#include <stdio.h>
main() {
FILE *fp;
char buff[255];
fp = fopen("/tmp/[Link]", "r");
fscanf(fp, "%s", buff);
printf("1 : %s\n", buff );
When the above code is compiled and executed, it reads the file created in the previous section
and produces the following result −
1 : This
2: is testing for fprintf...
3: This is testing for fputs...
Let's see a little more in detail about what happened here. First, fscanf() read just This because
after that, it encountered a space, second call is for fgets() which reads the remaining line till it
encountered end of line. Finally, the last call fgets() reads the second line completely.
There are two functions, that can be used for binary input and output −
Both of these functions should be used to read or write blocks of memories - usually arrays or
structures.
C - Preprocessors
The C Preprocessor is not a part of the compiler, but is a separate step in the compilation
process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the
compiler to do required pre-processing before the actual compilation. We'll refer to the C
Preprocessor as CPP.
All preprocessor commands begin with a hash symbol (#). It must be the first nonblank
character, and for readability, a preprocessor directive should begin in the first column. The
following section lists down all the important preprocessor directives −
#define
1
Substitutes a preprocessor macro.
#include
2
Inserts a particular header from another file.
#undef
3
Undefines a preprocessor macro.
#ifdef
4
Returns true if this macro is defined.
5 #ifndef
Returns true if this macro is not defined.
#if
6
Tests if a compile time condition is true.
#else
7
The alternative for #if.
#elif
8
#else and #if in one statement.
#endif
9
Ends preprocessor conditional.
#error
10
Prints error message on stderr.
#pragma
11 Issues special commands to the compiler, using a standardized
method.
Preprocessors Examples
#define MAX_ARRAY_LENGTH 20
This directive tells the CPP to replace instances of MAX_ARRAY_LENGTH with 20.
Use #define for constants to increase readability.
#include <stdio.h>
#include "myheader.h"
These directives tell the CPP to get stdio.h from System Libraries and add the text to the current
source file. The next line tells CPP to get myheader.h from the local directory and add the
content to the current source file.
#undef FILE_SIZE
#define FILE_SIZE 42
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
It tells the CPP to define MESSAGE only if MESSAGE isn't already defined.
#ifdef DEBUG
/* Your debugging statements here */
#endif
It tells the CPP to process the statements enclosed if DEBUG is defined. This is useful if you
pass the -DDEBUG flag to the gcc compiler at the time of compilation. This will define DEBUG,
so you can turn debugging on and off on the fly during compilation.
Predefined Macros
ANSI C defines a number of macros. Although each one is available for use in programming, the
predefined macros should not be directly modified.
__DATE__
1 The current date as a character literal in "MMM DD YYYY"
format.
__TIME__
2
The current time as a character literal in "HH:MM:SS" format.
__FILE__
3
This contains the current filename as a string literal.
__LINE__
4
This contains the current line number as a decimal constant.
__STDC__
Defined as 1 when the compiler complies with the ANSI
standard.
int main() {
When the above code in a file test.c is compiled and executed, it produces the following result −
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
Preprocessor Operators
A macro is normally confined to a single line. The macro continuation operator (\) is used to
continue a macro that is too long for a single line. For example −
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
The stringize or number-sign operator ( '#' ), when used within a macro definition, converts a
macro parameter into a string constant. This operator may be used only in a macro having a
specified argument or parameter list. For example
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
When the above code is compiled and executed, it produces the following result −
The token-pasting operator (##) within a macro definition combines two arguments. It permits
two separate tokens in the macro definition to be joined into a single token. For example −
Live Demo
#include <stdio.h>
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
When the above code is compiled and executed, it produces the following result −
token34 = 40
It happened so because this example results in the following actual output from the preprocessor
−
This example shows the concatenation of token##n into token34 and here we have used
both stringize and token-pasting.
Live Demo
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
When the above code is compiled and executed, it produces the following result −
Parameterized Macros
One of the powerful functions of the CPP is the ability to simulate functions using parameterized
macros. For example, we might have some code to square a number as follows −
int square(int x) {
return x * x;
}
Macros with arguments must be defined using the #define directive before they can be used. The
argument list is enclosed in parentheses and must immediately follow the macro name. Spaces
are not allowed between the macro name and open parenthesis. For example −
Live Demo
#include <stdio.h>
int main(void) {
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
When the above code is compiled and executed, it produces the following result −
You request to use a header file in your program by including it with the C preprocessing
directive #include, like you have seen inclusion of stdio.h header file, which comes along with
your compiler.
Including a header file is equal to copying the content of the header file but we do not do it
because it will be error-prone and it is not a good idea to copy the content of a header file in the
source files, especially if we have multiple source files in a program.
A simple practice in C or C++ programs is that we keep all the constants, macros, system wide
global variables, and function prototypes in the header files and include that header file wherever
it is required.
Include Syntax
Both the user and the system header files are included using the preprocessing
directive #include. It has the following two forms −
#include <file>
This form is used for system header files. It searches for a file named 'file' in a standard list of
system directories. You can prepend directories to this list with the -I option while compiling
your source code.
#include "file"
This form is used for header files of your own program. It searches for a file named 'file' in the
directory containing the current file. You can prepend directories to this list with the -I option
while compiling your source code.
Include Operation
The #include directive works by directing the C preprocessor to scan the specified file as input
before continuing with the rest of the current source file. The output from the preprocessor
contains the output already generated, followed by the output resulting from the included file,
followed by the output that comes from the text after the #include directive. For example, if you
have a header file header.h as follows −
and a main program called program.c that uses the header file, like this −
int x;
#include "header.h"
the compiler will see the same token stream as it would if program.c read.
int x;
char *test (void);
Once-Only Headers
If a header file happens to be included twice, the compiler will process its contents twice and it
will result in an error. The standard way to prevent this is to enclose the entire real contents of
the file in a conditional, like this −
#ifndef HEADER_FILE
#define HEADER_FILE
#endif
This construct is commonly known as a wrapper #ifndef. When the header is included again, the
conditional will be false, because HEADER_FILE is defined. The preprocessor will skip over
the entire contents of the file, and the compiler will not see it twice.
Computed Includes
Sometimes it is necessary to select one of the several different header files to be included into
your program. For instance, they might specify configuration parameters to be used on different
sorts of operating systems. You could do this with a series of conditionals as follows −
#if SYSTEM_1
# include "system_1.h"
#elif SYSTEM_2
# include "system_2.h"
#elif SYSTEM_3
...
#endif
But as it grows, it becomes tedious, instead the preprocessor offers the ability to use a macro for
the header name. This is called a computed include. Instead of writing a header name as the
direct argument of #include, you simply put a macro name there −
SYSTEM_H will be expanded, and the preprocessor will look for system_1.h as if
the #include had been written that way originally. SYSTEM_H could be defined by your
Makefile with a -D option.
C - Type Casting
Converting one datatype into another is known as type casting or, type-conversion. For example,
if you want to store a 'long' value into a simple integer then you can type cast 'long' to 'int'. You
can convert the values from one type to another explicitly using the cast operator as follows −
(type_name) expression
Consider the following example where the cast operator causes the division of one integer
variable by another to be performed as a floating-point operation −
Live Demo
#include <stdio.h>
main() {
When the above code is compiled and executed, it produces the following result −
Value of mean : 3.400000
It should be noted here that the cast operator has precedence over division, so the value of sum is
first converted to type double and finally it gets divided by count yielding a double value.
Type conversions can be implicit which is performed by the compiler automatically, or it can be
specified explicitly through the use of the cast operator. It is considered good programming
practice to use the cast operator whenever type conversions are necessary.
Integer Promotion
Integer promotion is the process by which values of integer type "smaller" than int or unsigned
int are converted either to int or unsigned int. Consider an example of adding a character with
an integer −
Live Demo
#include <stdio.h>
main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
int sum;
sum = i + c;
printf("Value of sum : %d\n", sum );
}
When the above code is compiled and executed, it produces the following result −
Here, the value of sum is 116 because the compiler is doing integer promotion and converting
the value of 'c' to ASCII before performing the actual addition operation.
The usual arithmetic conversions are implicitly performed to cast their values to a common
type. The compiler first performs integer promotion; if the operands still have different types,
then they are converted to the type that appears highest in the following hierarchy −
The usual arithmetic conversions are not performed for the assignment operators, nor for the
logical operators && and ||. Let us take the following example to understand the concept −
Live Demo
#include <stdio.h>
main() {
int i = 17;
char c = 'c'; /* ascii value is 99 */
float sum;
sum = i + c;
printf("Value of sum : %f\n", sum );
}
When the above code is compiled and executed, it produces the following result −
Value of sum : 116.000000
Here, it is simple to understand that first c gets converted to integer, but as the final value is
double, usual arithmetic conversion applies and the compiler converts i and c into 'float' and adds
them yielding a 'float' result.
C - Error Handling
As such, C programming does not provide direct support for error handling but being a system
programming language, it provides you access at lower level in the form of return values. Most
of the C or even Unix function calls return -1 or NULL in case of any error and set an error
code errno. It is set as a global variable and indicates an error occurred during any function call.
You can find various error codes defined in <error.h> header file.
So a C programmer can check the returned values and can take appropriate action depending on
the return value. It is a good practice, to set errno to 0 at the time of initializing a program. A
value of 0 indicates that there is no error in the program.
The C programming language provides perror() and strerror() functions which can be used to
display the text message associated with errno.
The perror() function displays the string you pass to it, followed by a colon, a space, and
then the textual representation of the current errno value.
The strerror() function, which returns a pointer to the textual representation of the current
errno value.
Let's try to simulate an error condition and try to open a file which does not exist. Here I'm using
both the functions to show the usage, but you can use one or more ways of printing your errors.
Second important point to note is that you should use stderr file stream to output all the errors.
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main () {
FILE * pf;
int errnum;
pf = fopen ("[Link]", "rb");
if (pf == NULL) {
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
} else {
fclose (pf);
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of errno: 2
Error printed by perror: No such file or directory
Error opening file: No such file or directory
It is a common problem that at the time of dividing any number, programmers do not check if a
divisor is zero and finally it creates a runtime error.
The code below fixes this by checking if the divisor is zero before dividing −
Live Demo
#include <stdio.h>
#include <stdlib.h>
main() {
exit(0);
}
When the above code is compiled and executed, it produces the following result −
It is a common practice to exit with a value of EXIT_SUCCESS in case of program coming out
after a successful operation. Here, EXIT_SUCCESS is a macro and it is defined as 0.
If you have an error condition in your program and you are coming out then you should exit with
a status EXIT_FAILURE which is defined as -1. So let's write above program as follows −
Live Demo
#include <stdio.h>
#include <stdlib.h>
main() {
if( divisor == 0) {
fprintf(stderr, "Division by zero! Exiting...\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
When the above code is compiled and executed, it produces the following result −
Value of quotient : 4
C - Variable Arguments
Sometimes, you may come across a situation, when you want to have a function, which can take
variable number of arguments, i.e., parameters, instead of predefined number of parameters. The
C programming language provides a solution for this situation and you are allowed to define a
function which can accept variable number of parameters based on your requirement. The
following example shows the definition of such a function.
int main() {
func(1, 2, 3);
func(1, 2, 3, 4);
}
It should be noted that the function func() has its last argument as ellipses, i.e. three dotes (...)
and the one just before the ellipses is always an int which will represent the total number
variable arguments passed. To use such functionality, you need to make use of stdarg.h header
file which provides the functions and macros to implement the functionality of variable
arguments and follow the given steps −
Define a function with its last parameter as ellipses and the one just before the ellipses is
always an int which will represent the number of arguments.
Create a va_list type variable in the function definition. This type is defined in stdarg.h
header file.
Use int parameter and va_start macro to initialize the va_list variable to an argument list.
The macro va_start is defined in stdarg.h header file.
Use va_arg macro and va_list variable to access each item in argument list.
Use a macro va_end to clean up the memory assigned to va_list variable.
Now let us follow the above steps and write down a simple function which can take the variable
number of parameters and return their average −
Live Demo
#include <stdio.h>
#include <stdarg.h>
va_list valist;
double sum = 0.0;
int i;
return sum/num;
}
int main() {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}
When the above code is compiled and executed, it produces the following result. It should be
noted that the function average() has been called twice and each time the first argument
represents the total number of variable arguments being passed. Only ellipses will be used to
pass variable number of arguments.
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
C - Memory Management
While programming, if you are aware of the size of an array, then it is easy and you can define it
as an array. For example, to store a name of any person, it can go up to a maximum of 100
characters, so you can define something as follows −
char name[100];
But now let us consider a situation where you have no idea about the length of the text you need
to store, for example, you want to store a detailed description about a topic. Here we need to
define a pointer to character without defining how much memory is required and later, based on
requirement, we can allocate memory as shown in the below example −
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char name[100];
char *description;
When the above code is compiled and executed, it produces the following result.
Same program can be written using calloc(); only thing is you need to replace malloc with calloc
as follows −
calloc(200, sizeof(char));
So you have complete control and you can pass any size value while allocating memory, unlike
arrays where once the size defined, you cannot change it.
When your program comes out, operating system automatically release all the memory allocated
by your program but as a good practice when you are not in need of memory anymore then you
should release that memory by calling the function free().
Alternatively, you can increase or decrease the size of an allocated memory block by calling the
function realloc(). Let us check the above program once again and make use of realloc() and
free() functions −
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char name[100];
char *description;
When the above code is compiled and executed, it produces the following result.
You can try the above example without re-allocating extra memory, and strcat() function will
give an error due to lack of available memory in description.
It is possible to pass some values from the command line to your C programs when they are
executed. These values are called command line arguments and many times they are important
for your program especially when you want to control your program from outside instead of hard
coding those values inside the code.
The command line arguments are handled using main() function arguments where argc refers to
the number of arguments passed, and argv[] is a pointer array which points to each argument
passed to the program. Following is a simple example which checks if there is any argument
supplied from the command line and take action accordingly −
#include <stdio.h>
When the above code is compiled and executed with single argument, it produces the following
result.
$./[Link] testing
The argument supplied is testing
When the above code is compiled and executed with a two arguments, it produces the following
result.
When the above code is compiled and executed without passing any argument, it produces the
following result.
$./[Link]
One argument expected
It should be noted that argv[0] holds the name of the program itself and argv[1] is a pointer to
the first command line argument supplied, and *argv[n] is the last argument. If no arguments are
supplied, argc will be one, and if you pass one argument then argc is set at 2.
You pass all the command line arguments separated by a space, but if argument itself has a space
then you can pass such arguments by putting them inside double quotes "" or single quotes ''. Let
us re-write above example once again where we will print program name and we also pass a
command line argument by putting inside double quotes −
#include <stdio.h>
When the above code is compiled and executed with a single argument separated by space but
inside double quotes, it produces the following result.