C Linux Handbook
C Linux Handbook
com
Student Handbook:
Programming in C &
Linux
INDEX
No. of
Sl # Topics / Subtopics Session Lab - Y/N Page #
1 Introduction to C 1 Y
Historical Development and features of C 3
Compilation Process (Source Code - Executable File) 4
Sample Program 5
Variables, Keywords, Constants 6
Data types 7
Working with VIM 9
2 Operators 2 Y
Unary operators (++ / -- ) 11
Binary operators / Arithmetic operators 12
Assignment operators 13
Relational operators ,Logical Operators 14
Short hand Assignment operators , Bitwise operators 16
Order of Evaluation of expressions 18
Formatted / Unformatted Functions 19
3 CONTROL FLOW 3 Y
Decision Constructs: if, if..else, ternary operator 22
Switch – case 26
Looping Constructs: while, do-while, for 28
break and continue 34
Nested Loops and infinite loops 37
4 Modular Programming 2 Y
Functions, Parts of Function 39
Passing arguments to function 41
5 Preprocessor 2 Y
C Compilation Model 43
File Inclusion 44
Macro With and without arguments 46
Macros versus constant and Functions 47
Predefined Macros 48
Conditional compilation 49
Working with multiple files 53
6 Storage classes 1 Y
Storage classes specifiers : auto, register, static, extern 55
Internal Linkage & External Linkage 57
7 Arrays 2 Y
Array and its memory layout 60
Initialization of array 61
Passing Array to Function 62
© Cranes Varsity V5:2022-23 2/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
C is a programming language developed at AT&T’s Bell Laboratories of USA in 1972. It was designed and
written by Dennis Ritchie. C is popular because it is reliable, simple and easy to use for the development
of Application and System Software.
Historical Development of C
By 1960 a horde of computer languages had come into existence, almost each for specific purpose. For
ex: COBOL was being used for Commercial Applications, FORTRAN for Engineering and Scientific
Application and so on.
An international committee was set up to develop a common language. This committee came up with a
language called ALGOL-60. But it never became popular because it seemed too abstract, too general.
To reduce this abstractness and generality, a language called Combined Programming Language (CPL)
was developed at Cambridge University. CPL turned out to be too big, having so many features, that it
was hard to learn and difficult to implement.
Basic Combined Programming Language (BCPL) was developed by Martin Richards at Cambridge
University. But turned out to be powerful and too scientific!
Ken Thompson at AT&T’s Bell Labs wrote a language called B, as a further simplification of CPL. But
unlike BCPL, B turned out to be too very specific. Ritchie inherited the features of B and BCPL, added
some of his own and developed C.
C has the flexibilities of high level language and features of low level language so the C language is called
as middle level language that can be used to develop utilities, data base applications, compilers and so
on.
Special features of C
C is a language that supports many desired features. We briefly discuss some of these:
Middle level language
Modularity
Portability
High level refers to ease of programming in a particular language. The nearer the language is to natural
language (like English), the faster a programmer can develop programs using it.
Low level is the ability of a language to address the instructions directly to the CPU.
C supports good low-level programming and is easy to program hence it is called a middle level language.
It is the ideal language for the development of system programs Operating Systems, Compilers,
Embedded Software etc. In fact, the C compiler itself is written in C. C has special operators like logical,
bitwise operators, Increment decrement operators etc., that closely imitate the instructions available on a
commercial CPU. This leads to the compiled code being very compact and efficient.
Structured programming is a programming paradigm aimed on improving the clarity, quality, and
development time of a computer program by making extensive use of subroutines, block structures and
loops - in contrast to using simple tests and jumps such as the goto statement which could lead to
"spaghetti code" which is both difficult to follow and to maintain.
Modularity
Portability
C is portable language. Code written for one machine can be easily moved to another. C provides the
programmer with a standard library of functions that work the same on all machines.
Environment for C
Program Creation
The program, which has to be executed, is first written into a file on the computer system, this file is
known as the source file and the contents of it is called as source code. This file should have .c as its
extension.
In unixenvironment,file can be created with vi editor as-
$vi filename.c
Here $ is the unix prompt. The file can be saved by pressing ESC , colon ( : ) and wq
Program Compilation
After creation of C program, it is compiled as-
$ gccfilename.c
After compilation, the executable code is stored in the default file called a.out.
Another way of compilation is providing the user specified executable name. Use –o compiler option for
the same.
$ gccfilename.c –o User_executablename
A Sample Program
/******************************************************************************
AUTHOR : Cranes Student
Description : Program to print “Welcome To Cranes” in C
Developed on : 15th June 2016
Modified on :
Tested on :
******************************************************************************/
#include <stdio.h>
int main( )
{
printf(“WELCOME TO CRANES \n”); //Print WELCOME TO CRANES on monitor
return 0;
}
#include <stdio.h>
This line tells the preprocessor to include header file stdio.h in the current working file.
Comments
Comments are used for increasing readbility of the program. There can be single line or multiple line
comments. If it is a single line comment it can be given as // in the beginning of statement. Multiple line
comments are written inside the delimiters /* and */.
Executable part: Consists of executable statements necessary to achieve the desired output.
printf( ) function
Is a library function used to display its arguments on the video screen.
NOTE
C requires a semicolon at the end of almost every statement, which acts as a statement
terminator.
\n signifies new line. It is also required flush the contents of the output buffer.
TOKENS
The smallest individual unit in a c program is known as a token or a lexical unit. C tokens can be classified
as follows:
Identifiers
Keywords
Constants
Strings
Special symbols
operators
C Identifier
The term identifier refers to the names of variables, functions, macros, structures and other objects
defined in a C program. In order to maintain the best programming practice for maintaining the code one
must specify the variable name appropriately. i.e., the name should highlight the purpose of using it in the
program.
Ex: int count; is more appropriate than int x;
Rules for identifiers
Case is significant.
© Cranes Varsity V5:2022-23 6/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
Variable
A variable corresponds to an area of memory which can store a value of the given type. The value
contained can be modified during the course of program execution.
Every variable in a C program must be declared before it is used. When you declare a variable you are
telling the compiler what kind of data you will be storing in the variable. The syntax for variable
declarations is as follows.
Syntax
Type_Name Variable_Name_1, Variable_Name_2,. . .;
Keywords
Keywords are the words whose meaning has already been defined in the C compiler. These keywords
have to be used in the program for the specific purposes based on the definition. The keywords are also
called as reserved words.
auto Double if sizeof
break Else int static
case Enum long struct
char Extern void switch
const Float register typedef
continue For return union
default While short unsigned
do Goto signed volatile
Constants
A constant is a quantity that doesn’t change. This quantity can be stored in the memory of the computer.
We can specify our constants in octal or hexadecimal, or force them to be treated as long
integers.
Octal constants are written with a leading zero – 015.
Hexadecimal constants are written with a leading 0x – 0x1ae.
Long constants are written with a trailing L – 890L.
Unsigned constants are written with a trailing u - 25u
Float Constants are written with a trailing f - 3.14f
Character constants are enclosed in single quotes; ‘a’, ‘B’.
Character constants are rarely used, since string constants are more convenient. A string
constant is surrounded by double quotes Ex. “Brian and Dennis”.
A backslash, \, preceding a character tells the compiler that the sequence following the backslash does
not have the same meaning as the character appearing by itself. Such a sequence is called an escape
sequence. The sequence is typed in as two characters with no space between the symbols. Several
escape sequences are defined in C.
Sequence Meaning
\n New line
\r Carriage returns (Position the cursor at the start of the current line.You are not
likely to use this very much.)
\t (Horizontal)Tab (Advances the cursor to the next tab stop.)
\a Alert (Sounds the alert noise, typically a bell.)
\\ Backslash (Allows you to place a backslash in quoted expression.)
\’ Single quote (Mostly used to place a single quote inside single quotes.)
\” Double quote (Mostly used to place a double quote inside a quoted string.)
C Data Types
pointers
structures
unions
enumerator
The user defined data types like arrays, structures, pointers can be combined in any ways.
char is the smallest data type as it occupies just one byte of memory. char is the short form for “character”,
typically used to represent an alphabet. To represent the characters standard bit patterns are used that
are called ASCII (American Standard Code for Information Interchange) codes.
ASCII is a 128-character set:
95 characters are printable (with graphic shape)
33 characters are nonprintable (control characters)
int data type’s size is usually chosen as natural size of the ALU. Width of ALU = Size of operand. Popular
ALU’s are 16 bits OR 32 bits. int is a non-portable data type. For example, a program running on a 32-bit
compiler may not work if compiled on a 16-bit compiler. To develop portable programs, two suffixes are
used viz., short and long.
Ex: short int num; or short num;
long int sum; or long sum;
short is always 16 bits (or 2 bytes)
long is always a 32 bit (or 4 bytes)
unsigned prefix is used on char, int, short and long data types to represent physical quantities that can
never be negative, in order to get double the respective ranges.
Unsigned N bit value has range: 0 to 2 N -1.
Ex: unsigned char age;
unsigned int age;
To represent quantities larger than a “long”, floating point representation are used. There are two IEEE
standard formats used
Note: -ve numbers will be stored using 2’s compliment
Floats and doubles are stored in mantissa and exponent form except that instead of the exponent
representing the power of 10, it represents a power of 2, since base 2 is computer’s natural format.
The accuracy of representation or “precision” is different for float and double. 23 bits of mantissa of a float
can represent only 7 significant decimal digits. “double” can represent approx. 14 decimal figures.
The error in representation is known as round off error. Doing computation on erroneous numbers
increases error in the result. Placing the binary point ahead of all the bits is known as normalized
representation and is most efficient.
NOTE
There is NO Boolean type in C – you should use char, int or (better) unsigned. Refer to limits.h and float.h
for the range and size of various primitive data types.
Vim is an open-source text editor designed for working with programming code in Unix. Vim was
developed by Bram Moolenaar in 1991.
Vim is an advanced text editor that seeks to provide the power of the de-facto Unix editor 'Vi', with a more
complete feature set. Vim is a highly configurable text editor built to enable efficient text editing. It is an
improved version of the vi editor distributed with most UNIX systems.
Vim is often called a "programmer's editor," and so useful for programming that many consider it an
entire IDE. It's not just for programmers, though. Vim is perfect for all kinds of text editing, from composing
email to editing configuration files.
Vim employs a command line interface rather than a graphical user interface (GUI).
Modes in Vim
There are two modes in vim. One is the command mode and another is the insert mode.
1. In the command mode, user can move around the file, delete text, etc.
Exit Commands
:wq Write file to disk and quit the editor
:q! Quit (no warning)
:q Quit (a warning is printed if a modified file has not been saved)
CHAPTER – 2
OPERATORS
An operator is a symbol that tells the compiler to perform certain mathematical or logical manipulations.
Operators are used in program to manipulate data and variables. In other words, Operators are used by
instructions of CPU to manipulate data values.
Every language has a set of operators that get translated to appropriate operation of the target CPU. C
language supports a rich set of built-in operators.
Operators Classification
Operators can be classified based on the operations that they perform or based on the number of
operands it operates on.
Unary Operators :
Increment and Decrement Operators
C provides another set of shortcuts: the increment and decrement operators. In their simplest forms,
they look like this:
++i; add 1 toi
--j; subtract 1 from j
The ++ and – operators apply to one operand (they’re unary operators). The expression ++i adds 1 to i,
and stores the incremented result back in i. This means that these operators don’t just compute new
values; they also modify the value of some variable.
Both the ++ and – operators have an unusual property: they can be used in two ways; depending on
whether they are written to the left or the right of the variable they’re operating on. The prefix form ++i
increments i and returns the incremented value. The postfix form i++ increments i, but returns the prior,
non-incremented value. Rewriting our previous example slightly, the expression
k = 2 * i++;
means: take i’s old value and multiply it by 2, increment i, store the result of the multiplication in k.
Other Unary operators are unary - , unary + , ! , ~ ,& (address) , sizeof ,cast operator
Program to demonstrate logical AND and OR operators are short circuit operators
Binary operators
A binary operator is an operator that operates on two operands and manipulates them to return a
result. Operators are represented by special characters or by keywords and provide an easy way to
compare numerical values or character strings. Binary operators are presented in the form:
1. Arithmetic Operators
2. Logical Operators
3. Bitwise Operators
4. Relational Operators
5. Short hand Assignment Operators
6. Comma operator
Addition +
Subtraction -
Multiplication *
Division /
Modulus %
Integer division truncates any fractional part. The % operator cannot be applied to float or double. The
direction of truncation for / and the sign of result for % operator are machine dependent for negative
operands, as in the action taken on overflow or underflow.
The binary + and – operators have the same precedence, which is lower than the precedence of *, /, and
%, which in turn lower than unary + and -. Arithmetic operators associate left to right.
#include <stdio.h>
int main( )
{
int num1 = 3,num2 = 5,num3 = 8;
int total;
float avg;
total = num1 + num2 + num3;
avg = total / 3;
printf(“\n Total = %d “,total);
printf(“\n avg = %f “,avg);
return 0;
OUTPUT:
}
Total = 16
Output: avg = 5.0
Observe the avg is 5.0 and not 5.33, because when both the operands are integers, integer division is
performed. In other words, integer division discards the part after the decimal point. So, 10/3 is 3 (not
3.3333…), 5/2 is 2 (not 2.5). To get the accurate result, we need to typecast. A type cast is a way of
changing a value of one type to another type.
© Cranes Varsity V5:2022-23 13/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
In some situations, you might want the answer to be the double value 5.33. You can get a result of 5.33 by
using the “equivalent” floating-point value 3.0 in place of the integer value 3, as in 16/3.0, which evaluates
to 5.33. But what if the 3 is the value of variables of type int named count? Then total/count yields 5. If you
want floating-point division in this case, you must do a type cast from int to float (or another floating-point
type), such as in the following:
avg = (float)total / count;
Assignment Operators
The assignment operator is used to assign the value to a variable. In C the equal sign is used as the
assignment operator. An assignment statement always consists of a variable on the left-hand side of the
equal sign and an expression on the right-hand side. An assignment statement ends with a semicolon.
The expression on the right-hand side of the equal sign may be a variable, a number, or a more
complicated expression made up of variables, numbers, operators, and function invocations. An
assignment statement instructs the computer to evaluate (that is, to compute the value of) the expression
on the right-hand side of the equal sign and to set the value of the variable on the left-hand side equal to
the value of that expression.
Syntax
Variable = Expression;
Examples
temperature = 98.6;
count = count + 2;
totalWeight = oneWeight * numberOfBeans;
When a variable is declared it contains undefined value commonly known as garbage value. If we
want we can assign some initial value to the variable during the declaration itself, this is called as
initialization of the variable. For example,
int a=5;
float x=8.9,y=10.5;
int l,m,n,total=0;
Relational Operators
The relational operators are used to check the relation between two operands. The relational operators
take two operands, compare them, and ``return” a value of 1 or 0 depending on whether the tested
relation was true or false. The complete set of relational operators in C is
int main( )
{
int a = 10,b = 50,res;
printf(“Enter the values of a and b :”);
scanf(“%d%d”,&a,&b);
res = a > b;
printf(“The result of comparison is %d\n”, res);
}
Logical Operators
&& AND
|| OR
! NOT (takes one operand; “unary”)
&& and || are used to combine conditions. Expressions connected by && or || are evaluated left to right,
and evaluation stops as soon as the truth or falsehood of the result is known.
Truth Tables
AND OR
Exp_1 Exp_2 Exp_1&&Exp_2 Exp_1 Exp_2 Exp_1||Exp_2
true true true true true true
true false false true false true
false true false false true true
false false false false false false
NOT
Exp !(Exp)
true false
false true
Program to demonstrate logical operators
int main( )
{
int marks1,marks2,marks3;
printf(“Enter the marks of 3 subjects :”);
scanf(“%d%d%d”,&marks1,&marks2,&marks3);
© Cranes if( marks1 > 40 && marks2 > 40 && marks3
Varsity > 40)
V5:2022-23 15/ 188
printf(“PASS”);
else
printf(“FAIL”);
}
Advanced C & Data Structure & Linux www.cranesvarsity.com
A shorthand notation exists that combines the assignment operator (=) and an arithmetic operator so that
a given variable can have its value changed by adding, subtracting, multiplying by, or dividing by a
specified value. The general form is
Variable Operator = Expression
which is equivalent to
Variable = Variable Operator (Expression)
The Expression can be another variable, a constant, or a more complicated arithmetic expression. The
following list gives examples.
EXAMPLE EQUIVALENT TO
We can also shift the bit pattern of an integer to the left or right.
| Bitwise OR Compares each bit of its first operand to the corresponding bit of its second
operand. If either bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is
set to 0.
^ Bitwise XOR Compares each bit of its first operand to the corresponding bit of its second
operand. If one bit is 0 and the other bit is 1, the corresponding result bit is set to 1. Otherwise, the
corresponding result bit is set to 0.
>> Right Shift right shifts of their left operand by the number of bit positions given by the right
operand
<< Left Shift Left shifts of their left operand by the number of bit positions given by the right
operand
One must distinguish the bitwise operators & and | from the logical operators && and ||, which imply left to
right evaluation of a truth value. For eg., if x is 1 and y is 2, then x & y is zero while x && y is one.
Program to demonstrate bit-wise operators
int main( )
{
int num ;
printf(“Enter the number : ”);
scanf(“%d”, &num);int main
if((num & 1) == 1) unsi = 0011 1100
printf(“Thegned %d is=odd=“,num);
number int 0000 1101
else 0x3C;
printf(“The number %d is even “,num);
unsi = 0000 1100
} = 0011 1101
gned int b =
0xD; = 0011 0001
print
f(“ a & b =
%x “, a & b);
print
f(“ a & b =
Program to Convert uppercase alphabet to lowercase
%x “, a | b);
int main( ) print
{ f(“ a & b =
char alpha; %x “, a ^ b);
printf("\n ENTER } A Alphabet : ");
scanf(“%c", &alpha);
alpha = (alpha | 0x20) ;
printf(“ %c ”,alpha);
return 0;
}
The shift operators << and >> perform left and right shifts of their left operand by the number of bit
positions given by the right operand, which must be non negative. Thus x << 2 shifts the value of x by two
positions, filling vacated bits with zero; this is equivalent to multiplication by 4. Right shifting an unsigned
quantity always fits the vacated bits with zero. Right shifting a signed quantity will fill with bit signs
(``arithmetic shift”) on some machines and with 0 bits (``logical shift”) on others. In logical shift, the
vacated bits are always filled with 0’s while in arithmetic shift, the vacated bits are filled with the sign bit.
The unary operator ~ yields the one’s complement of an integer; that is, it converts each 1x bit into a 0x bit
and vice versa
Right Shift by 1
Left Shift by 1
Clear/reset a bit
Set a bit
Toggle a bit
Operators Associativity
() [ ] -> . left to right
! ~ ++ - - + - * & (datatype) sizeof right to left
* / % left to right
+ - left to right
<<>> left to right
<<= >>= left to right
== != left to right
& left to right
^ left to right
| left to right
© Cranes
&& Varsity V5:2022-23
left to right 18/ 188
|| left to right
?: right to left
= += -= *= /= %= &= ^= |= <<= >>= right to left
, left to right
Advanced C & Data Structure & Linux www.cranesvarsity.com
Order of evaluation
For most operators, the order of evaluation of sub expressions is not guaranteed. In particular, you
normally cannot assume that the order of evaluation is left to right. For example, consider the following
expression:
n + (++n)
Suppose n has the value 2 before the expression is evaluated. Then, if the first expression is evaluated
first, the result is 2 + 3. If the second expression is evaluated first, the result is 3 + 3.
Since C does not guarantee the order of evaluation, the expression could evaluate to either 5 or 6. The
moral is that you should not program in a way that depends on order of evaluation, except for the
operators discussed in the next paragraph.
Some operators do guarantee that their order of evaluation of sub expressions is left to right. For the
operators && (and), || (or), and the comma operator, C guarantees that the order of evaluations is left to
right. Consider
(n <= 2) && (++n > 2)
Suppose n has the value 2, before the expression is evaluated. In this case you know that the sub
expression
(n <= 2) is evaluated before the value of n is incremented. You thus know that
(n <= 2) will evaluate to true and so the entire expression will evaluate to true.
Do not confuse order of operations (by precedence rules) with order of evaluation. For example,
(n + 2) * (++n) + 5
always means
((n + 2) * (++n)) + 5
However, it is not clear whether the ++n is evaluated before or after the n + 2. Either one could be
evaluated first.
Now you know why we said that it is usually a bad idea to use the increment (++) and decrement (--)
operators as sub expressions of larger expressions. If this is too confusing, just follow the simple rule of
not writing code that depends on the order of evaluation of sub expressions.
Types of Instructions
Arithmetic Instruction
Control Instruction
To declare a variable in C
Syntax: Data_typevariable_name; (more than one variable of the same type are
separated by commas)
Ex: char gender ;
int total;
float avg ;
Formatted Functions.
Unformatted Functions
Formatted Functions: These functions allow us to supply the input in a fixed format and let us obtain the
output in a specified form.
Unformatted Functions: They are opposite to formatted functions. These are the library functions which
can deal with a single character or with a set of characters (string).
Note
Each variable name must be preceded by an ‘&'. (Because the arguments are actually pointers that
indicated where the data items are stored in the computers memory), However array names should
notbeginwith&.
Commonly used conversion characters for data input
A minimum field width can be specified by preceding the conversion character by an unsigned integer, if
the width of the data item is less than the specified width, then the data item will be preceded by enough
leading blanks to fill the specified field. If the width of the data item is more than the specified field width,
then the specified width is ignored.
It is also possible to specify the maximum number of decimal places for floating-point value, or a
maximum number of characters for a string. This specification is known as precision. A floating-point value
will be rounded to conform to the precession specification.
In addition a flag can also be included which affects the appearance of the output. The flag must be
placed immediately after the % sign.
Example
printf(“%3d”, idata); //Since the specified width is smaller than value of idata, the specified width is
ignored.
printf(“%8d”,idata); // Since the specified width is larger than value of idata, the data is displayed within
the field width of 8 with 3 leading spaces
printf(“%17.3f”, fdata); // Since the precision is specified the rounding occurs, leading blanks are added
due to the minimum width specified.
printf(“%-10d”, idata); // Since the specified width is larger than value of idata, the data is displayed
within the field width of 10 with, since – flag is specified data is left aligned within the field width with
following spaces
printf(“%c %d %f \n”, ch, idata,fdata); // Displays the contents of ch, idata and fdata
CHAPTER – 3
CONTROL FLOW
The control flow statements of a language specify the order in which programs are performed.
There are three types of control instructions in C they are
The sequence control instruction ensures that the instructions are executed in the same order in
which they appear in the program. Built into C, statements are executed sequentially by default
The Decision control instructions allow the computer to take a decision as to which instruction is
to be executed next. The decision control statements are used when we want, a set of
instructions to be executed in one situation and a different set of instructions to be executed in
another situation. Decision control instructions can be implemented in C using
The if statement
Switch-case
if (condition)
{
statement(s);
}
Flowchart
When an if statement is encountered, condition is evaluated if the value is true, the statement(s)
(grouping is required if more than one statement is to be executed) is executed. If the condition
is false then the statement (s) following if are skipped.
The if-else statement – The if-else statement directs the computer to select a sequence of one or
more instructions based on the result of comparison.
The condition is checked if the result is true the statement(s) following if are executed, otherwise
the statement(s) following the else part are executed.
if(condition)
{
statement(s) if condition is true.
}
else
{
statement(s) if condition is false
}
Flowchart
The ?: are the ternary operators they can be used to replace the statements of the form if – else.
The general form is
Value = expression1 ? expression2 : expression3
If expression1 is true then the expression2 is executed otherwise expression3.
Ex: Value = (n > 0) ?1 : -1
If n > 0 is true then, value will be assigned 1 otherwise –1.
int main( )
{
int num1,num2,max;
printf(“Enter Twp Numbers : “);
scanf (“%d %d”, &num1,&num2);
max = (num1 > num2) ? num1 : num2 ;
printf(“\n The max = %d”,max);
return 0;
}
The switch statement provides an alternative to the if-else chain for cases that compare the
value of an integer expression to a specific value. The general form is
switch (expression)
{
case value1:
statement(s);
break;
case value2:
statement(s);
break;
case valueN:
statement(s);
break;
default:
statement(s);
break; /* Optional */
}
Flowchart
The switch statement uses four keywords switch, case, default and break. The keyword switch
identifies the start of the switch statement. The expression in parentheses following switch word
is evaluated and the result of the expression is compared to various alternative values contained
in the case within the switch statement.
The keyword case is used to identify label values that are compared to the value of the switch
expression.
The switch expression’s value is compared to each of these case values in the order that these
values are listed until a match is found.
When a match occurs, execution begins with the statement immediately following the match until
the break statement occurs or until the end of switch. Any number of case labels may be
contained within a switch statement in any order. The word default is optional and operates like
the last else in an if-else chain. If the value of the expression does not match with any of the
case values, program execution begins with the statement following the word default.
The break statement signals the end of the particular case, and causes the switch statement to
be terminated. At the end of every case, there should be a break statement. Otherwise, it will
result in causing the program execution to continue into the next case whenever the case gets
executed.
Note
Any number of case values may be contained within a switch statement in any order.
Even if there are multiple statements to be executed in each case there is no need to enclose
these within a pair of braces
If there is no default case, and if none of the case is matched, then the program simply falls
through the entire switch and continuous with next instruction that follows the control structure.
The disadvantage in switch is that one cannot have a case in a switch which looks like case i< =
2, even float is not allowed
The case can be an int constant, a char constant or it can be a constant expression like 1 * 2 + 4
as cases..
No two constant expressions in case statements can evaluate to the same value
The switch statement is very useful while writing menu driven programs.
#include <stdio.h>
#include <stdio_ext.h>
int main( )
{
int num1,num2,res;
char op ;
printf(“ ENTER THE FIRST OPERAND “);
scanf(“%d”,&num1);
printf(“\n ENTER THE OPERATOR : “);
__fpurge(stdin);
op = getchar( );
printf(“ ENTER THE SECOND OPERAND “);
scanf(“%d”,&num2);
switch(op)
{
case ‘+’ : res = num1 + num2; break;
case ‘-‘ : res = num1 – num2; break;
case ‘*’ : res = num1 * num2; break;
case ‘/’ : res = num1 / num2; break;
}
printf(“\n The result of %d %c %d = \ %d”,num1,op,num2,res);
return 0;
}
Looping Constructs
The versatility of the computer lies in its ability to perform a set of instructions repeatedly. This
involves repeating some portion of the problem either a specified number of times or until a
particular condition is being satisfied.
This repetitive operation is done through a loop control structure. There are three looping
statements in C
while loop
for loop
do-while loop
while loop:
Initialization;
while (expression)
{
statement(s);
}
The loop is executed as long as the expression is true and exits when the condition is false. The condition
being tested may use relational or logical operators.
Flowchart
for loop :
for loop allows us to specify three things about a loop in a single line:
Testing the loop counter to determine whether its value has reached the number of
repetitions desired.
Updating the value of loop counter each time the program segment within the loop has
been reached.
Initialization: This is usually an assignment statement that is used to set the loop control variable.
Expression: This is usually a relational expression that determines when the loop should terminate.
Update: This defines how the loop control variable should change each time the loop is repeated.
#include <stdio.h>
int main( )
{
int num, count;
printf(“\n ENTER A NUMBER : “);
scanf(“%d”,&num);
for(count = 0; num != 0 ; count++)
{
num /= 10;
© Cranes Varsity V5:2022-23 33/ 188
}
printf(“\n The no of digits = %d”,count);
return 0;
}
Advanced C & Data Structure & Linux www.cranesvarsity.com
#include <stdio.h>
int main( )
{
int num, i;
printf(“\n ENTER A NUMBER : “);
scanf(“%d”,&num);
for(i = 15 ; i>= 0 ; i--)
{
if(num & (1 <<i))
printf(“1”);
else
printf(“0”);
}
return 0;
}
do...while Statement
do
{
statement(s)
} while ( expression );
Flowchart
The loop body statement is executed once before the controlling expression is evaluated for the first time.
Unlike the while and for statements, do ... while ensures that at least one iteration of the loop body is
performed. If the controlling expression yields true, then another iteration follows. If false, the loop is
finished.
int main()
{
int num ;
int repeat;
do
{
printf(“Enter a number : “);
scanf(“%d”,&num);
if(num > 0)
printf(“Positive”);
else
printf(“Negative”);
printf(“Do you want to check another number(0-No 1-Yes) “);
scanf(“%d”,&repeat);
} while(repeat !=0);
}
The break statement can occur only in the body of a loop or a switch statement, and causes a jump to the
first statement after the loop or switch statement in which it is immediately contained.The break statement
can be used to end the execution of a loop statement at any position in the loop body.
Program to check if a given number is prime or not with and without break
The continue statement is used when it is required to bypass a part of looping statements. The behavior of
continue in different loops is as follows:
When the keyword continue is encountered inside the loop the control automatically passes to the
beginning of the loop. The continue will take the control to the condition block of the while and do-while
loop where as in for loop the control will be taken to the update part as shown in the above diagram.
Continue is usually associated with an if.
#include <stdio.h>
int main( )
{
int number, sum = 0, count = 0;
printf(“Enter 4 positive numbers, ONE PER LINE:\n”);
while (count < 4)
{
scanf(“%d”,&number);
if (number < 0)
{
printf(”ERROR: Enter positive number ! \
Reenter that number and continue:\n”);
continue;
}
sum = sum + number;
count++;
}
printf(“ %d is the sum of the %d numbers”,sum, count);
return 0;
}
Infinite loops
A while loop, do-while loop, or for loop does not terminate as long as the controlling Boolean expression is
true. This Boolean expression normally contains a variable that will be changed by the
loop body, and usually the value of this variable is changed in a way that eventually makes the Boolean
expression false and therefore terminates the loop. However, if you make a mistake and write your
program so that the Boolean expression is always true, then the loop will run forever. A loop that runs
forever is called an infinite loop.
Unfortunately, examples of infinite loops are not hard to come by. First let’s describe a loop that does
terminate. The following C code will write out the positive even numbers less than 12. That is, it will output
the numbers 2, 4, 6, 8, and 10, one per line, and then the loop will end.
x = 2;
while (x != 12)
{
printf(“ %d”,x);
x = x + 2;
}
The value of x is increased by 2 on each loop-iteration, until it reaches 12. At that point, the Boolean
expression after the word while is no longer true, so the loop ends. Now suppose you want to write out
the odd numbers less than 12, rather than the even numbers. You might mistakenly think that all you need
do is change the initializing statement to
x = 1;
But this mistake will create an infinite loop. Because the value of x goes from 11 to 13, the value of x is
never equal to 12; thus, the loop will never terminate. This sort of problem is common when loops are
terminated by checking a numeric quantity using == or !=. When dealing with numbers, it is always safer
to test for passing a value. For example, the following will work fine as the first line of our while loop:
while (x < 12)
With this change, x can be initialized to any number and the loop will still terminate.
Nested loops
It is perfectly legal to nest one loop statement inside another loop statement. A loop inside another loop is
called a nested loop. The depth of nested loop depends on the complexity of a problem. We can have any
number of nested loops as required. Consider a nested loop where the outer loop runs n times and
consists of another loop inside it. The inner loop runs m times. Then, the total number of times the inner
loop runs during the program execution is n*m. Consider the following snippet:
void main()
{
int row,col;
for(row=1;row<4;row++) // outer loop
{
for(col=1;col<4;col++) //inner loop
{
printf("%d\t%d\n",row,col);
© Cranes Varsity V5:2022-23 39/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
}
}
}
When doing so, remember that any break or continue statement applies to the innermost loop (or switch)
statement containing the break or continue statement. It is best to avoid nested loops by placing the inner
loop inside a function definition and placing a function invocation inside the outer loop.
Program to generate and print prime numbers in a given range. Also print the number of prime
numbers.
#include <stdio.h>
int main( )
{
int n,i,j,count;
printf(“\n Enter a number : “);
scanf(“%d”,&n);
count = 0;
for(j = 1 ; j <= n ; j++)
{
for(i = 2 ; i< j ; i++)
{
if(j % i == 0)
{
break;
}
}
if(i>= j)
{ count++;
printf(“\n %d”,j);
} }
printf(“Total No. of prime nos = %d”,count);
return (0);
}
CHAPTER - 4
FUNCTIONS
A function is a set of statements grouped under a particular name which perform a specific task. Every C
program can be thought as a collection of functions.
Functions fall into two categories: those written by the programmer (User defined function) and those
provided with the C language implementation (Built-in function). The latter are also called as library
functions which are supplied along with the compiler.
Library Functions:These are the predefined functions stored in what is called as library. These
are available on the system and are written by the people who develop compilers.
Ex: printf( ), sqrt ( ), scanf ( )…
User Defined Functions: These are developed by the programmers when the built in function will
not support the desired task. However, a user defined function can latter be made as part of the C library.
Parts of Function
3. Definition
Return_typefunction_name(argument declarations)
{
declarations and statements
}
Function_name (argument(s));
A function declaration specifies the rules and regulations to use the function by specifying the number and
type of arguments along with return value of the function. In addition, a function declaration may optionally
specify the function’s linkage.
Function Definitions
i) At least one “type specifier” as return value, which determines the type of value that the
function returns. Some function which returns an unsigned long int uses three type
specifiers.
ii) An optional storage class specifier static, which determines the scope of the function. If a
storage class specifier is not given, the function has external linkage.
iii) A function definition is the function name followed by a parenthesized list of parameter
types and names each parameter that the function expects.
A function can return one value of any type, except arrays. A function may return address like a pointer to
function, or a pointer to the first element of an array. To indicate that the function does not return a value,
declare return type as void.
Return Value
A called function returns a value to the caller using return statement. A function can return only one value
per call. The return statement can take one of the following forms
return; (only return, does not return any value, acts like a closing brace of function)
or
return expression or return (expression); (returns the value of the expression or variable
enclosed within ( ) to the caller.
Note
A function is defined when function name is followed by a pair of braces in which one
or more statements are present.
Any function can be called from any other function except those functions which are
static in some modules from some other module
The order in which the functions are defined in a program and the order in which they
are called need not be same.
Call by address
In C, all function arguments are passed ``by value.” This means that the called function is given the values
of its arguments in temporary variables rather than the originals. Call by value is an asset, however, not a
liability. It usually leads to more compact programs with fewer extraneous variables, because parameters
can be treated as conveniently initialized local variables in the called routine.
#include <stdio.h>
int addNumbers(int a, int b); // function prototype
© Cranes Varsity V5:2022-23 43/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
int main()
{
int n1,n2,sum;
printf("sum = %d",sum);
return 0;
}
Passing by address refers to a method of passing arguments where the value of an argument in the
calling function can be modified in the called function. This concept will be discussed later with pointer.
CHAPTER – 5
PREPROCESSOR
The Preprocessor
Preprocessing is the first task in C compilation. About Preprocessor in depth will be covered in this
chapter.
The C Compiler
The next stage of the process is the compilation of the preprocessed source code to assembly language,
for a specific processor.
Assembler
The assembler creates object code. On a UNIX system you may see files with a.o suffix.
Linker
If a source file references library functions or functions defined in other source files the link editor
combines these functions to create an executable file. External Variable references are also resolved by
the linker. The output of the linker is an executable file a.out in UNIX by default.
$ gcc –E program.c
Use the above command to view the preprocessed code.
$ gcc –S program.c
Use the above command to create an assembly file from the source file program.c. The assembly file
called program.s will be created.
$ gcc –c program.c
Use the above command to create an object file from the source file program.c. The object file called
program.o will be created.
$ gcc -o my_exeprogram.c
Use the above command to create an executable called my_exe from the source file program.c
Running the program
$ ./my_exe
To run an executable in Linux, you simply type the name of the file containing it in this case my_exe. If
you have not specified the executable filename then the file a.out will be created
The Preprocessor
The preprocessor is a program that is invoked by the compiler to process code before compilation.
Commands for that program, known as directives, are lines of the source file beginning with the character
#, which distinguishes them from lines of source program text. The effect of each preprocessor directive is
a change to the text of the source code, and the result is a new source code file, which does not contain
the directives. The preprocessed source code, an intermediate file, must be a valid C program because it
becomes the input to the compiler.
Easier to read,
Easier to modify
The macro templates and their expansion are separated by space and not =.
The directives can be placed anywhere in a program but are most often placed at the
beginning of a program, before main( ), or before the beginning of a particular function.
Macro substitution.
Conditional inclusion.
Miscellaneous directives.
File Inclusion
An external file containing functions or macro definitions can be included as a part of another file. This is
achieved by the preprocessor directive
#include <filename>
© Cranes Varsity V5:2022-23 47/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
or
#include “filename”
causes the contents of the specified file to be included for parsing, or compilation.
filename: Is the name of the file containing the required definitions or functions.
“Filename”: When the file name is included within the double quotation the search for the
file is made in the current directory and then in the standard directories.
<Filename>: When the file name is included within the angle signs, the file is searched
only in the standard path.
Headers may be included in any order. A header must be included outside of any external
declaration.
Declarations of global variables, we said that a global variable must have exactly one
defining instance, but that it can have external declarations in many places.
Structure declarations.
typedef declarations.
The operation to replace a macro name with its associated macro body is called macro substitution or
macro expansion.
You can use the #define directive to give a meaningful name to a constant in your program. The two forms
of the syntax are:
Syntax
#define identifiertoken-string
The #define directive, substitutes token-string for all subsequent occurrences of an identifier in the source
file. The identifier is replaced only when it forms a token.
Example
#define TRUE 1
#define SIZE 10
#define PI 3.141517
Note: macro templates (macros) are normally written in capitals. It is a convention to write all macros in
capitals to identify them as symbolic constant.
#include <stdio.h>
#define PI 3.14159
int main( )
{
int radius = 4;
float area, circumference ;
area = PI * radius * radius;
printf(“The area = %f “,area);
circumference = 2 * PI * radius;
printf(“The circumference = %f “, circumference);
return 0;
}
Macros with parameters
You can define macros with parameters. When the preprocessor expands such a macro, it incorporates
arguments you specify for each use of the macro in the replacement text. Macros with p
arameters are often calledfunction-like macros
Note
There should not be a space between macro template and its arguments
GREAT(a,b) /* correct */
GREAT (a,b) /* error no space allowed */
The entire macro expansion should be enclosed within parentheses.
SQUARE(n,m) (((n)*(n))/(m)) /* correct */
SQUARE(n,m) n*n /m /* The expected result may not be obtained */
The problem with side effects is that macros don’t evaluate their arguments; they just paste them into the
macro text when performing the substitution.
#define SQR(x) x*x
int main( ) int main( )
{ {
int x = 2; int x = 2;
printf(“%d”,SQR(x + 3)); printf(“%d ” ,x+3*x+3);
} }
© Cranes Varsity
Output : 11 instead of 25 V5:2022-23 49/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
A const object is subject to the scoping rules for variables, whereas a constant created using
#define is not.
Unlike a const object, the value of a macro does not appear in the intermediate source code used
by the compiler because they are expanded inline.
The inline expansion makes the macro value unavailable to the debugger.
A macro can be used in a constant expression, such as an array bound, whereas a const object
cannot.
Whenever there is a function call the control is passed to the function and after executing the function the
control is returned back to the calling function, hence the program has to save the required information
about the currently executing function before switching to the called function in order to continue the
execution of the current function later. This is an overhead and therefore slows down the program. This
can be avoided using macros; in a macro call the preprocessor replaces the macro with its macro
expansion. Macros increase the program speed, but they use more memory. Functions use more CPU
time but less memory. Hence small functions can be replaced by macros.
Argument to function are evaluated and then passed where as in macros arguments are expanded and
then evaluated.
A preprocessor undef directive causes the preprocessor to end the scope of a preprocessor definition. If
the identifier is not currently defined as a macro, #undef is ignored.
Any occurrences of the identifiers BUFFER and SQR that follow these #undef directives are not replaced
with any replacement tokens. Once the definition of a macro has been removed by a #undef directive, the
identifier can be used in a new #define directive.
Predefined Macros
The compiler recognizes several simple macros that are predefined.
You can use them without giving definitions for them.
Macro Description
__ FILE __ The name of the current source file. __FILE__ expands to a string
__ LINE __ The line number in the current source file. The line number is a
decimal integer constant.
__ DATE __ The compilation date of the current source file. .
__TIME __ The most recent compilation time of the current source file.
int main()
{
printf("\n FILE NAME : %s ",__FILE__);
printf("\n DATE OF COMPILATION : %s ",__DATE__);
printf("\n TIME OF COMPILATION : %s ",__TIME__);
printf("\n LINE NUMBER : %d ",__LINE__);
}
CONDITIONAL COMPILATION
Conditional compilation as the name implies code is compiled if certain condition(s) hold true.
Conditional compilation is the process of selecting the source code conditionally from the program and
sending to the compiler using preprocessor statements. Normally we use if keyword for checking some
condition, Since it is conditional compilation we need to use a slightly different syntax so that compiler can
determine whether to compile the code or not.
A preprocessor conditional inclusion directive causes the preprocessor to conditionally suppress the
compilation of portions of source code. These directives test a constant expression or an identifier to
determine which tokens the preprocessor should pass on to the compiler and which tokens should be
bypassed during preprocessing. The directives are:
#if
#ifdef
#else
#ifndef
#elif
#endi
The #ifdef and #endif directives control whether a given group of statements is to be included as part of
your program.The general form to use the #ifdef and #endif directives is
#ifdef macro_name
statement1
statement2
...
statement
#endif
Here macro_name is any character string that can be defined by #define directive.
Statement1,statement2, and statement are statements that are included in the program if macro_name
has been defined. If macro_name has not been defined, statement1, statement2, and statement are
skipped.
Because the statements under the control of the #ifdef directive are not enclosed in braces, the #endif
directive must be used to mark the end of the #ifdef block.
Example
#ifdef EXTENDED
#define MAX_LEN 75
#else
#define MAX_LEN 50
#endif
The #ifndef directive enables you to define code that is to be executed when a particular macro name is
not defined.
#ifndef macro_name
Statement1
Statement2
...
StatementN
#endif
Example
© Cranes Varsity V5:2022-23 53/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
#ifndef EXTENDED
#define MAX_LEN 50
#else
#define MAX_LEN 75
#endif
Example
#include <stdio.h>
int main()
{
#define COMPUTER "An amazing device"
#ifdef COMPUTER
printf(COMPUTER);
#endif
return 0;
}
The preprocessor selection statement ( #if ) checks the condition. If it is true or a non-zero then
statements between #if and #else are sent to the compiler. If it is false or a zero then statements between
#else and #endif are sent to the compiler.
The constant_expression that is tested must be integer constant expressions with the following
properties:
Example
#include <stdio.h>
#define A 10
#define B 40
int main()
{
#if A==B
printf("Hello");
#elif A>B
printf("World");
#else
printf("CodingFox");
#endif
© Cranes Varsity V5:2022-23 54/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
return 0;
}
It checks whether a macro with the name is defined or not. It returns true if in case macro with the name
is defined otherwise returns false.
Example
#define<stdio.h>
#define MAX
int main()
{
#if defined(MAX)
printf("Hello");
#else
printf("World");
#endif
printf("\n");
#if !defined(MIN)
printf("Fox");
#else
printf("Duck");
#endif
return 0;
}
Here defined(MAX) gives true as the macro MAX is defined, defined(MIN) gives false as the macro MIN is
not defined.
At the first occurrence of a directive to include the file myheader.h, the macro MYHEADER_H is not yet
defined. The preprocessor therefore inserts the contents of the block between #ifndef and #endif
including the definition of the macro MYHEADER_H. On subsequent insertions of myheader.h, the #ifndef
condition is false, and the preprocessor discards the block up to #endif
A preprocessor error directive causes the preprocessor to generate an error message and causes the
compilation to fail.
The #error directive is often used in the #else portion of a #if-#elif-#else construct, as a safety check
during compilation. For example, #error directives in the source file can prevent code generation if a
section of the program is reached that should be bypassed.
#undef directive
The #undef directive removes the current definition of identifier. Consequently, subsequent occurrences
of identifier are ignored by the preprocessor.
The #undef directive is typically paired with a #define directive to create a region in a source program in
which an identifier has a special meaning. For example, a specific function of the source program can use
manifest constants to define environment-specific values that do not affect the rest of the program.
The #undef directive also works with the #if directive to control conditional compilation of the source
program.
In the following example, the #undef directive removes definitions of a symbolic constant and a macro.
Note that only the identifier of the macro is given.
#define WIDTH 80
#define ADD( X, Y ) ((X) + (Y))
.
.
.
#undef WIDTH
#undef ADD
Till now, we have been writing programs made of single source file. Large applications cannot be
programmed in single source file; instead, it consists of several source files, developed simultaneously by
different members.
© Cranes Varsity V5:2022-23 56/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
Let’s say, we would like to write a program to calculate the factorial of a given number using functions.
Two files are created, one consists of function to calculate the factorial and the other contains the main,
which invokes the factorial function.
Example
/******************** main.c ***************/
#include<stdio.h>
int fact(int); //function declaration
int main()
{
int num , res;
printf(“Enter the number : “);
scanf(“%d”,&num);
res = fact(num);
printf(“Factorial of %d = %d\n”,num,res);
$gcc main.c
Linker Error : Undefined reference to fact.
$gcc factorial.c
Linker Error : Undefined reference to main.
To compile the program, both files should be compiled and linked together.
$gcc main.c factorial.c
We can compile individual files, which checks for syntax error and generates object code. Once all the
files are compiled, we can link the compiled files.
$gcc –c main.c
$gcc –c factorial.c
$gcc main.o factorial.o
$./a.out
By the time you have realized that modularization makes source code easy to manage. Along with that, it
speeds up the re-compilation as you need to recompile only changed source file.
CHAPTER – 6
STORAGE CLASSES
Storage Class:
The storage classes specify the scope and life time of a variable. There are two types of storage classes.
Automatic Storage Class -This type of storage classes helps us to create the variables
temporarily to keep the data for a limited time and scope which helps us to save the memory at
the time of execution.
Static Storage Class - static objects may be created with a block or outside the block, but
in either case static objects retain their values across exit and re-entery to functions or modules.
A storage class specifier is used to refine the declaration of a variable. The basic declaration is like this:
Variable created with storage class specifiers gives the following information:
What will be the initial value of the variable, if the initial value is not explicitly assigned
(i.e. the default initial value).
What is the scope of the variable i.e. in which context the variable is accessible.
What will be the life of the variable, i.e. how long the variables exist?
register
static
extern
auto (automatic)
The features of a variable defined to have an automatic storage class are as below:
Storage - Stack segment
Default initial value - An unpredictable value, which is often called Garbage value
Scope - Local to the block in which the variable is defined.
Life - Till the control remains within the block in which the variable is defined.
Example
int main (void)
{
© Cranes Varsity V5:2022-23 59/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
register
A variable stored in the CPU register can always be accessed faster than the one, which is stored in Data
Segment or Stack Segment memory. Therefore, if a variable is frequently accessed in the program it is
better to create it as register variable.
Example
Here even though i is declared as register, there is no guarantee that the variable will get CPU register
memory, because the number of CPU registers is limited (14 in case of a microcomputer), if CPU
registers are busy doing some other task the variable will be treated as if it is of auto storage class.
Note: It is not possible to make a global or static variable as register. It is not possible to define float or
double variables as register.
Static
The features of a variable defined to have a static storage class are as under:
Like auto variables, static variable are also local to the block in which they are declared. The difference
between automatic and static variables is that the automatic variables will be destroyed at the end of the
block or context where as the static variables will not be destroyed.
The static variables will be destroyed only at the end process. The static variables will retain their value
between the accesses. Based on whether the initialization is done or not, the memory is given in either of
two sections of Data Segment.
© Cranes Varsity V5:2022-23 60/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
Example
static int x; /* Created in Un-initialized Data Segment */
static int y = 10; /* Created in Initialized Data Segment */
#include <stdio.h>
void funcallcount(void);
int main( )
{
char ch ;
do
{
funcallcount( );
printf(“\nDo you want to call again. \Enter y to continue :”);
c = getchar( );
} while (ch == ‘y’);
return 0;
}
void funcallcount(void)
void funcallcount(void)
{
{
static int count;
static int count;
count++;
count++;
printf(“Function invoked %d times”, count);
printf(“Function invoked %d times”, count);
}
}
Use static storage class only if you want the value of a variable to persist between
different function calls.
Use register storage class for only those variables which are being used very often in the
program. Application of register storage class is loop counters which get used a number of times
in a program.
External variables are those which are defined outside all blocks. They can be accessed by all functions.
Because external variables are globally accessible, they can be used instead of argument lists to
© Cranes Varsity V5:2022-23 61/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
communicate data between functions. Furthermore, because external variables remain in existence
permanently, rather than appearing and disappearing as functions are called and exited, they retain their
values even after the functions that set/modify them have returned. All global variables are external
variables.
An external variable must be defined, exactly once, outside of any function; this sets aside storage for it.
The variable must also be declared in each function that wants to access it. The declaration may be an
explicit extern statement or may be implicit from context .
Extern
The extern storage class specifier is used for external linkage. The global variable that has been defined
in one module can be accessed in another if there is an external linkage with the help of extern keyword.
In the below example there are two files File1.c and Main.c. The variable Num1 of File1.c is accessed
because of external linkage done in main using extern keyword. Internal linkage can be made by
specifying the static keyword.
It is not possible to access St_num variable in the Main.c file because of internal linkage done by using
static keyword.
Example
/******************** File1.c ***************/
extern int st_num; /* error static variables are not
accessible */
extern int num1;//External Declaration
void Fun1(void)
{
printf(”Num1 = %d\n”, num1);
printf(”St_num = %d\n”, st_num);
Fun2(); // Valid
}
void Fun1(void);
static void Fun2(void);
int main(void)
© Cranes Varsity V5:2022-23 62/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
{
printf(“Num1 = %d\n”, num1);
num1 = 100;
Fun1( );
num1 = 200;
Fun2( ); /* Error : because of internal linkage */
}
$gcc –c File1.c
$gcc –c Main.c
$gcc –o program File1.o Main.o
$./program
Storage class
specifier Scope Lifetime Storage Default value Linkage
area
within block stack garbage
auto block segment value no
1. Use static storage class only if you want the value of a variable to persist between
different function calls.
2. Use register storage class for only those variables which are being used very often in the
program. Application of register storage class is loop counters which get used a number
of times in a program.
3. Use extern storage class for only those variables which are being used by almost all the
functions in the program.
CHAPTER – 7
ARRAYS
C programming provides a capability that enables a user to define a set of elements of similar data types
which can be referred by single name, called Arrays.
Suppose we had a set of grades that we wished to read into the computer and suppose we wished to
perform some operations on these grades, we will quickly realize that we cannot perform such an
operation until each and every grade has been entered since it would be quite a tedious task to declare
each and every student grade as a variable especially since there may be a very large number.
In C we can define a variable called grade, which represents not a single value of grade but an entire set
of grades. Each element of the set can then be referenced by means of a number called as index number
or subscript.
Declaration of arrays
Like any other variable arrays must be declared before they are used. The general form of declaration is:
<datatype><variable-name>[<no_of_elements>];
The type specifies the type of the elements that will be contained in the array, such as int float or char and
the size indicates the maximum number of elements that can be stored inside the array.
Declares the grade to be an array containing 50 integer elements. The array elements are accessed using
subscript. The array elements index or subscript begins with number zero. So grade [0] refers to the first
element of the array. . Any subscripts 0 to 29 are valid.
The declaration
#define MAX 5
would reserve enough space for an array called values that could hold up to 5 integers. Refer to the
below given picture to conceptualize the reserved storage space.
Values [0]
Values [1]
Values [2]
Values [3]
© Cranes Varsity V5:2022-23 65/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
Values [4]
Once the array is declared the computer reserves the amount of memory specified in the declaration. In
the above declaration 5 x 4 bytes of memory is reserved (32 bit compiler).
You can use these”array subscript expressions” anywhere, like the name of a simple variable, for
example:
Value [0] = 10;
Value [1] = 20;
Value [2] = Value [0] + Value [1];
Notice that the subscripted array references can appear on either side of the assignment operator. The
subscript does not have to be a constant like 0 or 1; it can be any integral expression. For example, it’s
common to loop over all elements of an array:
#define MAX 10
int i;
for(i = 0; i< MAX ; i++)
Value [ i ] = 0;
This loop sets all ten elements of the array value to 0. Arrays are a real convenience for many problems,
but there is not a lot that C will do with them for you automatically. In particular, you can neither set all
elements of an array at once nor assign one array to another; both of the assignments are illegal
Value = 0; /* WRONG */
And
int b[MAX]; // MAX is macro
b = Value; /* WRONG */
To set all of the elements of an array to some value, you must do so one by one, as in the loop example
above. To copy the contents of one array to another, you must again do so one by one:
int b[MAX];
for(i = 0; i< MAX; i ++)
b [i] = Value [i];
Remember that for an array declared
int Value[10];
There is no element Value[10]; the topmost element is Value [9]. This is one reason that zero-based
loops are also common in C.
Initialization of Arrays
We can initialize the elements in the array in the same way as the ordinary variables when they are
declared. The general form of initialization of arrays is:
will declare the array size as an array of size 3 and will assign zero to each element if the number of
values in the list is less than the number of elements, then only that many elements are initialized. The
remaining elements will be set to zero automatically.
In the declaration of an array the size may be omitted, in such cases the compiler generates the code to
allocate enough space for all initialized elements. For example the statement
Will declare the array to contain four elements with initial values 1.
Bounds Checking
In C there is no bound checking to check whether the subscript used for an array exceeds the size of the
array. Data entered with subscript exceeding the array size will simply be placed in memory outside the
array; probably overwrite the other’s data. There will be no error message displayed to warn. In some
cases the system may hang. Hence it is the programmer’s responsibility to keep track of the array size.
When you want to pass an array to function, just mention the name of the array while calling the function.
At the receiving end use an array notation.
Arrays do not carry information about their own sizes. If array size is needed, you must supply it as an
additional argument
When you pass an array, it is passed by address and any changes done to an array will reflect the actual
array.
Searching Algorithm
Linear search is the simplest search algorithm. It compares each element of the array with the key
element in sequence. It can be applied on sorted and unsorted arrays.
Its worst case complexity is proportional to the number of elements in the list O(n). It is suitable for
smaller list.
Binary Search
It is a fast way to search for key element in a sorted array. The idea is to look at the element in the
middle. If the key is equal to that, the search is finished. If the key is less than the middle element, do a
binary search on the first half. If it’s greater, do a binary search of the second half.
The advantage of a binary search over a linear search is, it takes less number of searches. The worst
case complexity is O(log2n). To search for an element in a list of 1000 elements, binary search requires
max of 10 comparisons.
This performance comes at a price – the array must be sorted first. Because sorting isn’t a fast operation,
it may not be worth the effort to sort when there are only a few searches.
Function for binary search
Sorting
Introduction
What will you do if you were asked to search for a particular telephone number in a directory? You will
ask for the surname of the particular person and as the directory is sorted in an ascending order of
alphabets, it will not be difficult to find the telephone number. But if the case is reverse, you know the
phone number and you wish to find the name of the person using the telephone directory, will it be easy
like the first case. One would have to search the entire directory sequentially for this purpose. Data
cannot be retrieved efficiently if it is not placed in a particular format.
To convert an unordered list of data items into an ordered list is known as sorting. We can define sorting
as arrangement of elements in a list according to the increasing or decreasing (ascending/descending)
value of each element. There are many programs and processes in the computer, which require sorted
data. Every time there is a new entry sorting is done and it is put in its proper position. A computer on an
average spends 25 to 40 % of its time in sorting. The only way to search any element in an unordered list
is to perform sequential search. If we have a list having thousands of records then this sequential search
will take a very large amount of time to search a given element. The worst part comes when you search
the whole list for a particular record, only to find that it does not exist. Sorting is one of the most important
operations to be performed on the list. The elements in the list may contain single values or records.
Sorting process should be done using minimum amount of time. There has been much work done to find
optimal algorithms to perform sorting under various environments.
SORTING Techniques:
Bubble Sort
Selection Sort
Insertion Sort
Bubble Sort
Bubble sort is a simple sorting algorithm. It works by repeatedly stepping through the list to be sorted,
comparing two items at a time and swapping them if they are in the wrong order. The pass through the list
is repeated until no swaps are needed, which indicates that the list is sorted. The algorithm gets its name
from the way smaller elements "bubble" to the top of the list. Because it only uses comparisons to operate
on elements, it is a comparison sort.
Bubble sort has worst-case complexity О(n²), where n is the number of items being sorted. There exist
many other sorting algorithms with substantially better worst-case complexity O(n log n), meaning that
bubble sort should not be used when n is large.
Step-by-step example
Let us take the array of numbers "5 1 4 2 8", and sort the array from lowest number to greatest number
using bubble sort algorithm. In each step, elements written in bold are being compared.
First Pass
(51 4 2 8) (15 4 2 8) Here, algorithm compares the first two elements, and swaps them.
(1 5 4 2 8) (1 4 5 2 8)
(1 4 5 2 8) (1 4 2 5 8)
(1 4 2 5 8) (1 4 2 5 8)
Now, since these elements are already in order, algorithm does not swap them.
Second Pass
(14 2 5 8) (14 2 5 8)
(1 4 2 5 8) (1 2 4 5 8)
(1 2 4 5 8) (1 2 4 5 8)
(1 2 4 5 8) (1 2 4 5 8)
Now, the array is already sorted, but our algorithm does not know if it is completed. Algorithm needs one
whole pass without any swap to know it is sorted.
Third Pass
(124 5 8) (124 5 8)
(1 2 4 5 8) (1 2 4 5 8)
(12 4 5 8) (12 4 5 8)
(1 2 4 5 8) (1 2 4 5 8)
Implementation.
#include<stdio.h>
void Bubble_Sort (int *a, int n)
© Cranes
{ Varsity V5:2022-23 71/ 188
Selection Sort
The idea of Selection Sort is rather simple. It basically determines the minimum (or maximum) of the list
and swaps it with the element at the index where it is supposed to be.
Effectively, we divide the list into two parts: the sublist of items already sorted, which we build up from left
to right and is found at the beginning, and the sublist of items remaining to be sorted, occupying the
remainder of the array.
Analysis
Selecting the lowest element requires scanning all n elements (this takes n - 1 comparisons) and then
swapping it into the first position. Finding the next lowest element requires scanning the remaining n - 1
elements and so on, for (n - 1) + (n - 2) + ... + 2 + 1 = n(n - 1) / 2 = O(n2) comparisons. Each of these
scans requires one swap for n - 1 elements (the final element is already in place). Thus, the comparisons
dominate the running time, which is O(n2).
Implementation
Modified Bubble O(n^2) O(n) O(n^2) Stops after reaching a sorted array
sort
Selection Sort O(n^2) O(n^2) O(n^2) Even a perfectly sorted input
requires scanning the entire array
Insertion Sort O(n^2) O(n) O(n^2) In the best case (already sorted),
every insert requires constant time
Often there is a need to store and manipulate two dimensional arrays such as matrices & tables. Here the
array has two subscripts. One subscript denotes the row & the other the column.
For eg:
Example:
The above statement initializes the elements of first row to zero and second row to 1. The initialization is
done row by row. The above statement can be equivalently written as
To access individual element in a 2D array, we need to specify row index and column index.
Marks[i] [j]
or
Arrays do not carry information about their own sizes. If array size is needed, you must supply it as
argument
#include <stdio.h>
#define ROWS 10
#define COLS 10
void mattranspose(int mat[ ][COLS],int row,int col);
int main( )
{
int a[ROWS][COLS] = {{1,2,3},
{4,5,6},
{9,6,4},
{2,8,5}
};
mattranspose(a,4,3);
}
void mattranspose(int mat[ ][COLS],int row,int col)
{
int i,j;
for(i = 0 ; i< col ; i++)
{
for(j = 0 ; j < row ; j++)
printf(“ %d “,mat[j][i]);
printf(“\n”);
}
}
C allows arrays of three or more dimensions. The compiler determines the maximum number of
dimension. The general form of a multidimensional array declaration is:
<date_type><array_name> [s1][s2][s3]…..[sn];
Before we discuss in detail about debugger and especially of GNU debugger we need to understand
what do you mean by debugging and why is it a very important procedure in software development
life cycle. The following section discusses these issues in brief.
A software bug (or just “bug”) is an error, flaw, mistake, failure, or fault in a computer program that
prevents it from behaving as intended (e.g., producing an incorrect result). Most bugs arise from
mistakes and errors made by people in either a program’s source code or its design, and a few are
caused by compilers producing incorrect code. A program that contains a large number of bugs,
and/or bugs that seriously interfere with its functionality, is said to be buggy.
What is Debugging?
Debugging is a methodical process of finding and reducing the number of bugs, or defects, in a
computer program or a piece of electronic hardware thus making it behave as expected. Debugging
tends to be harder when various subsystems are tightly coupled, as changes in one may cause bugs
to emerge in another.
What is a Debugger?
A debugger is a program which runs other programs in such a way as to let you see every step of
program execution. A debugger will let you stop the program while it is running, change the program
or program variables, and start the program running again.
Debugging is, in general, a cumbersome and tiring task. The debugging skill of the programmer is
probably the biggest factor in the ability to debug a problem, but the difficulty of software debugging
varies greatly with the programming language used and the available tools, such as debuggers.
Debuggers are software tools which enable the programmer to monitor the execution of a program,
stop it, re-start it, set breakpoints, change values in memory and even, in some cases, go back in
time. The term debugger can also refer to the person who is doing the debugging.
Generally, high-level programming languages, such as Java, make debugging easier, because they
have features such as exception handling that make real sources of erratic behavior easier to spot.
In lower-level programming languages such as C or assembly, bugs may cause silent problems such
as memory corruption, and it is often difficult to see where the initial problem happened. In those
cases, debugger tools may be needed.
Now that we are familiar with what is debugging we can talk about GDB now.
Normal way to compile and link your program on the command prompt
[cranes@localhosttest]$gccexample.c
After the compilation and linking process we get a executable file with a default name a.out .
GDB requires some help from the compiler interms of debugging information . it needs the compiler to
insert debugging information in your object file , only then gdb can control your program.
GCC provides an option ‘ –g ’ while compiling so as to insert debug info in object file.
Invoking GDB and running our program (sample) under its control is simple, just type on the prompt:
[cranes@localhosttest]$gdb ./sample
Once the command executes gdb will start running on top of your process (program under execution)
sample.
Immediately we get a prompt from gdb and gdb waits for our command also making our program to wait
until we instruct gdb to run the program the way we intend to.
Prompt:
[cranes@localhosttest]$gdb ./sample
GNU gdb Red Hat Linux (5.3.90-0.20030710.40rh)Copyright 2003 Free Software Foundation, Inc.GDB is
free software, covered by the GNU General Public License, and you arewelcome to change it and/or
distribute copies of it under certain conditions.
Type “show copying” to see the conditions. There is absolutely no warranty for GDB. Type “show
warranty” for details.
This GDB was configured as “i386-redhat-linux-gnu”…Using host libthread_db library
“/lib/tls/libthread_db.so.1”.
(gdb)
GDB Commands
Command Description
help List gdb command topics.
help topic-classes List gdb command within class.
© Cranes Varsity V5:2022-23 78/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
Before we start giving commands to gdb we need to know one ivery important information , how to exit
gdb ? simple just type quit on the gdb prompt.
(gdb) quit
Advanced C
CHAPTER – 1
POINTERS
What is a pointer?
A pointer is a variable which holds the address of another variable. The value contained by a
pointer must be an address that indicates the location of another variable in the memory. That's
why a pointer is also called an address variable.
Pointer Declarations
The syntax for declaring pointers is like that for variables, except that pointers are distinguished
by an asterisk that prefixes their names. ‘*’ is called value at address operator. It is also called as
indirection operator. Hence if it is required to store an address of an integer use the following
declaration
int *ptr;
This declaration tells the compiler that ptr will be used to store the address of an integer. meaning
the value at the address contained in ptr is an int.
#include <stdio.h>
int main( )
{
int x, *ptr_x;
x = 7;
printf("x: address=%p, content=%d\n", &x, x);
ptr_x = &x;
printf("ptr_x: address=%p, content=%p\n", \
&ptr_x, ptr_x);
printf("*ptr_x => %d\n", *ptr_x);
return 0;
© Cranes Varsity V5:2022-23 83/ 188
}
Advanced C & Data Structure & Linux www.cranesvarsity.com
Note: The pointer type and the memory that it refers should be same. It is necessary that we
have to create an integer pointer to hold the address of type integer memory.
Example.
char char_var = ‘p’;
int num= 10, *ptr;
ptr = # /* Valid */
ptr = &char_var; /* Invalid */
Pointer dereferencing
We can use the pointer to retrieve data from memory or to store data into the memory to which it
points to. Both operations are classified as pointer dereferencing. It is also called as indirection
operator(‘ * ’) .
int var=10, var1, *ptr;
ptr = &var;
var1= *ptr;
In the above the first line is defining two normal variables var and var1 where asptr is a pointer
type of variable. In the second line ptr pointer, holds the address of var, and `var1 = *ptr' copies
the content of var into var1 using pointer.
Consider the following
char ch; /* a character */
char *pch; /* a pointer to a character */
char **ppch; /*a pointer to a pointer to a character */
ch = ‘A’;
pch = &ch;
ppch = &pch;
Here we can see that ch variable’s address is stored as the content of pch and the address of pch
is stored as the content of ppch.
The contents of ch normal variable is, the ASCII value of ‘A’
The contents of pch pointer is, the address of ch variable (pch = &ch)
By single indirection (dereferencing) gives the char data (*pch ‘A’)
The contents of ppch pointer is, the address of pch (ppch = &pch)
By single indirection (dereferencing) gives the address of the pointer (*ppch&ch)
By double indirection (dereferencing) gives the char data (**ppch ‘A’)
A pointer variable can be assigned a null(zero) value. (e.g., pv=NULL, where NULL
is a symbolic constant that represents the value 0).
An integer quantity can be added to or subtracted from a pointer variable. (e.g.,
pv+3, ++pv, pv – 2, pv--, etc.).
Pointers can be subtracted if the pointers are of same type. (e.g., pv-px), pointers
can be compared using relational operators (e.g., pv>px, pv==py, pv != py, etc.).
Arguments to Functions
Arguments are passed to functions in two ways.
Pass by value
Pass by address.
The parameter is initialized with the value of the argument. You can change the value of the
parameter (if that parameter has not been declared const) within the scope of the function, but
these changes will not affect the value of the argument in the calling function.
#include <stdio.h>
void increment (int *x);
int main ( )
{
int count = 5;
Pointers and arrays are closely related; Any operation that can be achieved by array subscripting
can also be done with pointers. The pointer version will in general be faster
Mentioning the name of array gives the base address of an array;
If pa points to a particular element of an array, then by definition pa+1 points to the next
element, pa+i points i elements after pa, and pa- i points i elements before. Thus, if pa points to
a[0], *(pa+1) refers to the contents of a[1], pa+i is the address of a[i], and *(pa+i) is the contents of
a[i].
These remarks are true regardless of the type or size of the variables in the array a. The meaning
of “adding 1 to a pointer”, and by extension, all pointer arithmetic, is that pa+1 points to the next
object, and pa+i points to the ‘iy’ th object beyond pa. a reference to a[i] can also be written as
*(a+i). In evaluating a[i], C converts it to *(a+i) immediately; the two forms are equivalent. Applying
the operator & to both parts of this equivalence, it follows that &a[i] and a+i are also identical: a+i
is the address of the iþth element beyond a. As the other side of this coin, if pa is a pointer,
expressions might use it with a subscript; pa[i] is identical to *(pa+i). In short, an arrayþandþ
index expression is equivalent to one written as a pointer and offset.
There is one difference between an array name and a pointer that must be kept in mind. A pointer
is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like
a=pa and a++ are illegal.
When an array name is passed to a function, what is passed is the location of the initial element.
Within the called function, this argument is a local variable,and so an array name parameter is a
pointer, that is, a variable containing an address.
Program to find the length of the string /* strlen: return length of string s */
int strlen(const char *s)
{
char *p = s;
while(*s++)
;
return s – p;
}
Since s is a pointer, incrementing it is perfectly legal; s++ has no effect on the character string in
the function that called strlen, but merely increments strlen's private copy of the pointer. That
means that calls like all work
CHAPTER 2
Advanced pointers
NULL Pointers
A pointer is a variable which can hold the address of another variable. There is one other value a
pointer may have: NULL value, then it is called as null pointer.
A null pointer is a special pointer not pointing to any variable or array cell which are usually
created either in Data Segment or in Stack segment, and also the null pointer is not pointing to
any valid memory in the heap.
The null pointer will hold NULL value as its content.
int *ip = NULL;
It is also possible to refer to the null pointer by using a constant 0, and you will see some code
that sets null pointers by simply doing
int *ip = 0;
Above said is legal, but the recommended one is using constant NULL for clarity.
The macro NULL is defined in stdlib.h, stdio.h and other header files as a null pointer constant.
A null pointer is always unequal to any valid pointer to an object or function. For this reason, functions
that return a pointer type usually use a null pointer to indicate a failure condition. One example is the
standard function malloc( ), which returns a null pointer if it fails to allocate the memory:
#include <stdio.h>
/* ... */
int *ptr = malloc(20);
if (ptr == NULL)
{
// Error: unable to allocate memory
}
Null pointers are implicitly converted to other pointer types as necessary for assignment operations, or for
comparisons using ==or !=. Hence no cast operator is necessary in the previous example.
The declaration
const float *pf; /* pf is a pointer to float constant */
establishes that pf points to value, that must remain constant. The value of pf itself can be
changed. For example, it can be set to point at another variable. In contrast, the declaration
To use it, you would pass the name of the array as an actual argument, but the name of an array is
an address, that would enable the function to alter data in the calling function. But the following
prototype prevents this from happening
In a prototype and a function header, the parameter declaration const int array[ ] is the same as
const int * array, so the declaration says that the data to which array points cannot be changed.
The ANSI C library follows this practice. If a pointer is used only to give a function access to
values, the pointer is declared as a pointer to a const-qualifier type. If the pointer is used to alter
data in the calling function, the const keyword isn’t used. For example, the ANSI C declaration for
strcat( ) is this:
char *strcat(char *,const char *);
Recall that strcat( ) adds a copy of the second string to the end of the first string. This modifies
the first string, but leaves the second string unchanged. The declaration reflects this.
str is an array, just big enough to hold the sequence of characters and'\0' that initializes it.
Individual characters within the array may be changed but str will always refer to the same
storage.
On the other hand, ptr is a pointer, initialized to point to a string constant; the pointer may
subsequently be modified to point elsewhere, but the result is undefined if you try to modify the
string contents.
return 0;
}
You can look at string literal as "a sequence of characters surrounded by double quotes". This
string is stored at read-only memory and trying to modify this memory leads to undefined
behavior (usually segmentation fault).
Array of Pointers
The way there can be an array of integers or an array of floats, similarly there can be an array of
pointers. Since a pointer variable always contains an address, an array of pointer would be
nothing but a collection of address. All rules that apply to an ordinary array applied to the array
of pointers as well.
#include <stdio.h>
#include <string.h>
void print_long (char **cities,int size);
int main( )
© Cranes Varsity V5:2022-23 90/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
{
int a = 10, b = 20, c = 30, I;
char *ptr = “Bangalore”;
char str[ ] = “Mumbai”;
char *cities [ ] = {“Delhi”, ”Hyderabad”, ptr, str};
print_long(cities, sizeof(cities) / sizeof(char *));
return 0;
}
void print_long (char **cities,int size)
{
int longindex, i;
longindex = 0;
for(i = 1 ; i< size ; i++)
{
if(strlen(cities[i]) >strlen(cities[longindex]))
longindex = i;
}
printf("\n %s \n",cities[longindex]);
}
Newcomers to C are sometimes confused about the difference between a two dimensional array
and an array of pointers. Given the definitions
int a[10][20];
int *b[10];
then a[3][4] and b[3][4] are both syntactically legal references to a single int. But a is a true two"
dimensional array: 200 int" sized locations have been set aside.
For b, however, the definition only allocates 10 pointers and does not initialize them; initialization
must be done explicitly, either statically or with code.
Example
char *p[ ] = {"hello", "goodbye", "so long", "thanks for all the help"};
// p is an array of 4 pointers
char *y; // let y be a pointer to a char so it can be used to move through a single
string
int i;
for(i=0;i<4;i++) // iterate for each string in x
{
puts(p[i]);
}
Notice that if we had used char x[ ][ ] = {…}; then the storage space would have been 4
strings of length 24 (the length of the longest string) or 96 bytes.In the above code memory used
is 16 bytes for pointer + 46(6 + 8 + 8 + 24) = 62.
/*Program to store 4 names in your Program and sort it in alphabetical order using array of
pointers*/
int main()
{
char *p[4]={" Swetha"," Abhishek"," Satish"," Kunal"};
char *temp;
int i,j;
printf("Before sorting: names are\n");
for(i=0;i<4;i++)
{
puts(p[i]);
}
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(strcmp(p[j],p[j+1])>0)
{
temp=p[j];
p[j]=p[j+1];
p[j+1]=temp;
}
}
Diagram
p
char * Satish
p[2]
char * Kunal
p[3]
Here, p is an array of 4 character pointers. The size of p is 16 bytes , whereas the size of p[0] is 4
bytes. p[0] is a pointer which points to the first string of the array .
Pointer to pointer
We can have pointers to int,char, float and in fact to any datatype , pointer to a pointer can also
be created. Consider,
int i = 5;
pptrptri
When we pass an array, its base address (address of the first element) will be passed and hence
the pointer of the same type should be used as the function parameter. Any modification made to
that array in the function will get reflected back.
Consider p is an array of 4 character pointers. If we want to declare a pointer which should point
to this array of pointers p, it should be of type char ** . That is,
char *p[ ] ={" Sikander","Naveen","Monica","Zubair"};
char **cptr = p;
char * Sikander
Swetha
char * Abhishek
Naveen
char * Satish
Monica
char * Zubair
Kunal
Pointer to a function
A pointer to a function points to the address of the function which is in Code Segment. We can
use pointers to function, to call functions, to pass function as an argument to other functions and
return a function’s address as the return value. But we cannot perform pointer arithmetic
operations on pointers to functions.
The type of a pointer to a function is based on both the return type and parameter types of the
function. A declaration of a pointer to a function must have the pointer name in parentheses. The
function call operator ( ) has a higher precedence than the dereference operator *. Without them,
the compiler interprets the statement as a function that returns a pointer to a specified return
type. For example:
In the first declaration, f is interpreted as a function that takes an int as argument, and returns a
pointer to an int. In the second declaration, g is interpreted as a pointer to a function that takes
an int argument and that returns an int.
Example
#include <stdio.h>
#include <string.h>
Callback Function
A useful function pointer application is a function callback. This is where a function pointer is
passed as a parameter to a function. As an example, let's say a function reads data from a file
but then does not know what to do when the data arrives. The programmer can use a callback
function that writes the data somewhere as it arrives.
#include <stdio.h>
#include <stdlib.h>
void my_write_func(char * str){
printf("received:%s", str);
}
Function pointers can be used in applications where we don’t know in advance which function
wil be called. Consider a program that has three inputs: 1, 2, and 3. For each input, a different
function is executed. This can easily be done with a switch statement, but it is easier to use an
array of function pointers, if the number of inputs is much larger. The program below shows both
approached.
int main()
{
int (*pf[4])(int,int) = {add,sub,mul,div};
int a,b,ch;
printf("\n ENTER TWO NUMBERS : ");
scanf("%d %d",&a,&b);
printf("\n 1. ADD 2. SUB 3. MAX 4. MIN: ");
© Cranes Varsity V5:2022-23 96/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
scanf("%d",&ch);
printf("\n The result = %d ",(*pf[ch-1])(a,b));
return 0;
}
The standard function qsorttakes a pointer to a comparison function as one of its arguments, in addition
to the information about the array to be sorted. qsort uses the pointer to call the specified function
whenever it has to compare two array elements.
Prototype of Qsort:
voidqsort(void*base,size_tnum,size_twidth,int(__cdecl*compare)(constvoid*elem1,constvoid
*elem2));
Program to demonstrate the use of function pointer passed as argument using qsort( ) library
function
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 5
int compareInt(const void *a,const void *b)
{
return *(int *)a - *(int *)b;
}
int compareString(const void *a,const void *b)
{
return strcmp(a,b);
}
void displayInt(int arr[ ],int n)
{
int i;
for(i = 0 ; i< n ; i++)
printf(" %d ",arr[i]);
}
void displayString(char arr[ ][20],int n)
{
int i;
for(i = 0 ; i< n ; i++)
printf(" %s ",arr[i]);
}
main( )
{
int arr[N] = {5, 32, 8, 16, 9};
char name[N][20] = {"Swetha","Abhishek","Satish","Kunal"};
© Cranes Varsity V5:2022-23 97/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
qsort(arr,N,sizeof(int),compareInt);
printf("\n THE SORTED ELEMENTS ARE \n");
displayInt(arr,N);
qsort(name,N,20,compareString);
printf("\n THE SORTED ELEMENTS ARE \n");
displayString(name,N);
}
void *bsearch(const void *key, const void *base, The bsearch function performs a binary
size_t num, size_t width, search of a sorted array of num
int (*compar)(const void *, const void elements, each of width bytes in size.
*));
void *lsearch(const void *key, void *base, size_t *num, The lsearch function performs a linear
size_t size, int(*compar)(const void *, const void *)); search for the value key in an array of
num elements, each of width bytes in
size. If key is not found, lsearch adds it to
the end of the array and increments num.
void *lfind(const void *key, const void *base, Similar to lsearch. If key is not found,
size_t *nmemb, size_t size, return NULL
int(*compar)(const void *, const void *));
There are several possible uses of pointer to function:
In writing Device Driver programs for operating system
#pragma
The #pragma directive gives special instructions to the compiler. The #pragma directive is
especially useful in embedded C programming and can tell the compiler to allocate a certain
variable in RAM or EEPROM. It can also tell the compiler to insert a snippet of assembly
language code.
The GNU GCC compiler, also uses attributes as an alternative syntax to the #pragma directive
#pragmapack modifies the current alignment rule for members of structures that follow this
pragma.
Examples
This example shows how a #pragma pack directive can affect the size and mapping of a structure:
struct test
{
char a;
int b;
short c;
int d;
}S;
Void Pointers
A void pointer (void *ptr) is called as generic pointer. We can assign the address of any type of
variable to void pointer without casting and the address of void pointer can be assigned to any
type of pointer without casting.
int x = 10 , *iptr;
float y = 3.5 , *fptr;
void *vptr;
{
int num= 10;
char char_var = ‘u’;
void *ptr;
ptr = # /* Valid */
printf(“%d “, *(int *) ptr); /* Casting is a must */
ptr = &char_var; /* Valid */
printf(“%c “, *(char *) ptr); /* Casting is a must */
return 0;
}
All the variables in every program up to this point have been either automatic or static variables.
i.e., the memory will be automatically allocated on declaring it and is de-allocated automatically
when the control goes out of the block in which it is declared.
Dynamic memory is the memory that does not exist when the program is loaded, but is created /
allocated dynamically as they are needed during the execution of the program. It is possible,
using these techniques, to create as much memory (till heap is not full) as needed, use them, and
de-allocate their memory space for reuse by other variables. Memory allocated dynamically will be
allocated from the heap segment.
Heap Memory
"Heap" memory, also known as "dynamic" memory is a large area of memory available for use by
the program. Heap memory is different in every way. The programmer explicitly requests the
allocation of a memory "block" of a particular size. In order to allocate a block of some size, the
program makes an explicit request by calling the heap allocation function. The allocation function
reserves a block of memory of the requested size in the heap and returns a pointer to it (Address).
The block continues to be allocated until the programmer explicitly requests that it has to be
deallocated.
Nothing happens automatically. So the programmer has much greater control of memory, but with
greater responsibility.
C provides access to the heap memory through a set of library functions. The prototypes for these
functions are in the file <stdlib.h>, so any code which wants to call these must include that header
file.
malloc ( ):This function will try to get a contiguous block of memory of the required size. It
returns a pointer to the memory it found, if it could get some. If not it returns a NULL pointer. The
syntax for the malloc ( ) function is
void *malloc (size_t size);
You must always check to make sure that malloc is successful or not before you use the memory.
malloc has one parameter, the size of the block of memory you want. You can use sizeof to
specify how much memory you need, for example:
sizeof (int) * 99
would be enough space for 99 integers. Because malloc returns a pointer of type void it must be
typecasted to make this compatible with the type you want; i.e. if you want to store 99 integers
you will have a pointer to integers which you want to make point at the block of memory which
malloc is going to get for you. The cast will make sure that the compiler does not produce an error
when it sees the assignment,
Example
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char * buffer ;
int size;
printf(“ ENTER THE SIZE : “);
scanf(“ %d”,&size);
buffer = (char *) malloc (sizeof (char) * size) ;
if (buffer == NULL) {
printf("No memory!\n") ;
exit (-1);
}
else {
/* Do something with the memory */
}
return 0;
}
We can access an item in buffer in exactly the same way as we access elements in an array if
memory allocation is successful.
free ( ):
The syntax for the free ( ) function is
free takes a pointer to a heap block earlier allocated and returns that block to the heap for re-use.
After the free ( ), the client should not access any part of the block or assume that the block is
valid memory. The block should not be freed a second time.
It is good programming practice to always give back memory which you have allocated. If you
do not you might find that the total amount of memory available will drop to a point where your
program will not run any more.
Double Free
int main()
{
int *ptr = malloc(20);
printf(“ ptr = %p \n“,ptr);
free(ptr);
printf(“\n ptr = %p \n“,ptr);
free(ptr);
calloc( )
Besides the malloc ( ) function, you can also use the calloc ( ) function to allocate a memory
dynamically. The differences between the two functions are that the latter takes two arguments
and that the memory space allocated by calloc( ) is always initialized to 0. The syntax for the
calloc( ) function is
Here nitem is the number of items you want to save in the allocated memory space. size gives the
number of bytes that each item takes. The calloc( ) function returns a void pointer too. If the
calloc( ) function fails to allocate a piece of memory space, it returns a null pointer.
}
return 0;
Realloc( )
The realloc( ) function gives you a means to change the size of a piece of memory space allocated
by the malloc( ) or the calloc( ) function, or even itself.
The syntax for the realloc( ) function is
Here block is the pointer to the start of a piece of memory space previously allocated. size
specifies the total byte number you want to change to. The realloc( ) function also returns a void
pointer. If the realloc( ) is successful then it returns the address. i.e., if the user wants to increase
the memory allocated to the pointer, then there is a possibility of giving a new memory address by
copying the data from old memory into new memory or by extending the existing memory realloc(
) returns the same address what was there earlier. That’s why it is necessary that we have to
collect the return value of realloc( ) function in a new pointer. The realloc( ) function returns a null
pointer if it fails to reallocate a piece of memory space. The realloc( ) function is equivalent to the
malloc( ) function if the first argument passed to realloc( ) is NULL. In other words, the following
two statements are equivalent:
Also, you can use the realloc( ) function as the free ( ) function. You do this by passing 0 to
realloc( ) as its second argument. For instance, to release a block of memory pointed to by a
pointer ptr, you can either call the free ( ) function like this:
free (ptr);
or use the realloc( ) function in the following way:
realloc (ptr, 0);
#include <stdio.h>
#include <stdlib.h>
int main( )
{
float *ptr1,*ptr2;
int i, n = 5;
if (ptr1 == NULL)
printf("calloc( ) failed.\n");
else
{
N = 10;
ptr2 = (float *)realloc(ptr1, n * sizeof(float));
if (ptr2 == NULL)
fprintf(stderr, “Error : In Realloc( ) \n “);
else if (ptr1 != ptr2) /* If new block of memory is allocated */
{
ptr1 = ptr2; /*Make ptr1 point to new block*/
}
else
{
/* Use ptr1. */
}
}
return 0;
Memory Leaks
What happens if some memory in heap is allocated, but never deallocated? A block or function
which forgets to deallocate a block is said to have a "memory leak" which may be a serious
problem. The result will be that the heap gradually fills up as there continue to be allocation
requests, but no deallocation requests to return blocks for re-use.
For a program which runs, computes something, and exits immediately, memory leaks are not
usually a concern. Such a "one shot" program could omit all of its de-allocation requests and still
mostly work. Memory leaks are more of a problem for a program which runs for an indeterminate
amount of time. In that case, the memory can gradually fill the heap and further memory allocation
requests cannot be satisfied, and the program stops working or crashes. Many commercial
programs have memory leaks, so that when run for long enough, or with large data-sets, they fill
their heaps and crash. Often the error detection and avoidance code for the heap-full error
condition is not well tested, precisely because the case is rarely encountered with short runs of
the program — that's why filling the heap often results in a real crash instead of a polite error
message. Most compilers have a "heap debugging" utility which adds debugging code to a
program to track every allocation and deallocation. When an allocation has no matching
deallocation, that's a leak, and the heap debugger can help you find them.
Like most of the function the main can also take the arguments. To pass the values to the main
function as an argument we need to specify the values along with the executable file name on the
command line. This is known as command line argument.
Example the vi command itself will take the file name as an argument to open the file
$ vi Fcopy.c
Here vi is a command which is taking the argument Fcopy.c from the command line. In order to be
able to use such arguments in our code we must define them as follows: int
main(int argc, char *argv[ ])
argc is the number of command line arguments (including the program name).
argv is a pointer to an array of character type, holding each command line argument --
including the program name in the first array element.
/* program to print arguments from command line and to find the sum total of the given
numbers */
#include<stdio.h>
int main (int argc, char *argv[ ])
{
int i, sum = 0 ;
printf(“\ntotal no of arguments = %d\n”,argc);
if (argc == 1)
{
fprintf(stderr, ”\nenter properly”);
exit(1); /* exit on failure */
}
for (i = 0; i < argc; ++i)
printf(“argv[%d]: %s\n”, i, argv[i]);
for (i = 1; i < argc; ++i)
sum = sum + atoi (argv[i]); /* ascii to integer conversion */
printf(”sum = %d”, sum);
return 0;
}
void *memset(void *s, int c, size_t n); The memset() function fills the first n bytes
of the memory area pointed to by s with the
constant byte c
void *memmove(void *dest, const void *src, The memmove() function copies n bytes from
size_t n); memory area src to memory area dest. The
memory areas may overlap.
void *memcpy(void *dest, const void *src, size_t The memcpy() function copies n bytes from
n); memory area src to memory area dest. The
memory areas may not overlap.
int memcmp(const void *s1, const void *s2, The memcmp() function compares the first n
size_t n); bytes of the memory areas s1 and s2.
Example: memset()
#include <stdio.h>
#include <string.h>
int main ()
{
char str[50];
strcpy(str,"This is string.h library function");
puts(str);
memset(str,'$',7);
puts(str);
return(0);
}
On running the above code, the first seven characters will be changed to $.
Example: memcpy()
#include <stdio.h>
#include <string.h>
int main ()
{
const char src[50] = "http://www.cranessoftware.com";
char dest[50];
printf("Before memcpydest = %s\n", dest);
memcpy(dest, src, strlen(src)+1);
printf("After memcpydest = %s\n", dest);
return(0);
}
Initially dest would be empty. After memcpy() , the content is copied to that location.
Chapter 3
RECURSION
Recursion is a programming technique that allows the programmer to express operations in terms
of themselves. In C, this takes the form of a function that calls itself. A useful way to think of
recursive functions is to imagine them as a process being performed where one of the
instructions is to "repeat the process".
A function that calls itself is known as a recursive function. And, this technique is known as
recursion.
void recursion()
{
recursion(); /* function calls itself */
}
int main()
{
recursion();
}
The important point to remember while using recursion is that the programmers need to be
careful to define an exit condition from the function, otherwise it will go into an infinite loop.
Recursive functions are very useful to solve many mathematical problems, such as calculating
the factorial of a number, generating Fibonacci series, etc.
Stack is used during recursion. When a function is called, the return address, the values of local
variable and formal parameters will be pushed on to the stack. Then control enters into the
function. Once the return statement is executed, control comes back to the same point from
where it had been called and the returned value is substituted at that point and the control goes
to the statement, which immediately follows the function call. The portion of the stack which
corresponds to a particular function is called as stack frame. The frame pointer (fp) points to the
start of the stack frame and does not move for the duration of the subroutine call.This points to
the base of the stack frame, and the parameters that are passed in to the subroutine remain at a
constant offset relative to the frame pointer. However, as variables are placed on the stack, the
stack pointer (sp) moves.
#include<stdio.h>
int main()
int number,result;
scanf(“%d”,&number);
result = sum(number);
printf(“sum: %d”,result);
if(num!=0)
else
return num;
int main()
{
int i = 15;
printf("Factorial of %d is %d\n", i, factorial(i));
return 0;
}
Fibonacci Series
The following example generates the Fibonacci series for a given number using a recursive
function.
#include <stdio.h>
int fibonaci(int i) {
if(i == 0) {
return 0;
}
if(i == 1) {
return 1;
}
return fibonaci(i-1) + fibonaci(i-2);
}
int main() {
int i;
for (i = 0; i< 10; i++) {
printf("%d\t\n", fibonaci(i));
}
return 0;
}
NOTE : Recursion makes program elegant and cleaner. All algorithms can be defined
recursively which makes it easier to visualize and prove. If the speed of the program is vital
then, you should avoid using recursion. Recursions use more memory and are generally slow.
Instead, you can use looping constructs.
CHAPTER 4
STRUCTURES
We have seen earlier how normal variables can hold one piece of information and how arrays can be
used to represent group data items of the same type. Suppose we want to deal with entities which is a
collection of different data types using a single name then we cannot use arrays. Fortunately, C supports
a constructed data type known as structure. Structures provide for grouping variables of different data
type under a single name.
Syntax
struct tag_name
{
type member1;
type member2; Elements or
--------- members of structure.
};
The first line contains the struct keyword, then the tag_name. member1, member2… are the
members of the structure. The members can be ordinary variables, pointers, arrays or of type
structure again. Members cannot be initialized within a structure declaration.
Once a structure is defined, a variable of its type can be created by using the tag name struct tag_name
variable1, variable2,…; Each of these variables contains all the members specified in the structure
definition.
For example, suppose we want to store data about a student, which consists of student name (a string),
regno (an integer), fees (a float), section (a character) and so on. Then we create a structure variable as
below.
struct student
{
char name[10];
int rollno;
float fees;
char section;
};
Note: The above declaration has not declared any variable it simply describes a format called template to
represent the information as shown below.
We can also write a structure declaration without the tagname as seen below. We can define as many
variables as we want immediately after the closing brace. But we will not be able to define variables of
this type later in our program. Since the tagname identifying this structure type is not available.
struct
{
char name[10];
int rollno;
float fees;
char section;
}s1, s2;
Note
Members of the structure themselves are not variables. They do not occupy any memory until
they are associated with a structure variable.
The structure declaration should be terminated with a semicolon.
Like ordinary variables and arrays, structure variables can also be initialized
For example:
© Cranes Varsity V5:2022-23 114/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
struct student
{
char name[10];
int rollno;
float fees;
char section;
}s1={“princy”,123,4000,’A’};
struct student s2 = {“suman”,124,4000,’B’};
struct student s3 = {“bob”,125,4000,’C’};
Structure members or elements are accessed using the dot (.) operator
For example to access the elements of the above structure the syntax is
Variable.element;
Example:
s1.rollno;
s1.fees;
We can have a pointer pointing to structures; such pointers are known as structure pointers.
#include <stdio.h>
int main(void)
{
struct student
{
char name[12];
int rollno;
float fees;
};
struct student s = {"suman",12,2000};
struct student *ptr;
ptr = &s;
printf("Name: %s\t",ptr->name);
printf("Rollno: %d\t",ptr->rollno);
printf("Fees: %f\n",ptr->fees);
© Cranes Varsity V5:2022-23 115/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
return 0;
}
ptr = &s;
An individual structure element can be accessed using ptr using the -> operator
ptr->name;
The parentheses are required because the dot operator (.) has higher precedence then the
indirection operator (*).
Without the parenthesis the compiler would generate error because ptr(a pointer) is not directly
compatible with the dot operator.
We cannot use relation operators to compare between structures. Individual members have to be
compared using relational and logical operators.
Example
/*Comparison of structure variables*/
#include <stdio.h>
#include <string.h>
struct student
{
char name[12];
int rollno;
float fees;
};
int main( )
{ Varsity
© Cranes V5:2022-23 116/ 188
struct student st1={"suman",12,2000};
struct student st2;
st2 = st1;
/* if(st1 == st2) gives error */
Advanced C & Data Structure & Linux www.cranesvarsity.com
display (st.name,st.rollno,st.fees);
i.e. we are passing the base address of the array name, but the other two arguments rollno and
fees by value. Thus this is a mixed call: a call by reference as well as a call by value.
Passing individual structure elements becomes tedious for structures with more elements. A
better way is pass the entire structure variable to the function at a time.
Example
/* Passing entire structure to function */
#include <stdio.h>
struct student
{
char name[12];
int rollno;
float fees;
© Cranes Varsity V5:2022-23 118/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
};
void display(struct student s)
{
printf("Name : %s\t",s.name);
printf("Rollno: %d\t",s.rollno);
printf("Fees : %f\n",s.fees);
}
int main( )
{
struct student st = { "suman",12,2000};
display (st);
return 0;
}
display(st);
struct student s;
The structure is declared globally, so the function display ( ) can take an argument as student in
the program
Example
/*Passing the address of the structure as argument */
#include <stdio.h>
struct student
{
char name[12];
int rollno;
float fees;
};
void display(struct student *s)
{
printf("Name : %s\t", s->name);
}
Advanced C & Data Structure & Linux www.cranesvarsity.com
Array of structures
In an array of structures all elements of the structure are stored in adjacent memory locations.
Since each element in this array is a structure and since all structure elements are always stored
in adjacent locations we can very well visualize the arrangement of array of structures in memory
as below
Eg: struct student s[10]; //will be stored as shown below.
float fees;
} s[NO_STUDENT];
int i;
/* input student details */
for(i = 0; i< NO_STUDENT; i++)
{
printf("\nEnter name:");
gets(s[i].name);
printf("\nEnterrollno:");
scanf ("%d",&s[i].rollno);
printf("\nEnter fees:");
scanf ("%f",&s[i].fees);
}
/* print the records*/
for(i = 0; i< NO_STUDENT; i++)
{
printf("\n\nName:%s",s[i].name);
printf("\nRollno:%d",s[i].rollno);
printf("\nFees:%f",s[i].fees);
}
return 0;
}
Here we have an array called s which is of the type struct student. This provides space in memory
for 10 structures of the type struct student. The syntax for referring to each element of the array is
similar to the syntax used for ordinary arrays.
};
struct student
{
char name[10];
int rollno;
float fees;
struct date doj;
}s;
The structure date has been made as the member of structure student.
To access the elements of the structure date, this is the part of another structure.
s.doj.dd;
s.doj.mm;
nam
e
rolln
o
fees
doj
dd
mm
yy
Self-referential structures
It is a structure which contains one member which is a pointer of its own type.
Example
struct student
{
char name [12];
int rollno;
float fees;
struct student *next;
};
The above structure contains an element/member which is a pointer to a structure of the same
type (i.e., a pointer to structure of type student), called next. Therefore this is a self-referential
structure. Self referential structures are very useful in applications that involve linked data
structures, such as lists and trees
In a scalar data object, the smallest object that can be addressed directly is usually a byte. In a
structure, you can define data objects which can be as small as 1 bit using bit-fields. A bit-fieldis an
integer variable that consists of a specified number of bits. If you declare several small bit-fields in
succession, the compiler packs them into a single machine word. This permits very compact
storage of small units of information. Of course, you can also manipulate individual bits using the
bitwise operators, but bit-fields offer the advantage of handling bits by name, like any other
structure.
typemember_name :width ;
Example
struct Date
{
unsigned int month : 4; // 1 is January; 12 is December.
unsigned int day : 5; // The day of the month (1 to 31).
unsigned int year : 12;
};
© Cranes Varsity V5:2022-23 123/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
We can initialize an object of type struct Date in the normal way, using an initialization list:
The object birthday occupies the same amount of storage space as a 32-bit int object.
Example :
struct Student
{
int regno;
char name[20];
unsigned int brCode : 3; // Can store values from 0 to 7.
unsigned int sem : 3; // Can store values from 0 to 7.
unsigned int gender : 1;
};
Accessing the bit-field members is same as accessing any other members of struct / union.
Eg., struct Student s;
s.regno = 5;
s.sem = 2;
Union
Unions are derived data-types. Unions like structures, contain members of dissimilar data types.
However all members of the union share the same memory, whereas each member of the
structure is assigned separate memory; that is, all members of a union start at the same address.
Thus you can define a union with many members, but only one member can contain a value at any
given time.
The compiler will allocate enough storage to accommodate the largest element in the union.
The union elements are accessed exactly the same way as that of structure elements using dot(.)
operator and if the union variable is a pointer then arrow(->) operator is used.
We can have nested unions or there can be a nesting on structure and a union or a union and a
structure.
Example
typedef struct
{
unsigned mantissa : 23;
unsigned exponent : 8;
unsigned sign : 1;
}FLOAT_t;
union
{
float f;
FLOAT_t ff;
char c[4];
}u;
int main(void)
{
float a;
int i;
printf("\n ENTER A FLOAT NUMBER :");
scanf("%f",&u.f);
printf("\n sign = %d exponent = %d \
mantissa = %x",u.ff.sign,u.ff.exponent,u.ff.mantissa);
for(i = 0 ; i< 4; i++)
printf(" %x ",u.c[i]);
return 0;
}
Enumerated data types will help us to create one more type of user defined data type where the
identifiers in the enum data type will represent the integer values only. Its general form is
enumtag_name variable1,variable2,..variablen;
Internally the compiler treats the enumeration constants as integers and assign's values
beginning from 0 for first member, with each successive member increasing by 1 and so on.
Example:
enum weekday {MON, TUE, WED, THU, FRI}; /* defining enumerated data-type*/
enum weekday d2; /* creating a variable of that type*/
Example
int main( )
{
enum DAYS_OF_WEEK {SUN,MON, TUE,WED,THU,FRI,SAT} d1, d2;
d1 = TUE;
d2 = WED;
printf(“No of days between d1 & d2 :", d2 - d1);
if(d1 > SUN && d1 < SAT) /*They can be compared */
printf(“Valid Week Day\n");
else
printf("Invlalid Week Day\n");
switch(d1)
{
© Cranes Varsity V5:2022-23 126/ 188
Advanced C & Data Structure & Linux www.cranesvarsity.com
These automatic assignments can be overridden within the definition of the enumeration by
assigning some of the constants with explicit integer values which differ from the default values.
Thus the constants which are not assigned explicit values will automatically be assigned values
which increase by 1 from the last explicit assignment. This may cause two or more enumeration
constants to have the same integer values.
enum weekday {MON=1, TUE, WED, THU, FRI};
The member MON is assigned a value 1, TUE will be represent the value 2, WED represents 3 and
so on. i.e., the other members are automatically assigned values that increase successively by 1.
Note
It is not possible to collect the value to an enum variable using the input statements.
typedef
The Keyword typedef is used to give an alternate name for an existing datatype.
typedef to used to create shorter or simpler type names.
Let's see how typedef works. Suppose you want to use the term BYTE for one-byte numbers. You
simply define BYTE as if it were a char variable and precede the definition by the keyword typedef,
like
typedef unsigned char BYTE;
BYTE x, y[10], * z;
size_t no_elements;
size_t class_strength;
void bubblesort(int arr[] , size_t n);
Type Qualifiers
Type qualifiers are used to tell the compiler that variables(objects) of these types will need special
consideration. There are two type qualifiers in C
const
volatile
The const keyword in a declaration establishes an entity whose value cannot be modified by
assignment or by incrementing or decrementing.
The code
const int nochange = 10; /* qualifier nochange as being constant */
nochange = 12; /* not allowed */
The preceding declaration makes nochange a read–only variable. After it is initialized, it cannot
be changed. If you inadvertently try to modify an entity defined as a const, the compiler will
generate an error/warning. This is an indication to you that something is wrong. Declaring an
entity as const allows the optimizer to do a better job which could make your program run a little
faster.
Since constants can never have a value assigned to them in the executable part of the program,
they must always be initialized. The purpose of volatile is to force an implementation to
suppress optimization that could otherwise occur.
The declaration
const float *pf; /* pf is a pointer to float constant */
establishes that pf points to value, that must remain constant. The value of pf itself can be
changed. For example, it can be set to point at another variable. In contrast, the declaration
As the comment indicates, placing const after the type name and before the * means the pointer
can’t be used to change the pointer-to value. In short, a const anywhere to the left of the *, makes
the data constant and a const to the right of the *, makes the pointer itself constant. One
common use for const is declaring pointers that serve as formal function parameters. For
example, suppose you have a function called display( ) that displays the contents of an array.
To use it, you would pass the name of the array as an actual argument, but the name of an array
is an address, that would enable the function to alter data in the calling function. But the
following prototype prevents this from happening
In a prototype and a function header, the parameter declaration const int array[ ] is the same as
const int * array, so the declaration says that the data to which array points cannot be changed.
The ANSI C library follows this practice. If a pointer is used only to give a function access to
values, the pointer is declared as a pointer to a const-qualifier type. If the pointer is used to alter
data in the calling function, the const keyword isn’t used. For example, the ANSI C declaration
for strcat( ) is this:
©Cranes V5:2022-23 129/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Volatile
Volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the
value of the variable may change at any time—without any action being taken by the code the
compiler finds nearby. The implications of this are quite serious. However, before we examine
them, let’s take a look at the syntax.
Syntax
To declare a variable volatile, include the keyword volatile before or after the data type in the
variable definition. For instance both of these declarations will declare foo to be a volatile integer:
volatile int foo;
int volatile foo;
Now, it turns out that pointers to volatile variables are very common. Both of these declarations
declare foo to be a pointer to a volatile integer:
volatile int * foo;
int volatile * foo;
Question 1
int main
{
int x[10]={0,1,2,3,4,5,6,7,8,9};
int *ptr1,*ptr2;
ptr1=&x[0];
ptr2=&x[5];
printf("%p\n",(ptr1+ptr2));
return 0;
}
Output :
Explanation :
Question - 2
int main()
{
int color=2;
switch(color)
{
case 0: printf("Black");
case 1: printf("Blue");
case 2: printf("Green");
case 3: printf("Aqua");
default: printf("Other");
}
return 0;
}
Output:
Explanation:
Question - 3
int main()
{
char str[10]="Hello";
printf("%d,%d\n",strlen(str),sizeof(str));
return 0;
}
Output:
Explanation:
Question - 4
int main()
{
char *str="Hello";
printf("%d,%d\n",strlen(str),sizeof(str));
return 0;
}
Output:
Explanation:
©Cranes V5:2022-23 132/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Question - 5
int main()
{
struct number num;
test(num);
printf("%d\n",num.x);
return 0;
}
Output :
Explanation:
Question - 6
int main()
{
if(0);
printf("Hello");
©Cranes V5:2022-23 133/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
printf("Hi");
return 0;
}
Output:
Explanation:
Question - 7
int main()
{
int x,y;
int *ptr;
x=100;
ptr=&x;
y=*ptr;
printf("%d\n",y);
return 0;
}
Output:
Explanation:
Question - 8
int main()
{
int val=1;
do{
val++;
++val;
}while(val++>25);
printf("%d\n",val);
return 0;
}
Output :
Explanation :
Question - 9
int main()
{
char *str="A%%B";
printf("A%%B ");
printf("%s\n",str);
return 0;
}
Output :
Explanation :
©Cranes V5:2022-23 135/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Question - 10
int main()
{
printf("%d,%d,%d\n",sizeof(char*),
sizeof(int*),sizeof(float*));;
return 0;
}
Output :
Explanation :
Question - 11
#include <stdio.h>
int main()
{
int x = 400, y, z;
if (x >= 500)
y = 400;
z = 300;
printf("%d %d\n", y, z);
return 0;
}
©Cranes V5:2022-23 136/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Output :
Explanation:
Question - 12
#include <stdio.h>
int main()
{
int p = 800, q, r;
if (p >= 700)
q = 600;
r = 500;
return 0;
}
Output :
Explanation :
question - 13
#include <stdio.h>
int main()
{
int a = 30, b = 40;
if (a == b);
return 0;
}
Output :
Explanation :
Question - 14
#include <stdio.h>
int main()
{
int e = 4;
float f = 4.0;
if (e == f) {
©Cranes V5:2022-23 138/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 15
#include <stdio.h>
int main()
{
int p = 4, q, r;
q = p = 15;
r = p < 15;
return 0;
}
Output :
Explanation:
Question -16
#include <stdio.h>
int main()
{
int i = 65;
char j = 'A';
if (i == j) {
else {
printf("This place is not beautiful\n");
}
return 0;
}
Output :
Explanation :
Question - 17
#include <stdio.h>
int main()
{
float p = 13.25, q = 14.5;
if (p = q) {
printf("Hello\n");
}
return 0;
}
Output :
Explanation :
Question - 19
#include <stdio.h>
int main()
{
int k = 14, l = 12;
if (l >= k)
{
©Cranes V5:2022-23 141/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
l = k;
k = l;
printf("%d, %d\n", k, l);
}
return 0;
}
Output :
Explanation :
Question - 20
#include <stdio.h>
int main()
{
if ('Y'<'y') {
printf("ASCII value of Y is smaller than that of y\n");
}
else {
printf("ASCII value of y is smaller than that of Y\n");
}
return 0;
}
Output :
Explanation :
Question - 21
#include <stdio.h>
int main()
{
int j = 16, k = 25;
if (j % 2 == k % 5) {
printf("Solve\n");
}
return 0;
}
Output :
Explanation:
Question -22
#include <stdio.h>
int main()
{
int a = 50, b = 100;
if (a == b / 2) {
printf("Hello");
}
else {
©Cranes V5:2022-23 143/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
printf("Hi");
}
return 0;
}
Output :
Explanation :
Question - 24
What will be the output of the below program, if input values are 1 and 2?
#include <stdio.h>
int main()
{
int r, s, c;
c = scanf("%d%d", &r, &s);
if (r + s - c) {
printf("This is a game");
}
else {
printf("you have to play it");
}
return 0;
}
Output:
Explanation:
Question - 25
#include <stdio.h>
int main()
{
unsigned char a=0xAA;
unsigned char b=0;
b= (a&0x0F);
printf("b= %02X\n",b);
return 0;
}
Output:
Explanation :
Question - 26
#include <stdio.h>
int main()
{
unsigned char a=0xAA;
return 0;
}
Output :
Explanation :
Question - 28
#include <stdio.h>
int main()
{
unsigned char a=0xAA;
printf("a= %02X\n",a);
if(a | 0x01)
printf("true\n");
else
printf("false\n");
return 0;
}
Output :
Explanation :
Question - 29
#include <stdio.h>
int main()
{
©Cranes V5:2022-23 147/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
a= a|0x01;
a= a|0x02;
a= a|0x04;
a= a|0x08;
printf("a= %02X\n",a);
return 0;
}
Output :
Explanation:
Question - 30
#include <stdio.h>
int main()
{
unsigned char a=0x00;
a = ~a;
printf("a= %02X\n",a);
return 0;
}
Output :
©Cranes V5:2022-23 148/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 31
#include <stdio.h>
int main()
{
unsigned char a=0xFA;
a= (a>>4) | (a<<4);
printf("a = %02X\n",a);
return 0;
}
Output :
Explanation :
Question - 32
#include <stdio.h>
int main()
{
unsigned char a=0xFA;
char loop;
printf("\n");
return 0;
}
Output:
Explanation :
Question - 33
#include <stdio.h>
int main()
©Cranes V5:2022-23 150/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
{
unsigned char a=0xAA;
unsigned char b=0x55;
printf("(a^b): %02X\n",(a^b));
return 0;
}
Output :
Explanation :
Question - 34
#include <stdio.h>
int main()
{
unsigned char a=0xAA;
a= (a^0x55);
a= (a^0x55);
printf("a= %02X\n",a);
return 0;
}
Output :
©Cranes V5:2022-23 151/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 35
#include <stdio.h>
int main()
{
printf("%s\n",4+"Hello world");
printf("%s\n","Hello world"+4);
return 0;
}
Output :
Explanation :
Question - 36
#include <stdio.h>
©Cranes V5:2022-23 152/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
#include <string.h>
int main()
{
char str[]="Hello";
str[strlen(str)+1]='#';
printf("str= %s\n",str);
return 0;
}
Output :
Explanation :
Question - 37
#include <stdio.h>
int main()
{
char str[]={0x41,0x42,0x43,0x20,0x44,0x00};
printf("str= %s\n",str);
return 0;
}
Output :
©Cranes V5:2022-23 153/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 38
#include <stdio.h>
int main()
{
char str[]="Hello";
char *ptr=str;
while(*ptr!='\0')
printf("%c",++*ptr++);
printf("\n");
return 0;
}
Output :
Explanation :
Question - 39
#include <stdio.h>
int main()
{
char str[5]={0},loop=0;
while(loop<5)
printf("%02X ",str[loop++]);
printf("\n");
return 0;
}
Output :
Explanation :
Question - 40
#include <stdio.h>
#include <string.h>
int main()
{
char *s1, *s2;
s1= "abcdef" ;
s2= "abcdeg" ;
printf(" %d ", strcmp (s1,s2));
printf(", ");
s1="abcdef";
s2="abcdef";
printf(" %d ", strcmp (s1,s2));
printf(", ");
s1="abcdef";
s2="abcdee";
printf(" %d ", strcmp (s1,s2));
printf(", ");
return 0;
}
Output :
Explanation :
Question - 41
Which function is used to find the last occurrence of character in C?
Answer :
Explanation :
Question - 42
#include <stdio.h>
#include <string.h>
int main()
{
char document[] = "I love IncludeHelp.com This is an amazing website ";
char *s, *p ;
char character2 = 'x', character1 = 't';
s = strrchr(document, character1 );
p = strrchr(document, character2 );
if (s)
printf("The position of '%c' is %d\n", character1, s-document);
else
printf("The character was not found in given document\n");
if (p)
printf("The position of '%c' is %d\n", character2 , p-document);
else
printf("The character was not found in given document\n");
return 0;
}
Output:
Explanation :
Question – 42
#include <stdio.h>
#include <string.h>
int main()
{
char a[] = "%d\n";
a[5] = 'i';
printf(a, 85);
return 0;
}
Output :
Explanation :
Question - 43
In C, what will be the output of following program?
#include <stdio.h>
#include <string.h>
int main()
{
char a[] = "Cranes";
char *b = "Cranes";
return 0;
}
Output :
Explanation :
Question - 44
Is the following declaration of structure 'tag' is correct?
int main()
{
struct tag{
int a;
float b;
};
//other statement
return 0;
}
Explanation :
Question - 45
©Cranes V5:2022-23 160/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
int main()
{
struct tag{
int a=0;
float b=0.0f;
};
//other statement
return 0;
}
Explanation :
Question - 46
What will be the output of following program?
#include <stdio.h>
int main()
{
struct tag{
int a;
float b;
};
Output :
Explanation :
Question - 47
Is the following structure variable declaration is correct? If yes, what will be the output of
following program?
#include <stdio.h>
int main()
{
struct person{
char *name;
int age;
};
printf("%s, %d\n",p.name,p.age);
return 0;
}
Output :
©Cranes V5:2022-23 162/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 48
What will be the output of this program?
#include <stdio.h>
int main()
{
struct person{
char name[30];
int age;
};
//edit values
p.name="Vanka";
p.age=27;
©Cranes V5:2022-23 163/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
printf("%s, %d\n",p.name,p.age);
return 0;
}
Output :
Explanation :
Question - 49
#include <stdio.h>
int main()
{
char ch='A';
printf("%d",ch);
return 0;
}
Output :
©Cranes V5:2022-23 164/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 50
#include <stdio.h>
int main()
{
char ch='A';
printf("%c-%d",ch+32,ch+32);
return 0;
}
Output :
Explanation :
Question - 51
#include <stdio.h>
int main()
{
int a= 'a'-'A';
printf("%d[%c]",a,a);
return 0;
}
Output :
Explanation :
Question - 52
#include <stdio.h>
©Cranes V5:2022-23 166/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
int main()
{
char ch='g';
printf("%c",ch-('a'-'A'));
return 0;
}
Output :
Explanation :
Question - 53
#include <stdio.h>
int main()
{
printf("%d",('1'-48));
return 0;
}
Output :
Explanation :
Question - 54
Select the correct floating point data type in C programming?
Output :
Explanation :
Question - 55
#include<stdio.h>
int main()
{
float a;
double b;
int i;
return 0;
}
Output :
Question - 56
How can we store 5.95 as a float?
use 5.95f
use 5.95
use 5.95ld
none of the above.
©Cranes V5:2022-23 169/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Output :
Explanation :
Question - 57
which of the following is range of float?
-3.4E+37 to +3.4E+37
-3.5E+37 to +3.5E+37
-3.5E+38 to +3.5E+38
-3.4E+38 to +3.4E+38
Output :
Explanation :
Question - 58
How can we perform module operation (%) between two floating point variables 6.78 and
3.26?
For floating point modulo is not define hence we cannot find modulo of floating variables.
6.78 % 3.26 is the result of modulus operation.
int(6.78)%int(3.26) is the result of modulus operation.
fmod(6.78,3.26) is the result of modulus operation.
Output :
Explanation :
Question - 59
using this function we can find the modulus of any two floating points variable. This
function is available in header file <math.h>.
#include <stdio.h>
#include <math.h>
int main()
{
float a,b;
printf("Enter 1st float value : ");
scanf("%f",&a);
printf("Enter 2nd float value : ");
scanf("%f",&b);
printf("Modulus of %f and %f is %f",a,b,fmod(a,b));
return 0;
}
Enter 1st float value : 6.78
Enter 2nd float value : 3.26
Output :
Question - 60
How can we round off any float variable f into a int value i?
i=(int)(f+0.5)
i=int(f+0.5)
i=(int)x+0.5
Output :
Explanation :
©Cranes V5:2022-23 172/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Question - 61
#include<stdio.h>
int main()
{
float f;
return 0;
}
Enter float value : 145.62
Output :
#include <stdio.h>
int main()
{
int i;
for(i=1; i<=10;i++)
printf("i=%d\n",i);
return 0;
}
Output :
Explanation :
Question -62
#include <stdio.h>
int main()
{
int i;
for(i=1; i<=10;i++);
printf("i=%d\n",i);
return 0;
}
Output :
Explanation :
Question - 63
#include <stdio.h>
int main()
{
int i;
for(i=65; i<(65+26);i++)
printf("%c ",i);
return 0;
}
Output :
©Cranes V5:2022-23 175/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Explanation :
Question - 64
#include <stdio.h>
int main()
{
int i;
for(i=1; -1; i++)
printf("%c ",i);
return 0;
}
Output :
Explanation :
Question - 65
What will happen if we assigned a value to an array element whose size of subscript is
greater than the size of array in C programming?
Explanation :
Question - 66
#include <stdio.h>
©Cranes V5:2022-23 177/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
int main()
{
int arr[10];
arr[15]=200;
printf("%d",arr[15]);
return 0;
}
Output:
Explanation :
Question - 67
In C, if user passes array as an argument then, what actually get passes?
Output :
Explanation:
©Cranes V5:2022-23 178/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
Question - 68
#include <stdio.h>
int main()
{
int arr[2][2]={ 1, 2, 3, 4 };
printf("%u\n", arr);
return 0;
}
Output :
Question - 69
What will be the output of the following program in turbo C?
#include <stdio.h>
int main()
{
int arr[8];
int n=0;
while(n<8)
{
arr[n]=++n;
}
for(n=0; n<8; n++)
{
©Cranes V5:2022-23 179/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
printf("%d, ",arr[n]);
}
return 0;
}
a. 1, 2, 3, 4, 5, 6, 7,
b. 1, 2, 3, 4, 5, 6, 7, 8,
c. 0, 1, 2, 3, 4, 5, 6, 7,
d. Garbage value, 1, 2, 3, 4, 5, 6, 7,
Output:
Explanation :
Question - 70
What will be the output of the following program in C?
#include <stdio.h>
int main()
{
char arr[]={ 'A', 'B', 'c', 'd', 'E', 'f' };
int size=sizeof(arr)/sizeof(arr[0]);
printf("%d\n", size);
return 0;
}
a.0
b.6
©Cranes V5:2022-23 180/8
Varsity 9
Advanced C & Data Structure & Linux www.cranesvarsity.com
c.12
d.1
Output :
Explanation :
Question - 71
What will be the output of the following code?
#include <stdio.h>
int main()
{
int a[2][2] = { 1, 2, 3, 4 };
int *p;
p= &a[1][1];
printf("%d\n",*p);
return 0;
}
a. 1
b. 2
c. 3
d. 4
Output :
Explanation :
cal
Unix-like systems provide a handful of tools for dealing with dates and times. Cal is one such
command that enables you to view calendar in the command line.
cat
Cat is one of the most used commands in Linux. Intended for concatenating text, it is mainly
used for displaying the contents of text files.
cd
The cd command is used to navigate between directories in Linux. It stands for ‘change
directory’.
chgrp
chgrp command is used for changing the group of a file or directory in Linux.
chmod
Chmod stands for change mode. This command is used for changing the mode of access, i.e.
the file permissions in Linux.
chown
The chown command in Linux enables you to change the user and group ownership of a file
or directory.
cp
One of the commands that you must know in Linux is cp. It’s often called the copy command
in Linux and it is actually short for copy and it does exactly as it name suggests: it copies.
cron
The crontab is used to automate all types of tasks on Linux systems. This is an especially
important skill for aspiring system administrators to learn.
curl
CURL is a tool for data transfer. The most popular use case for curl command is to download
files from the web in Linux terminal.
cut
The cut command is the canonical tool to remove “columns” from a text file. In this context,
a “column” can be defined as a range of characters or bytes identified by their physical
position on the line, or a range of fields delimited by a separator.
date
The date command gives you the current date and time of you Linux system. But it can do a
lot more than that.
dd
The dd command in Linux is a powerful utility for copying and converting files. Its most
popular use case is creating live Linux USB using Linux command line.
df
The df command is used for checking disk space in Linux.
diff
When you need to compare two files containing similar text in Linux, using the diff
command can make your task much easier. The command compares two files to suggest
changes that would make the files identical. Great for finding that extra curly brace that
broke your newly updated code.
dig
Dig command in Linux is commonly used for retrieving the DNS information of a remote
server.
dirname
The dirname command in Linux prints a file path with its final component removed. This
basically gives you the directory path from the file path.
du
Knowing the size of a file is easy in Linux but it won't show the size of directories. The du
command is used for checking the size of directory.
echo
The echo command is perhaps one of the first few commands you see when you start
learning Linux commands or bash shell scripting. It is a simple command that simply prints
its arguments on the display.
file
The file command gives you various information about a file in Linux. This includes the type
of file, MIME type etc.
find
One of the frequent used commands. The find command can be used to looks for files based
on their name, type, modification time and more. Combine it with the likes of exec or xargs
command and you have a powerful tool at your hand for searching and modifying files.
grep
Find command works on file name. The grep command is used to find patterns inside file
content.
groupadd
The groupadd command in Linux creates new groups
groupdel
The groupdel command is perhaps the simplest command in Linux with virtually no options.
It is used for deleting an existing group.
groupmod
You can modify group properties like group name and group ID with the groupmod
command in Linux.
groups
This command helps you find the groups a Linux user belongs to in Linux command line.
head
You can use the head command to print a specified number of lines from the beginning of
the file.
history
Everything you type in the terminal is stored in the shell history. This aspect can be
displayed and controlled through the history command.
id
Every user in Linux has a unique, numeric user ID and a default group with a unique numeric
group ID. The id command prints this information.
jobs
The jobs command in Linux allows the user to directly interact with processes in the current
shell.
less
Less is an awesome Linux command utility for viewing text files.
ln
The ln command allows you to create both soft and hard links in Linux.
locate
The locate command allows you to preform a super quick search for files.
ls
The ls command in Linux is one of the most used commands. It is used for listing the
contents of a directory.
lsof
You can list opened files by a user or a process by using the lsof command in Linux.
mkdir
The mkdir command allows you to make new directories (folders in common term) in Linux.
more
The more command in Linux opens a text file in page views. It's predecessor to the less
command and not used a lot these days.
mv
mv command in Linux is used for moving and renaming files and directories.
nslookup
nslookup is one of the popular networking commands in Linux used for querying the
Domain Name System (DNS) records.
Passwd
The passwd command in Linux allows you to change user password, lock accounts, expire
passwords and more.
paste
The paste command merges several input files to produce a new delimited text file from
them.
ping
Ping is mainly used to check if a remote host is reachable or not.
ps
The ps command in Linux is used for getting information about running processes.
pwd
It will print the present working directory.
read
With read command, you can make your bash script interactive by accepting user inputs.
reboot
Reboot performs the actions of the halt command (explained below), requiring that all
processing stop. Then instead of triggering the ACPI signal, your system is restarted.
rename
Rename command can be used to rename multiple files in Linux at once.
rm
The rm command is used for removing files and directories in Linux.
rsync
Rsync (Remote Sync) is a synchronization tool for copying files and directories in a system or
between systems. Its most popular use case includes copying files between remote systems.
sleep
Linux sleep command is one of the simplest commands out there. As you can guess from the
name, its only function is to sleep. In other words, it introduces a delay for a specified time.
stat
You can get file permissions, size, mtime, ctime, atime, ownership and several other file
attribute information using the stat command in Linux.
tail
The tail command prints the last ten lines of the input files. The tail command is also used
for reading log files in real time.
tar
Tar is one of the most common tool used for archiving files in Linux.
time
The time command in Linux measures how long a particular command or script runs.
top
The top command provides a quick look at system resources and processes.
touch
Touch command in Linux is used for changing file timestamps however one of the most
common usages of touch command includes creating a new empty file.
tr
The tr command in Linux is used to perform simple but useful translations of one set of
characters into another.
ulimit
Ulimit is a built-in shell command designed to display, allocate, and limit resources.
uname
You can get Linux kernel version and some other system information with the uname
command in Linux.
uniq
The uniq command in Linux and Unix is used for removing duplicate lines from a file.
useradd
The useradd command lets a superuser create a new user account on Linux.
usermod
The usermod command in Linux allows you to modify a user account in various ways.
vim
Vim is one of the most popular text editor in the Linux command line.
wc
The wc command displays statistical information about a file such as the number of lines,
words, characters.
which
which command is an extremely useful command for locating executable files located
anywhere in the Linux system.
who
The who command in Linux lists all logged-in users on the system.
References/Resources:
Linux Handbook: Abhishek Prakash