Learn C
Learn C
int main () {
};
Chapter 1
Variables
A variable is a data structure that allows storing different kinds of values . variables are the
names you give to a specific computer's memory location .
Picture this like a little box where you want to store something and you label that box in order
to know what it contains.
As for a real world example, imagine you have a box where you want to store books its
genre and you also want to know how many are in there.
you’d possibly follow this approach you’d get a box and stick a label on it with the following
writing .
books of fiction
20
When you take that box for whatever purpose you know it contains 20 books belonging to
the fiction genre.
BooksOfFictionBoxNumber= 20;
Let’s go through this example and make it work following a C syntax program :
1. Type
2. Variable name
3. Value
1. The type relates to the kind of value you want to store:In the above example you use
the value 20 to indicate the number of books. this being provided , it can be deduced
that numbers are a value type.There are also many more types that will be later
explained throughout the chapter.
2. It’s just a way to give a name that describes best what the value is related to. In the
books case you use the name BooksOfFictionBoxNumber to denote that you’re going
to store the number of books of that genre.
3. The value itself is followed by a semicolon . In this case you assign the value 20.
Chapter 1
1. Variable Creation
The process I detailed before resumes how you can create variables. Nevertheless I’d like to
clarify two concepts that You’ll see quite often throughout the book:
a) Direct initialization : the assignment and declaration take place at the same
line of code.
1)
2)
3)
3. Variable Reassignment
You can redefine a variable later in your program . You can assign a different value any
time. You’ll learn more about this topic in the Operators chapter.
For example:
int anInt=2;
int anotherInt= 1;
// to start using the variables you must not include the int type
anymore. the program already knows what kind of variable it is
dealing with.
nevertheless notice that both variables belong to the same type
(int).
anInt = anotherInt
anInt equals 1 ;
anotherInt equals 2;
4.Const variables
In the previous program it was explained how you can declare, define (also initialize and
assign ) and redefine (reassign) variables.
Const variables behave a little differently in terms of declaration , definition and
reassignment.
a) To declare a const variable you must initialize it straight away.So you use the one
step definition :
b) You can't reassign any values later in the program . it yields an error when you run
the code..
number = 2;
To conclude , what do you need a const variable for ? when you want to store values that
you dont later want to change along the program.
printf(“%d”,BooksOfFictionBoxNumber );
return 0;
};
5. Variable Types
Previously I used the int type to give an example for creating a variable.
The list below shows the remaining data types.Declaration and definition
Data Types Examples :
In the table below you’ll see included some of the basic types with some modifications , the
value range (numbers that can be stored ) and the printf format specifier,which I’ll explain in
brevity). I’ll just give an explanation of the types not discussed beforehand.
If you pay attention there are some new keywords before the basic types:
a) short
b) long
c) unsigned/signed
These are called modifiers just like the const keyword but they affect the value range of the
basic types when used in combination.
1) Short reduces the range capacity in a half. So when you declare a variable
using the short modifier it takes half the storage capacity that a normal int:
A normal int takes 4 bytes of memory storage capacity.A short int takes 2 bytes of
memory storage capacity.
b) Long doubles the int memory storage capacity : An int data type takes 4 bytes of
memory storage.A long int takes 8.
1) signed means that the value range can include negative and positive numbers
including 0.
2) unsigned means that the value range can only include positive values including 0.
types by default are signed .They do not affect the memory storage capacity but it changes
the value range these variables can contain.
3. Format Specifiers
Format specifiers are placeholders that are replaced by the argument values supplied in the
printf() function between others.
In the format string section you add the format specifiers and in the arguments section you
add the values you want to print .
Remember that this function prints the arguments provided on the screen.
Each placeholder points to the corresponding argument in the exact same order they’re
included.
1) Format Specifier List
Example :
#include <stdio.h>
int main () {
printf(“%ld”, lampsQuantity);
return 0;
4. POINTER VARIABLES
Pointers are a special kind of data type that lets you store another variable’s memory
address.
every variable gets assigned an address in the computer’s memory when you declare it .
You previously saw that an int variable will take 4 bytes of memory when you declare it. you
can get its memory address through the use of pointers . an address is the place where your
variable is stored.
1) The Declaration Syntax is as follows :
type * pointer_name ;
I) int *pointerToPencils ;
To access the value stored in the variable Pencils through the pointerToPencils variable :
Example:
*pointerToPencils
4. CONST POINTERS
snippet:
*bookP= 15; // error you cant modify the value but you can assign
the pointer to point to a different variable.
5. Pointers To Const
Snippet :
1. C structures
The structure in C is a user-defined data type that can be used to group items of possibly
different types into a single type. The struct keyword is used to define it. The items in the
structure are called its members(properties) and they can be of any valid data type.
1) C Structure Declaration
We can use the struct keyword to declare the structure in C using the following syntax:
Syntax
struct structure_name {
data_type member_name1;
data_type member_name1;
....
....
};
2) C Structure Definition
To use structure in our program, we have to define its instance. We can do that by creating
variables of the structure type. We can define structure variables using two methods:
Structure members cannot be initialized with the declaration. For example, the following C
program fails in the compilation.
struct Point
{
int x = 0; // COMPILER ERROR: cannot initialize members
here
int y = 0; // COMPILER ERROR: cannot initialize members
here
};
The reason for the above error is simple. When a datatype is declared, no memory is
allocated for it. Memory is allocated only when variables are created.
We can initialize structure members in 3 ways which are as follows:
Syntax
structure_name.member1;
strcuture_name.member2;
In the case where we have a pointer to the structure, we can also use the arrow operator to
access the members.
Example of Structure in C
// Driver code
int main()
{
// variable declaration after structure template
// initialization with initializer list and designated
// initializer list
struct str1 var1 = { 1, 'A', 1.00, "GeeksforGeeks" },var2;
struct str2 var3 = { .ff = 5.00, .ii = 5, .cc = 'a' };
return 0;
}
Output
Struct 1:
i = 1, c = A, f = 1.000000, s = GeeksforGeeks
Struct 2:
i = 1, c = A, f = 1.000000, s = GeeksforGeeks
Struct 3
i = 5, c = a, f = 5.000000
The typedef keyword is used to define an alias for the already existing datatype. In
structures, we have to use the struct keyword along with the structure name to define the
variables. Sometimes, this increases the length and complexity of the code. We can use the
typedef to define some new shorter name for the structure.
// defining structure
struct str1 {
int a;
};
int main()
{
// creating structure variables using new names
str1 var1 = { 20 };
str2 var2 = { 314 };
printf("var1.a = %d\n", var1.a);
printf("var2.x = %d", var2.x);
return 0;
}
Output
var1.a = 20
var2.x = 314
5) Nested Structures
C language allows us to insert one structure into another as a member. This process is
called nesting and such structures are called nested structures. There are two ways in which
we can nest one structure into another:
In this method, the structure being nested is also declared inside the parent structure.
Example
struct parent {
int member1;
struct member_str member2 {
int member_str1;
char member_str2;
...
}
...
}
In this method, two structures are declared separately and then the member structure is
nested inside the parent structure.
Example
struct member_str {
int member_str1;
char member_str2;
...
}
struct parent {
int member1;
struct member_str member2;
...
}
One thing to note here is that the declaration of the structure should always be present
before its definition as a structure member. For example, the declaration below is invalid as
the struct mem is not defined when it is declared inside the parent structure.
struct parent {
struct mem a;
};
struct mem {
int var;
};
We can access nested Members by using the same ( . ) dot operator two times as shown:
str_parent.str_child.member;
Example:
// driver code
int main()
{
struct parent var1 = { 25, 195, 'A' };
return 0;
}
Output
var1.a = 25
var1.b.x = 195
var1.b.c = A
c. Structure Pointer in C
We can define a pointer that points to the structure like any other variable. Such pointers are
generally called Structure Pointers. We can access the members of the structure pointed by
the structure pointer using the ( -> ) arrow operator.
// structure declaration
struct Point {
int x, y;
};
int main()
{
struct Point str = { 1, 2 };
// p2 is a pointer to structure p1
struct Point* ptr = &str;
return 0;
}
Output
1 2
d. Self-Referential Structures
The self-referential structures in C are those structures that contain references to the same
type as themselves i.e. they contain a member of the type pointer pointing to the same
structure type.
struct structure_name {
data_type member1;
data_type member2;
struct structure_name* str;
}
// C program to illustrate the self referential structures
#include <stdio.h>
// structure template
typedef struct str {
int mem1;
int mem2;
struct str* next;
}str;
// driver code
int main()
{
str var1 = { 1, 2, NULL };
str var2 = { 10, 20, NULL };
// pointer to var1
str *ptr1 = &var1;
return 0;
}
Output
var2.mem1: 10
var2.mem2: 20
Such kinds of structures are used in different data structures such as to define the nodes of
linked lists, trees, etc.
}
e. Bit Fields
Bit Fields are used to specify the length of the structure members in bits. When we know the
maximum length of the member, we can use bit fields to specify the size and reduce memory
consumption.
struct structure_name {
data_type member_name: width_of_bit-field;
};
// driver code
int main()
{
printf("Size of Str1: %d\nSize of Str2: %d",
sizeof(struct str1), sizeof(struct str2));
return 0;
}
Output
Size of Str1: 8
Size of Str2: 4
2. Unions
The Union is a user-defined data type in C language that can contain elements of the
different data types just like structure. But unlike structures, all the members in the C union
are stored in the same memory location. Due to this, only one member can store data at the
given instance.
Syntax of Union in C
The syntax of the union in C can be divided into three steps which are as follows:
In this part, we only declare the template of the union, i.e., we only declare the members’
names and data types along with the name of the union. No memory is allocated to the
union in the declaration.
union union_name {
datatype member1;
datatype member2;
...
};
Keep in mind that we have to always end the union declaration with a semi-colon.
We need to define a variable of the union type to start using union members. There are two
methods using which we can define a union variable.
union union_name {
datatype member1;
datatype member2;
...
We can access the members of a union by using the ( . ) dot operator just like structures.
var1.member1;
where var1 is the union variable and member1 is the member of the union.
The above method of accessing the members of the union also works for the nested unions.
var1.member1.memberA;
Here,
4) Initialization of Union in C
The initialization of a union is the initialization of its members by simply assigning the value
to it.
var1.member1 = some_value;
One important thing to note here is that only one member can contain some value at a
given instance of time.
Example of Union
// driver code
int main()
{
return 0;
}
Output
The value stored in member1 = 15
The size of the union will always be equal to the size of the largest member of the array.
All the less-sized elements can store the data in the same space without any overflow.
union test2 {
int x;
char y;
} Test2;
union test3 {
int arr[10];
char y;
} Test3;
// driver code
int main()
{
// finding size using sizeof() operator
int size1 = sizeof(Test1);
int size2 = sizeof(Test2);
int size3 = sizeof(Test3);
Output
Sizeof test1: 4
Sizeof test2: 4
Sizeof test3: 40
is a user defined data type in C. It is mainly used to assign names to integral constants, the
names make a program easy to read and maintain.
enum State {Working = 1, Failed = 0};
The keyword ‘enum’ is used to declare new enumeration types in C and C++. Following is an
example of enum declaration.
a)
b)
#include<stdio.h>
enum week{Mon, Tue, Wed, Thur, Fri, Sat, Sun};
int main()
{
enum week day;
day = Wed;
printf("%d",day);
return 0;
}
Output:
2
In the above example, we declared “day” as the variable and the
value of “Wed” is allocated to day, which is 2. So as a result, 2 is
printed.
int main()
{
int i;
for (i=Jan; i<=Dec; i++){
printf("%d ", i);}
return 0;
}
Output:
0 1 2 3 4 5 6 7 8 9 10 11
In this example, the for loop will run from i = 0 to i = 11, as initially the value of i is Jan which
is 0 and the value of Dec is 11.
1) Two enum names can have the same value. For example, in the following C program both
‘Failed’ and ‘Freezed’ have same value 0.
#include <stdio.h>
enum State {Working = 1, Failed = 0, Freezed = 0};
int main()
{
printf("%d, %d, %d", Working, Failed, Freezed);
return 0;}
chapter 3
1. SCOPE
The scope of a variable in C is the block or the region in the program where a variable is
declared, defined, and used. Outside this region, we cannot access the variable and it is
treated as an undeclared identifier.
a) Global Scope
b) Local Scope
a) Global Scope in C
1. The global scope refers to the region outside any block or function.
2. The variables declared in the global scope are called global variables.
3. Global variables are visible in every part of the program.
4. Global is also called File Scope as the scope of an identifier starts at the
beginning of the file and ends at the end of the file.
Example :
int global = 5;
void display()
{
printf("%d\n", global);
}
// main function
int main()
{
printf("Before change within main: ");
display();
Output
Before change within main: 5
After change within main: 10
Global variables have external linkage by default. It means that the variables declared in the
global scope can be accessed in another C source file. We have to use the extern keyword
for that purpose.
// filename: file1.c
int a;
int main(void)
{
a = 2;
}
// filename: file2.c
// When this file is linked with file1.c, functions
// of this file can access a
extern int a;
int myfun()
{
printf("%d", a);
}
Output
Note: To restrict access to the current file only, global variables can be marked as static.
b) Local Scope in C
The local scope refers to the region inside a block or a function. It is the space enclosed
between the { } braces.
The variables declared within the local scope are called local variables.
Local variables are visible in the block they are declared in and other blocks nested inside
that block.
// Driver Code
int main()
{
{
int x = 10, y = 20;
{
// The outer block contains
// declaration of x and
// y, so following statement
// is valid and prints
// 10 and 20
Output
x = 10, y = 20
x = 11, y = 41
x = 11, y = 20
Q1. What if the inner block itself has one variable with the same name?
If an inner block declares a variable with the same name as the variable declared by the
outer block, then the visibility of the outer block variable ends at the point of the declaration
by inner block.
● The lifetime of the variable is the time between it is allocated memory and it is
deleted from the memory.
chapter 3
1) Functions
2) Loops
1) Functions
A sequence of program instructions that performs a specific task, packaged as a unit.
Just like variables you need to declare and define them but there’s also a further step which
is named calling.
a) Declaration
In a function declaration, we must provide the function name, its return type, and the number
and type of its parameters. A function declaration tells the compiler that there is a function
with the given name defined somewhere else in the program.
The function definition consists of actual statements which are executed when the function is
called (i.e. when the program control comes to the function).
A C function is generally defined and declared in a single step because it always starts with
the function declaration so we do not need to declare it explicitly. The below example serves
as both a function definition and a declaration.
c) Function Call
A function call is a statement that instructs the compiler to execute the function. We use the
function name and parameters in the function call.
In the below example, the first sum function is called and 10,30 are passed to the sum
function. After the function call sum of a and b is returned and control is also returned back
to the main function of the program.
Function call is necessary to bring the program control to the function definition. If not
called, the function statements will not be executed.
// Calling sum function and
// storing its value in add variable
int add = sum(10, 30);
Function Arguments (also known as Function Parameters) are the data that is passed to a
function. This is shown in the previous example . The sum function is passed two int
arguments to perform the calculation.
Example:
int function_name(int var1, int var2);
Function return type tells what type of value is returned after all functions are executed.
When we don’t want to return a value, we can use the void data type.
Example:
int func (parameter_1,parameter_2);
The above function will return an integer value after running statements inside the function.
Note: Only one value can be returned from a C function. To return multiple values, we have
to use pointers or structures.
In C programming language, functions can be called either with or without arguments and
might return values. They may or might not return values to the calling functions.
Working of the C function can be broken into the following steps as mentioned below:
2. Defining a function:
3. Calling the function: Calling the function is a step where we call the function by
passing the arguments in the function.
4. Executing the function: Executing the function is a step where we can run all
the statements inside the function to get the final result.
5. Returning a value: Returning a value is the step where the calculated value after
the execution of the function is returned. Exiting the function is the final step
where all the allocated memory to the variables, functions, etc is destroyed
before giving full control to the main function.
Program example:
// Driver code
int main()
{
Output
Sum is: 40
e) Types of Functions
● Library Functions
● User Defined Functions
Library Function
A library function is also referred to as a “built-in function”. A compiler package already exists
that contains these functions, each of which has a specific meaning and is included in the
package. Built-in functions have the advantage of being directly usable without being
defined, whereas user-defined functions must be declared and defined before being used.
// Driver code
int main() {
double Number;
Number = 49;
For Example:
pow(), sqrt(), strcmp(), strcpy() etc.
Functions that the programmer creates are known as User-Defined functions or “tailor-
made functions”. User-defined functions can be improved and modified according to the
need of the programmer.
Example:
// C program to show
// user-defined functions
#include <stdio.h>
// Driver code
int main(){
int a = 30, b = 40;
// function call
2) Loops
Loops in programming are used to repeat a block of code until the specified condition is met.
A loop statement allows programmers to execute a statement or group of statements
multiple times without repetition of code.
● Test Expression: In this expression, test conditions are performed. If the condition
evaluates to true then the loop body will be executed and then an update of the loop
variable is done. If the test expression becomes false then the control will exit from
the loop. for example, i<=9;
● Update Expression: After execution of the loop body loop variable is updated by
some value it could be incremented, decremented, multiplied, or divided by any
value.
The first program shows how you must proceed to print text several times. You’d need to
write as many printf() functions as you need to have the text printed the times you want .
#include <stdio.h>
int main(){
printf( "Hello World\n");
printf( "Hello World\n");
printf( "Hello World\n");
printf( "Hello World\n");
printf( "Hello World\n");
return 0;
}
#include <stdio.h>
// Driver code
int main(){
int i = 0;
for (i = 1; i <= 10; i++){ printf( "Hello World\n");};
return 0; };
In C, we have to declare the array like any other variable before using it. We can declare an
array by specifying its name, the type of its elements, and the size of its dimensions. When
we declare an array in C, the compiler allocates the memory block of the specified size to
the array name.
Program description :
int main()
{
return 0;
}
b) C Array Initialization
Initialization in C is the process to assign some initial value to the variable. When the
array is declared or allocated memory, the elements of the array contain some
garbage value. So, we need to initialize the array to some meaningful value. There
are multiple ways in which we can initialize an array in C.
In this method, we initialize the array along with its declaration. We use an initializer
list to initialize multiple elements of the array. An initializer list is the list of values
enclosed within braces { } separated by comma.
If we initialize an array using an initializer list, we can skip declaring the size of the
array as the compiler can automatically deduce the size of the array in these cases.
The size of the array in these cases is equal to the number of elements present in the
initializer list as the compiler can automatically deduce the size of the array.
We initialize the array after the declaration by assigning the initial value to each
element individually. We can use for loop, while loop, or do-while loop to assign the
value to each element of the array.
for (int i = 0; i < N; i++) {
array_name[i] = value i;
}
Program Description:
int main()
{
// array initialization using initialier list
int arr1[] = { 1, 2, 3, 4, 5 };
float arr2[5];
for (int i = 0; i < 5; i++) {
arr2[i] = (float)i * 2.1; }
return 0;
}
We can access any element of an array in C using the array subscript operator [ ]
and the index value i of the element.
array_name [index];
One thing to note is that the indexing in the array always starts with 0, i.e., the first
element is at index 0 and the last element is at N – 1 where N is the number of
elements in the array.
Program Description :
#include <stdio.h>
int main()
{
return 0;
}
Output
Element at arr[2]: 35
Element at arr[4]: 55
Element at arr[0]: 15
array_name[i] = new_value;
f) Length of Array in C
● Using Loop
The sizeof operator is a compile-time unary operator that calculates the size of the variables
and datatypes. It returns an integer value that represents the size of the expression or a
variable in bytes. The sizeof operator is primarily used for dynamic memory allocation but it
can also be used to find the length of an array.
The trick is to first find the size of the whole array in bytes and the size of a single element
using the sizeof operator and then divide the size of the whole array by the size of a single
element so that we can get the number of elements in the array.
Syntax:
data_type size = sizeof(Array_name) / sizeof(Array_name[index]);
In the above syntax,
● data_type: It is the type of variable in which we want to store the length of the
array.(like int, size_t, etc.).
● Array_name: It is the name of the array you want to find the size of.
int main()
{
int Arr[] = { 1, 2, 3, 4, 5 };
return 0;
}
Output
We can also calculate the length of an array in C using pointer arithmetic. This solution of
using a pointer is just a hack that is used to find the number of elements in an array.
Syntax:
data_type length = *(&arr + 1) - arr;
int Arr[] = { 1, 2, 3, 4, 5, 6 };
// variable to store the size of Arr
int length = *(&Arr + 1) - Arr;
Output
Using Loop
The loop method is used to calculate the length of an array in C. It iterates through all the
elements of an array and increments the count.
// C Program to calculate size of an array using loop
#include <stdio.h>
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int n;
n = arr_length(arr);
printf("Length of Array is: %d", n);
return 0;
}
Output
Length of Array is: 10
Note: Please noteThe iterative methods of finding the length of the strings (array of
characters) also cannot be applied to the array of other types as there is no end indicator in
these array types in contrast to the ‘\0’ NULL character marking the end of the string. that
these methods only works when the array is declared in the same scope. These methods
will fail if we try them on an array which is passed as a pointer. This happens due to Array
Decay
g) C Array Traversal
Traversal is the process in which we visit every element of the data structure. For C array
traversal, we use loops to iterate through each element of the array.
Program Description:
int main()
{
// array declaration and initialization
int arr[5] = { 10, 20, 30, 40, 50 };
return 0;
}
Output
h) Types of Array in C
There are two types of arrays based on the number of dimensions it has. They are as
follows:
The One-dimensional arrays, also known as 1-D arrays in C are those arrays that
have only one dimension.
Syntax of 1D Array in C:
array_name [size];
Program Description:
// 1d array declaration
int arr[5];
return 0;
}
output
Elements of Array: 1 0 1 4 9
Multidimensional Array in C
Multi-dimensional Arrays in C are those arrays that have more than one dimension.
Some of the popular multidimensional arrays are 2D arrays and 3D arrays. We can
declare arrays with more dimensions than 3d arrays but they are avoided as they get
very complex and occupy a large amount of space.
● Two-Dimensional Array in C
Syntax of 2D Array in C
array_name[size1] [size2];
Here,
int main()
{
printf("2D Array:\n");
// printing 2d array
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
Output
2D Array:
10 20 30
40 50 60
● Three-Dimensional Array in C
Another popular form of a multi-dimensional array is Three Dimensional Array or 3D
Array. A 3D array has exactly three dimensions. It can be visualized as a collection of
2D arrays stacked on top of each other to create the third dimension.
Syntax of 3D Array in C:
Program Description :
int main()
{
// 3D array declaration
int arr[2][2][2] = { 10, 20, 30, 40, 50, 60 };
// printing elements
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
printf("%d ", arr[i][j][k]);
}
printf("\n");
}
printf("\n \n");
}
return 0;
}
Output
10 20
30 40
50 60
0 0
chapter
1. STRINGS
String literals can be assigned without size. Here, the name of the string str acts as a pointer
because it is an array.
char str[] = "learning";
● Assigning a string literal with a predefined size
String literals can be assigned with a predefined size. But we should always account for one
extra space which will be assigned to the null character. If we want to store a string of size n
then we should always declare a string with a size equal to or greater than n+1.
char str[50] = "learning ";
We can also assign a string character by character. But we should remember to set the end
character as ‘\0’ which is a null character.
We can assign character by character without size with the NULL character at the end. The
size of the string is determined by the compiler automatically.
char str[] = { 'L','e','a','r','n','i','n','g','\0'};
Note: When a Sequence of characters enclosed in the double quotation marks is
encountered by the compiler, a null character ‘\0’ is appended at the end of the string by
default.
Note: After declaration, if we want to assign some other text to the string, we have to
assign it one by one or use built-in strcpy() function because the direct assignment of
string literal to character array is only possible in declaration.
Program description:
#include <stdio.h>
#include <string.h>
int main()
{
// declare and initialize string
char str[] = "learning";
// print string
printf("%s\n", str);
int length = 0;
length = strlen(str);
return 0;
}
Output
learning
Length of string str is 5
We can see in the above program that strings can be printed using normal printf statements
just like we print any other variable. Unlike arrays, we do not need to print a string, character
by character.
Note: The C language does not provide an inbuilt data type for strings but it has an access
specifier “%s” which can be used to print and read strings directly.
The following example demonstrates how to take string input using scanf() function in C
int main()
{
// declaring string
char str[50];
// reading string
scanf("%s",str);
// print string
printf("%s",str);
return 0;
}
Input
learning
Output
learning
You can see in the above program that the string can also be read using a single scanf
statement. Also, you might be wondering why we have not used the ‘&’ sign with the string
name ‘str’ in scanf statement! To understand this you will have to recall your knowledge of
scanf.
We know that the ‘&’ sign is used to provide the address of the variable to the scanf()
function to store the value read in memory. As str[] is a character array so using str without
braces ‘[‘ and ‘]’ will give the base address of this string. That’s why we have not used ‘&’ in
this case as we are already providing the base address of the string to scanf.
#include <stdio.h>
// driver code
int main()
{
char str[20];
scanf("%s", str);
// printing the read string
printf("%s", str);
return 0;
}
Input
Learning takes time and effort and much more than just going for a job.
Output
Learning takes time and effort and much more than just going for a job.
1. We can use the fgets() function to read a line of string and gets() to read characters
from the standard input (stdin) and store them as a C string until a newline character
or the End-of-file (EOF) is reached.
Example 1:
// C program to illustrate
// fgets()
#include <stdio.h>
#define MAX 50
int main()
{
char str[MAX];
Input
just type what you want
Output
String is:
just type what you want
Example 2 :
// c program
// scanset characters
#include <stdio.h>
// driver code
int main()
{
char str[20];
scanf("%[^\n]s", str);
return 0;
}
Input
doing some more printing
Output
doing some more printing
Example 3 :
int main()
{
// printing string
int i = 0;
while (arr[i]) {
printf("%c", arr[i++]);
}
return 0;
}
output : hey
The name of the array is a pointer to the array itself. The array name points to the first item.
The following sections discuss arrays and pointers.
Just in case you don't know you can use the following syntax to get the address of any data
structure:
Syntax: &variable_name
Output: 0x7ffc855092b0
#include<iostream>
int main(){
int arr[5]{1,2,3,4,5};
};
Each of the following statements will print the same address.that’s why it is said that an array
works similar to pointers.
Output:
a) arr: 0x7ffe359cf1d1
b) &arr: 0x7ffe359cf1d1
c) &arr[0]: 0x7ffe359cf1d1
d) To Access Addresses
At first it might seem surprising that you can use the array notation ptr[i] for pointers.
The compiler translates arr[i] to *(arr + i)—in other words: “Start at address
arr, move i objects up, and access the object!” This also applies to ptr[i].
Program Description:
#include <stdio.h>
int main()
{
output :
Syntax:
char variable_name[r] = {list of string};
Here,
● r is the maximum number of string values that can be stored in a string array.
● c is the maximum number of character values that can be stored in each string
array.
#include <stdio.h>
// Driver code
int main()
{
char arr[3][10] = {"hey","you ", "laugh more "};
printf("String array Elements are:\n");
Output
hey
you
laugh more
We have 3 rows and 10 columns specified in our Array of String but because of pre-
specifying the size of the array of strings the space consumption is high. So, to avoid high
space consumption in our program we can use an Array of Pointers in C.
Example:
char arr[3][10] = {"Geek", "Geeks", "Geekfor"};
Here, arr[0] = “GFG”; // This will give an Error that says
assignment to expression with an array type.
#include <stdio.h>
// Driver code
int main()
{
char *arr[] = {"Geek", "Geeks", "Geekfor"};
printf("String array Elements are:\n");
Output
Chapter
When you initialize a variable you can start performing operations with it like additions,
subtraction and many more according to the data type you’re working with.
I’ll introduce operators and their use cases.
there’s a wide range of operators that will let you work along the program to achieve its
objectives.
Operators
1.1 Binary Operators
The figure below makes clear why they’re called binary operators because to perform a
calculation you need two operands
a) ARITHMETIC OPERATORS
The following table shows the binary arithmetic operators that can be used in your C
program.
A recommendation is to always use the same type to avoid program errors.
Example :
Program Description: calculate meters based on centimeters , add them and print the
values.
#include <stdio.h>
int main () {
float meters=3.65;
float centimeters=4.25;
printf("%f", centimeterToMeters);
printf("%f",sum);
return 0;
b) ASSIGNMENT OPERATORS
“=”: This is the simplest assignment operator. This operator is used to assign the value on
the right to the variable on the left.
Example:
a = 10;
b = 20;
ch = 'y';
“+=”: This operator is a combination of ‘+’ and ‘=’ operators. This operator first adds the
current value of the variable on left to the value on the right and then assigns the result to
the variable on the left.
Example:
“=”This operator is a combination of ‘-‘ and ‘=’ operators. This operator first subtracts the
current value of the variable on the left from the value on the right and then assigns the
result to the variable on the left.
Example:
(a -= b) can be written as (a = a - b)
If initially value stored in a is 8. Then (a -= 6) = 2.
“*=”This operator is combination of ‘*’ and ‘=’ operators. This operator first multiplies the
current value of the variable on left to the value on the right and then assigns the result to
the variable on the left
Example:
(a *= b) can be written as (a = a * b)
If initially value stored in a is 5. Then (a *= 6) = 30.
“/=”This operator is a combination of ‘/’ and ‘=’ operators. This operator first divides the
current value of the variable on the left by the value on the right and then assigns the result
to the variable on the left.
Example:
(a /= b) can be written as (a = a / b)
If initially value stored in a is 6. Then (a /= 2) = 3.
Program Description :
// C program to demonstrate
// working of Assignment operators
#include <stdio.h>
int main()
// Assigning value 10 to a
// using "=" operator
int a = 10;
printf("Value of a is %d\n", a);
return 0;
}
c) COMPARISON OPERATORS
#include <stdio.h>
int main () {
_Bool comparisonResult= 5>6;
return 0;
}
d) LOGICAL OPERATORS
Logical operators comprise the boolean operators && (AND), || (OR), and ! (NOT).
They can be used to create compound conditions and perform conditional execution of a
program depending on multiple conditions.
A logical expression results in a value false or true, depending on whether the logical
expression is correct or incorrect, just like a relational expression.
In other words it takes two expressions . An expression can be defined as any code that
gets executed and ends up being a Value.
Example :
The following table shows variable A and B , their possible boolean values and compares
them using logical operators showing the returned boolean value.
● && And Operator
The and operator && evaluates an expression and returns a boolean value (true or false) .
it will return true only if both operands are true, so the logical expression:
int main () {
int x=2;
int y=3;
// returns 1 (true)
printf(“%d”,result);}
● The OR operator ||
will return true only if at least one operand is true, so the value
of the expression
#include <stdio.h>
int main () {
int x=2;
int y=4;
printf(“%d”,result);
return 0;
}
● The NOT operator !
will return true only if its operand is false. If the variable flag
contains the value false (or the value 0), !flag returns the boolean value true.
// A remainder any value that does not equal 0 . When used along the Not! operator will
return 1. The Value 0 represents False when it comes to Boolean types and 1 represents
True.
Now comes the trick , any values exceeding 0 will be treated as truthy values .
when you apply this operator it returns the opposite boolean value.
Let's check this down below.
#include <stdio.h>
return 0;
};
1.3 Unary Arithmetic Operators
#include <stdio.h>
int main () {
int num=1;
// adds 1 to num
num ++;
printf("%d\n",num);
num--;
printf("%d\n", num);
num--;
printf("%d\n",num);
return 0;
};
Chapter 4
A control flow statement is a statement that results in a choice being made as to which of two or
more paths to follow.
1.1 If Statements
Program Description : compares two numbers and if the expression results in numOne
being smaller than numTwo the printf() function executes that is the program executes the
code between the braces if not the program skips the code and just ends without any
further execution.
#include <stdio.h>
int main () {
int numOne=2;
int numTwo=5;
if (numOne<numTwo){
}
return 0;
};
output
Program Description : it is the same case as before but the program now executes the
code block in the else statement if the condition is not satisfied.
I changed the numOne value to 5 when the if expression gets evaluated it evaluates to false
but this isn't going to stop the program . in this case the else printf() executes before
reaching the return statement.
#include <stdio.h>
int main () {
int numOne=5;
int numTwo=5;
if (numOne<numTwo){
} else {
};
return 0;
};
Imagine that you want to evaluate several conditions. To accomplish this you’d need
to make use of several if /else-if statements . when one expression returns true the block
stops executing. if more than one condition is satisfied the one reached first executes and
the rest is not evaluated.
} else if (condition 2) {
statement 2
}else{
statement 3
};
if (condition 1) {
statement 1
}
if (condition 2) {
statement 2
}
if (condition 3) {
statement 3
}
#include <stdio.h>
int main()
{
int i = 20;
if (i == 10)
printf("i is 10");
else if (i == 15)
printf("i is 15");
else if (i == 20)
printf("i is 20");
else
printf("i is not present");
return 0;
}
The expression gets evaluated and executes the code that matches the case.
The break keyword prevents further execution.
if there’s no matching case the default case gets executed when included in the statement.
switch (expression)
{
case constant 1:
group-of-statements-1;
break;
case constant 2:
group-of-statements-2;
break;
...
default:
default-group-of-statements;
break;
}
#include <stdio.h>
int main()
{
// variable to be used in switch statement
int var = 2;
// declaring switch cases
switch (var) {
case 1:
printf("Case 1 is executed");
break;
case 2:
printf("Case 2 is executed");
break;
default:
printf("Default Case is executed");
break;
}
return 0;
}
It is kind of similar to the if-else statement as it follows the same algorithm as the if-else
statement but the conditional operator takes less space and helps to write the if-else
statements in the shortest way possible. It is also known as the ternary operator in C as it
operates on three operands
Example program
Description:
#include <stdio.h>
int main()
{
int m = 5, n = 4;
return 0;
}
CHAPTER 5
1. LOOPS
Loops in programming are used to repeat a block of code until the specified condition is met.
A loop statement allows programmers to execute a statement or group of statements
multiple times without repetition of code.
1.1. For Loops
is a repetition control structure that allows programmers to write a loop that will be executed
a specific number of times. for loop enables programmers to perform n number of steps
together in a single line.
statement1;
statement2;
...
statementN;
}
#include <stdio.h>
int main () {
return 0;
};
Another iteration statement is the while loop. It is simpler than the for loop. it will execute the
code as long as the condition evaluates to true (expression is true).
int main()
{
// Initialization of loop variable
int i = 0;
// loop statements
printf("GeeksforGeeks\n");
return 0;
}
A Similar loop is to the do-while loop, where the condition is checked after the execution
of the body statements, instead of before.This means that the code gets executed at least
once. that's the main difference between the other loops , which won't run the code if the
condition isn’t met (it’s evaluated first)
int main()
{
return 0;
}
a) What is continue in C?
The C continue statement resets program control to the beginning of the loop when
encountered. As a result, the current iteration of the loop gets skipped and the control moves
on to the next iteration. Statements after the continue statement in the loop are not
executed.
b) Syntax of continue in C
The syntax of continue is just the continue keyword placed wherever we want in the loop
body.
continue;
c) Use of continue in C
The continue statement in C can be used in any kind of loop to skip the current iteration. In
C, we can use it in the following types of loops:
● Single Loops
● Nested Loops
Using continue in infinite loops is not useful as skipping the current iteration won’t make a
difference when the number of iterations is infinite.
The continue statement can be used in for loop, while loop, and do-while loop.
Program Example :
#include <stdio.h>
int main()
{
// for loop to print 1 to 8
if (i == 4) {continue;}
printf("%d ", i); }
printf("\n");
int i = 0;
while (i < 8) {
i++;
if (i == 4) {continue;}
printf("%d ", i);}
return 0;}
Output
1 2 3 5 6 7 8
1 2 3 5 6 7 8
● STEP 1: The loop’s execution starts after the loop condition is evaluated to be
true.
● STEP 3A: If the condition is false, the normal execution will continue.
● STEP 3B: If the condition is true, the program control will jump to the start of the
loop and all the statements below the continue will be skipped.
FLOWCHART OF CONTINUE IN C
1.5 The Break Statement
Use of break in C
The break statement in C is used for breaking out of the loop. We can use it with any type of
loop to bring the program control out of the loop. In C, we can use the break statement in the
following ways:
● Simple Loops
● Nested Loops
● Infinite Loops
● Switch case
Example 1:
//Break statements in C can be used with simple loops i.e, for loops, while loops, and
do-while loops.
#include <stdio.h>
int main() {
// using break inside for loop to terminate after 2
// iteration
int i = 1;
while (i < 20) {
if (i == 3)
break;
else
printf("%d ", i);
i++;
}
return 0;
};
1. STEP 1: The loop execution starts after the test condition is evaluated.
3. STEP 3A: If the condition is true, the program control reaches the break
statement and skips the further execution of the loop by jumping to the
statements directly below the loop.
4. STEP 3B: If the condition is false, the normal flow of the program control
continues.
1.6 The Goto Statement
Examples:
Type 1: In this case, we will see a situation similar to as shown in Syntax1 above. Suppose
we need to write a program where we need to check if a number is even or not and print
accordingly using the goto statement. The below program explains how to do this:
// C program to check if a number is
// even or not using goto statement
#include <stdio.h>
{
if (num % 2 == 0)
// jump to even
goto even;
else
// jump to odd
goto odd;
even:
printf("%d is even", num);
// return if even
return;
odd:
printf("%d is odd", num);
}
int main()
{
int num = 26;
checkEvenOrNot(num);
return 0;
}
Output:
26 is even
Type 2: In this case, we will see a situation similar to as shown in Syntax2 above. Suppose
we need to write a program that prints numbers from 1 to 10 using the goto statement. The
below program explains how to do this.
● The use of the goto statement is highly discouraged as it makes the program
logic very complex.
● The use of goto makes tracing the flow of the program very difficult.
● The use of goto makes the task of analyzing and verifying the correctness of
programs (particularly those involving loops) very difficult.
● The use of goto can be simply avoided by using break and continue statements.
chapter 6
1.1 FUNCTIONS
A function consists in a piece of code that executes a set of instructions, performs a certain
operation and returns a value(optional ). If nothing is returned, the Void type is used.
1.2 Main Function
The main function is an integral part of the programming languages such as C. The main
function in C is where the execution of a program starts. It is a user-defined function that is
mandatory for the execution of a program because when a C program is executed, the
operating system starts executing the statements in the main() function.
return_type main() {
// Statement 1;
// Statement 2;
// and so on..
return;
}
We can write the main function in many ways in C language as follows:
In the above notations, int means integer return type, and void return type means that does
not return any information, or (void) or () means that does not take any information.
Let’s see the example of the main function inside which we have written a simple program
for printing a string. In the below code, first, we include a header file and then we define a
main function inside which we write a statement to print a string using printf() function. The
main function is called by the operating system itself and then executes all statements inside
this function.
Syntax :
void main()
{
// Function body
}
Program Example :
#include <stdio.h>
// code
printf("Hello Geek!");
}
Output
Hello Geek!
Note: The return type of main function according to C standard should be int only. Even if
your compiler is able to run void main(), it is recommended to avoid it.
In this example, we use the int return type in the main() function that indicates the exit status
of the program. The exit status is a way for the program to communicate to the operating
system whether the program was executed successfully or not. The convention is that a
return value of 0 indicates that the program was completed successfully, while any other
value indicates that an error occurred.
Syntax
int main()
{
// Function body
}
or
int main(void)
{
// Function Body
}
Program example :
#include <stdio.h>
int main()
{ printf("Hello Geek!");
return 0;}
Output
Hello Geek!
In this example, we have passed some arguments in the main() function as seen in the
below code. These arguments are called command line arguments and these are given at
the time of executing a program.
The first argument argc means argument count which means it stores the number of
arguments passed in the command line and by default, its value is 1 when no argument is
passed.
The second argument is a char pointer array argv[] which stores all the command line
arguments passed. We can also see in the output when we run the program without passing
any command line argument the value of argc is 1.
Syntax
Program example :
#include <stdio.h>
return 0;
}
I've previously detailed the creation process to put functions into work.
This chapter intends to dive deeper into their concept and application.
1) Declaration
2) Definition
a) int sum {
int num1 =2;
int num 2= 5;
int total = num1 + num2 ;
cout<< total;};
3) Calling :
a) sum ();
b) sum (1+2);
1) Function Declaration
In a function declaration, we must provide the function name, its return type, and the number
and type of its parameters. A function declaration tells the compiler that there is a function
with the given name defined somewhere else in the program.
Syntax: return_type - function_name - ( parameter list );
It’s composed of the returned value type, the function’s name and a list of parameters.
parameters can be optional but you must specify the type of each of them.
Function calling can be carried out with or without parameters.
1. Just like when you declare a variable you state its type but in this case what you're
stating is its return type. if the result of the operation effectuated returns an integer
you must start the declaration with an Int type.
2. Next you decide which name the function will take according to the expected
operation which at the time of writing turns out to be a “sum“.
3. Last step is to insert into the parenthesis the type of variables it is going to take to
execute the defined set of instructions (statements) in the definition step when the
function is called.
Example: 1.int
2.sum
3.(int a , int b )
2) Function Definition
When we define a function, we need to make sure that the signature (the return
value, the name, and the parameters) are the same as the declaration.
You must always use the return keyword unless nothing is returned.
A function can return a value by using the return keyword, followed by the value it wants to
return. If there’s no value to return, the Void type is used.
int sum ( ){
int a= 10;
int b=11;
int result = a+ b;
return result;
}
The C function prototype is a statement that tells the compiler about the function’s name, its
return type, numbers and data types of its parameters. By using this information, the
compiler cross-checks function parameters and their data type with function definition and
function call.
Function prototype works like a function declaration where it is necessary where the function
reference or call is present before the function definition but optional if the function definition
is present before the function call in the program.
Most programmers declare a function on top of the file and define it after the main function
with the objective of making the code more manageable , more organized and more
readable.
#include <iostream>
using namespace std;
// main function
int main() {
PrintName("Thomas", "Jefferson");
return 0;
// function definition
Although the previous structure of the code is the most preferred you could also
declare and define a function at a different place like in a header file or in any different order
in the same file although some compilers might complain if you don't follow the previous
order .Nevertheless try to stick to the above model since it is the standard followed by most
c++ programmers.
The compiler inserts the code of an inline function at the address where the function is
called and thus avoids jumping to a subroutine. The definition of an inline function is
introduced by the inline keyword in the function header.
An inline function must be defined in the source file in which it is called. You cannot
simply supply a prototype of the function. The code containing the instructions must
also be available to the compiler. It therefore makes sense to define inline functions in
header files, in contrast to “normal” functions. This means the function will be available
in several source files.
3) Function Calling
To call a function means that the code statements are going to be executed .
Basically the steps when dealing with function calling are as follows:
a) CALLING METHODS:
// DECLARATION
string sayHello();
// DEFINITION
string sayHello(){
string hello = “hello”;
std::cout<< hello <<std::endl; };
// FUNCTION CALL
sayHello();
To call a function that takes parameters, you need to write the name of the function,
followed by a list of expressions inside a pair of parentheses. Calling a function means that
it's going to execute the code defined in it.
output: 3
NOTE
● An argument is the value the caller wants to bind to the parameters of the function.
sum (1,2);
When you call the function you are giving it these two numbers as arguments. so arguments
are the actual value you assign to the defined parameters .
Example:
int a , b = 2;
sum (a,b);
Output: 4
#include <iostream>
using namespace std;
void Combine(string first, string second)
{
cout << first << " " << second << endl;
}
void Combine(int first, int second)
{
int sum = first + second;
cout << first << " " << second << " " << sum << endl;
}
int main()
{
Combine("David","Letterman");
Combine(15,20);
return 0;}
1) Default Parameters
2) Passed by Value
3) Passed by Reference
1) DEFAULT PARAMETERS
A function can be defined to take Default Parameters. See the example below:
The caller of the function can call multiply either with 1 or 2 arguments:
multiply(10); // Returns 10
The first term, passing by value, means sending the actual value of a variable to a function
when you call it. When working with C++, you accomplish this
task by calling the function with the variable. The second term,
passing by reference, means sending the address of the variable to the function so that
the function can modify the original content of that variable.
2) AS A VALUE TYPE
When the parameter is a value type, we say that the function is taking
an argument by value or the argument is passed by value.
In this case ,arguments are copied and a new local object is created each time the function
is called.
int main () {
int a =10;
int b=11;
sum(a,b);
return 0;};
Output: 21
a) Returning by Value
The calling code can then use the returned temporary value in another expression or
assign it to a value.
#include <iostream>
using namespace std
int main() {
int x = 3;
int y=5;
int result;
result=multiplication(x,y);
return 0;
}
In this case the sum function returned value gets stored in the result variable.
In this program you are passing two const variables to the function multiplication in order to
multiply them.
If you try to change the value of any of the passed arguments you'll get an increment of read
only parameter error.
#include <iostream>
int main() {
const int x = 3;
const int y=5;
int result=multiplication(x,y);
std::cout<< result<<std::endl; }
int total= x * y;
return total;}
There is no widespread reason to return by const value since the calling code often
assigns the value to a variable, in which case the const-ness of the variables is going
to be the deciding factor, or passes the value to a next expression, and it is rare for an
expression to expect a const value.
#include <iostream>
using namespace std;
int main() {
const int x = 3;
const int y=5;
const int result=multiplication(x,y);//
std::cout<< result<<std::endl;
return 0;
}
Example 1:
int pencils = 3 ;
int *refToPencils = &pencils; // its value is now
pencil’s address
Program Example :
#include <cstdio>
int main() {
// printing
printf("Original: %p\n", original);
printf("Reference: %p\n", ptr_original);
// printing
printf("Original: %p\n", original);
printf("New Value: %p\n", new_value);
printf("Reference: %p\n", ptr_original);
Original: 100
Reference: 100
Original: 200
New Value: 200
Reference: 200
a) Const References :
References to const cannot be used to change the object they refer to.
they’re read-only references.
Trying to modify the variable countries through refCountries throws a compiler error.
You can modify the value of var countries but not from the refToCountries variable.
If you change the value of countries the changes will be visible in refToCountries ;
Syntax;
a) type variable_name;
Snippet :
int countries =250;
ptrToCountries++ ;
Output:
A callback is any executable code that is passed as an argument to another code, which is
expected to call back (execute) the argument at a given time. In simple language, If a
reference of a function is passed to another function as an argument to call it, then it will be
called a Callback function.
In C, a callback function is a function that is called through a function pointer.
Below is a simple example in C to illustrate the above definition to make it more clear.
Program Example :
void A(){
printf("I am function A\n");
}
// callback function
void B(void (*ptr)())
{
(*ptr)(); // callback to A
}
int main()
{
void (*ptr)() = &A;
return 0;
}
Output
I am function A
This can be done by wrapping the array in a structure and creating a variable of type
of that structure and assigning values to that array. After that, passing the variable to
some other function and modifying it as per requirements. Note that array members
are copied when passed as parameters, but dynamic arrays are not. So this solution
works only for non-dynamic arrays (created without new or malloc).
Example 1:
#include<stdio.h>
#include<stdlib.h>
# define SIZE 5
printf("\n");
// Driver code
int main()
{
int i;
struct ArrayWrapper obj;
for (i=0; i<SIZE; i++)
obj.arr[i] = 10;
modify(obj);
printf("\n");
return 0;
}
Example 2 :
#include <stdio.h>
// Driver program
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
unsigned int n = sizeof(arr)/sizeof(arr[0]);
fun(arr, n);
return 0;
}
Output
1 2 3 4 5 6 7 8
Example 3 :
#include <stdio.h>
void fun(int *arr)
{
int i;
unsigned int n = sizeof(arr)/sizeof(arr[0]);
for (i=0; i<n; i++)
printf("%d ", arr[i]);
}
// Driver program
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
fun(arr);
return 0;
}
Output
1 2
According to the processor, the size of the pointer changes for a 32 bit computer it
assigns 4 bytes to the pointer then output becomes 1.
Example 4 :
#include <stdio.h>
#include <string.h>
// Driver program
int main()
{
char arr[] = "geeksquiz";
fun(arr);
return 0;
}
Output
n = 9
g e e k s q u i z
Example 5:
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
// Driver program
int main()
{
char arr[]
= { 'g', 'e', 'e', 'k', 's', 'q', 'u', 'i', 'z' };
fun(arr);
return 0;
}
Output
n = 9
g e e k s q u i z
b) PASS A 2D ARRAY
Example 1:
#include <stdio.h>
const int M = 3;
const int N = 3;
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr);
return 0;
}
Output
1 2 3 4 5 6 7 8 9
Example 2 :
When only the second dimension is available globally (either as a macro or as a global
constant).
#include <stdio.h>
const int N = 3;
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}
Output
1 2 3 4 5 6 7 8 9
The above method is fine if the second dimension is fixed and is not user specified. The
following methods handle cases when the second dimension can also change.
Example 3:
#include <stdio.h>
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
print(m, n, arr);
return 0;
}
Output
1 2 3 4 5 6 7 8 9
If the compiler is not C99 compatible, then we can use one of the following methods to pass
a variable sized 2D array.
Example 4 :
#include <stdio.h>
void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
Output
1 2 3 4 5 6 7 8 9
Example 5:
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr);
return 0;
}
Output
1 2 3 4 5 6 7 8 9
chapter
C Storage Classes are used to describe the features of a variable/function. These features
basically include the scope, visibility, and lifetime which help us to trace the existence of a
particular variable during the runtime of a program.
C language uses 4 storage classes, namely:
1) auto
This is the default storage class for all the variables declared inside a function or a block.
Hence, the keyword auto is rarely used while writing programs in C language. Auto variables
can be only accessed within the block/function they have been declared and not outside
them (which defines their scope). Of course, these can be accessed within nested blocks
within the parent block/function in which the auto variable was declared.
However, they can be accessed outside their scope as well using the concept of pointers
given here by pointing to the very exact memory location where the variables reside. They
are assigned a garbage value by default whenever they are declared.
2) extern
Extern storage class simply tells us that the variable is defined elsewhere and not within the
same block where it is used. Basically, the value is assigned to it in a different block and this
can be overwritten/changed in a different block as well. So an extern variable is nothing but
a global variable initialized with a legal value where it is declared in order to be used
elsewhere. It can be accessed within any function/block.
Also, a normal global variable can be made extern as well by placing the ‘extern’ keyword
before its declaration/definition in any function/block. This basically signifies that we are not
initializing a new variable but instead, we are using/accessing the global variable only. The
main purpose of using extern variables is that they can be accessed between two different
files which are part of a large program.
extern keyword in C applies to C variables (data objects) and C functions. Basically, the
extern keyword extends the visibility of the C variables and C functions. That’s probably the
reason why it was named extern.
Though most people probably understand the difference between the “declaration” and the
“definition” of a variable or function, for the sake of completeness, let’s clarify it
Declaration of a variable or function simply declares that the variable or function exists
somewhere in the program, but the memory is not allocated for them. The declaration of a
variable or function serves an important role–it tells the program what its type is going to be.
In the case of function declarations, it also tells the program the arguments, their data types,
the order of those arguments, and the return type of the function. So that’s all about the
declaration.
Coming to the definition, when we define a variable or function, in addition to everything that
a declaration does, it also allocates memory for that variable or function. Therefore, we can
think of the definition as a superset of the declaration (or declaration as a subset of the
definition).
The extern variable is used when a particular files need to access a variable from another
file.
a) Syntax of extern in C
The syntax to define an extern variable in C is just to use the extern keyword before the
variable declaration.
#include <stdio.h>
extern int a; // int var; -> declaration and definition
// extern int var; -> declaration
int main()
{
printf("%d", a);
return 0;
}
● Multiple declarations of extern variable is allowed within the file. This is not the
case with automatic variables.
● The extern variable says to the compiler “Go outside my scope and you will find
the definition of the variable that I declared.”
● The compiler believes that whatever that extern variable said is true and
produces no error. Linker throws an error when it finds no such variable exists.
● When an extern variable is initialized, then memory for this is allocated and it will
be considered defined.
A variable or function can be declared any number of times, but it can be defined only once.
(Remember the basic principle that you can’t have two locations of the same variable or
function).
Now back to the extern keyword. First, Let’s consider the use of extern in functions. It turns
out that when a function is declared or defined, the extern keyword is implicitly assumed.
When we write.
Since the extern keyword extends the function’s visibility to the whole program, the function
can be used (called) anywhere in any of the files of the whole program, provided those files
contain a declaration of the function. (With the declaration of the function in place, the
compiler knows the definition of the function exists somewhere else and it goes ahead and
compiles the file). So that’s all about extern and functions.
Now let’s consider the use of extern with variables. To begin with, how would you declare a
variable without defining it? You would do something like this:
Here, an integer-type variable called var has been declared (it hasn’t been defined yet, so no
memory allocation for var so far). And we can do this declaration as many times as we want.
Now, how would you define var? You would do this:
In this line, an integer type variable called var has been both declared and defined
(remember that definition is the superset of declaration). Since this is a definition, the
memory for var is also allocated. Now here comes the surprise. When we declared/defined a
function, we saw that the extern keyword was present implicitly. But this isn’t the case with
variables. If it were, memory would never be allocated for them. Therefore, we need to
include the extern keyword explicitly when we want to declare variables without defining
them. Also, as the extern keyword extends the visibility to the whole program, by using the
extern keyword with a variable, we can use the variable anywhere in the program provided
we include its declaration the variable is defined somewhere.
int var;
int main(void)
{
var = 10;
return 0;
}
—--
extern int var;
int main(void)
{
return 0;
}
—----------
extern int var;
int main(void)
{
var = 10;
return 0;
}
// As we are importing the file and henceforth the
// defination
#include "somefile.h"
int main(void)
{
var = 10;
return 0;
}
Output:
10
Note: Here arises another scenario what if we do not declare with extern in the above code
snippet,?
Considering an assumption that somefile.h contains the definition of var, this program will
compile successfully. ‘extern’ keyword is used for a variable when we declare the variable in
one file and define it in another file. But here when we import the same file in the file where it
is declared, here compiler error will be generated.
It is because we still have to use the extern keyword in the file where we have declared that
variable so as to tell our compiler that this variable is been defined somewhere else than
only new memory space will not be allocated else it will create another memory block which
usage of ‘extern’ keyword useless.
1. A declaration can be done any number of times but defined only once.
3. Since functions are visible throughout the program by default, the use of the
extern is not needed in function declarations or definitions. Its use is implicit.
4. When extern is used with a variable, it’s only declared, not defined.
3) static
This storage class is used to declare static variables which are popularly used while writing
programs in C language. Static variables have the property of preserving their value even
after they are out of their scope! Hence, static variables preserve the value of their last use
in their scope. So we can say that they are initialized only once and exist till the termination
of the program. Thus, no new memory is allocated because they are not re-declared.
Their scope is local to the function to which they were defined. Global static variables can be
accessed anywhere in the program. By default, they are assigned the value 0 by the
compiler.
Static variables have the property of preserving their value even after they are out of their
scope! Hence, a static variable preserves its previous value in its previous scope and is not
initialized again in the new scope.
a) Syntax:
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
static int i = initializer();
printf(" value of i = %d", i);
getchar();
return 0;
}
The reason for this is simple: All objects with static storage duration must be initialized (set
to their initial values) before execution of main() starts. So a value which is not known at
translation time cannot be used for initialization of static variables.
● A static int variable remains in memory while the program is running. A normal or
auto variable is destroyed when a function call where the variable was declared is
over.
For example, we can use static int to count the number of times a function is called,
but an auto variable can’t be used for this purpose.
Example 1:
#include <stdio.h>
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Output
Example 2 :
#include <iostream>
using namespace std;
struct marks {
int num;
// Driver Program
int main()
{
marks m1;
Output
1 2
The above program prints 1 2 because static variables are only initialized once and live till
the end of the program. That is why they can retain their value between multiple function
calls.
Let’s try the same code for the local auto variable.
Example 3 :
#include <stdio.h>
// Function
int fun()
{
int count = 0;
count++;
return count;
}
// Driver Code
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Output
1 1
● Static variables are allocated memory in the data segment, not the stack
segment. See the memory layout of C programs for details.Static variables
(like global variables) are initialized as 0 if not initialized explicitly. For
example in the below program, the value of x is printed as 0, while the value
of y is something garbage. See this for more details.
Example 1 :
// C program to illustrate the default value of static
// variables
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n%d", x, y);
}
Output
0
[some_garbage_value]
● In C, static variables can only be initialized using constant literals. For example, the
following program fails in the compilation. See this for more details.
Example 1:
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
static int i = initializer();
printf(" value of i = %d", i);
getchar();
return 0;
}
Output
In function 'main':
9:5: error: initializer element is not constant
static int i = initializer();
^
Note: Please note that this condition doesn’t hold in C++. So if you save the program as a
C++ program, it would compile and run fine.
● Static global variables and functions are also possible in C/C++. The purpose of
these is to limit the scope of a variable or function to a file. Please refer to Static
functions in C for more details.
● Static variables should not be declared inside a structure. The reason is C compiler
requires the entire structure elements to be placed together (i.e.) memory allocation
for structure members should be contiguous. It is possible to declare structure inside
the function (stack segment) or allocate memory dynamically(heap segment) or it can
be even global (BSS or data segment). Whatever might be the case, all structure
members should reside in the same memory segment because the value for the
structure element is fetched by counting the offset of the element from the beginning
address of the structure. Separating out one member alone to a data segment
defeats the purpose of structure and it is possible to have an entire structure as
static.
c) Static functions
In C, functions are global by default. The “static” keyword before a function name makes it
static.
Unlike global functions in C, access to static functions is restricted to the file where they
are declared. Therefore, when we want to restrict access to functions, we make them static.
Another reason for making functions static can be the reuse of the same function name in
other files.
/* Inside file1.c */
static void fun1(void) {
puts("fun1 called");
}
/* Inside file2.c */
int main(void)
{
fun1();
getchar();
return 0;
}
Now, if we compile the above code with the command “gcc file2.c file1.c”, we get the error
“undefined reference to `fun1’”. This is because fun1() is declared static in file1.c and cannot
be used in file2.c.
In C, functions are global by default. The “static” keyword before a function name makes it
static.
Unlike global functions in C, access to static functions is restricted to the file where they
are declared. Therefore, when we want to restrict access to functions, we make them static.
Another reason for making functions static can be the reuse of the same function name in
other files.
/* Inside file1.c */
static void fun1(void) {
puts("fun1 called");
}
/* Inside file2.c */
int main(void)
{
fun1();
getchar();
return 0;
}
Now, if we compile the above code with the command “gcc file2.c file1.c”, we get the error
“undefined reference to `fun1’”. This is because fun1() is declared static in file1.c and cannot
be used in file2.c.
4) register
This storage class declares register variables that have the same functionality as that of the
auto variables. The only difference is that the compiler tries to store these variables in the
register of the microprocessor if a free register is available. This makes the use of register
variables to be much faster than that of the variables stored in the memory during the
runtime of the program.
If a free registration is not available, these are then stored in the memory only. Usually, a few
variables which are to be accessed very frequently in a program are declared with the
register keyword which improves the running time of the program. An important and
interesting point to be noted here is that we cannot obtain the address of a register variable
using pointers.
Registers are faster than memory to access, so the variables which are most frequently used
in a C program can be put in registers using the register keyword. The keyword register
hints to the compiler that a given variable can be put in a register. It’s the compiler’s choice
to put it in a register or not. Generally, compilers themselves do optimizations and put the
variables in a register.
b) Following are some interesting facts about the “register” keyword in C:
● If you use & operator with a register variable then the compiler may give an error or
warning (depending upon the compiler you are using), because when we say a
variable is a register, it may be stored in a register instead of memory and accessing
the address of a register is invalid.
#include <stdio.h>
int main()
{
// Declaring a register variable 'i' and initializing it
// with 10
register int i = 10;
// Creating a pointer variable 'a' and assigning the
// address of 'i' to it
int* a = &i;
printf("%d", *a);
getchar();
return 0;
}
Output
./Solution.c: In function 'main':
./Solution.c:6:5: error: address of register variable 'i' requested
int* a = &i;
● register keyword can be used with pointer variables. Obviously, a register can have
the address of a memory location. There would not be any problem with the below
program.
Example :
#include <stdio.h>
int main()
{
// Declaring an integer variable 'i' and initializing it
// with 10
int i = 10;
// Declaring a register pointer variable 'a' and
// assigning the address of 'i' to it
register int* a = &i;
printf("%d", *a);
getchar();
return 0;
}
Output
10
● Register is a storage class, and C doesn’t allow multiple storage class specifiers for
a variable. So, the register can not be used with static.
#include <stdio.h>
int main()
{
// Declaring an integer variable 'i' and initializing it
// with 10
int i = 10;
Output
./Solution.c: In function 'main':
./Solution.c:6:5: error: multiple storage classes in declaration
specifiers
register static int* a = &i;
● Register can only be used within a block (local), it can not be used in the global
scope (outside main).
Example:
#include <stdio.h>
Output
./Solution.c:4:14: error: register name not specified for 'x'
register int x = 10;
^
● There is no limit on the number of register variables in a C program, but the point is
the compiler may put some variables in the register and some not. Please write
comments if you find anything incorrect in the above article or you want to share
more information about register keyword.
a) Syntax
To specify the storage class for a variable, the following syntax is to be followed:
Example:
#include <stdio.h>
void autoStorageClass()
{
printf("\nDemonstrating auto class\n\n");
printf("--------------------------------");
}
void registerStorageClass() {
printf("\nDemonstrating register class\n\n");
printf("--------------------------------");
}
void externStorageClass()
{
printf("\nDemonstrating extern class\n\n");
printf("--------------------------------");
}
void staticStorageClass()
{
int i = 0;
printf("\nDemonstrating static class\n\n");
printf("\nLoop started:\n");
printf("\nLoop ended:\n");
printf("--------------------------------");
}
int main()
{
// exiting
printf("\n\nStorage Classes demonstrated");
return 0;
}
Output
Loop started:
Loop ended:
chapter
chapter
FILE HANDLING
1. Types of Files in C
A file can be classified into two types based on the way the file stores the data. They are as
follows:
● Text Files
● Binary Files
Text Files
A text file contains data in the form of ASCII characters and is generally used to store a
stream of characters.
● Each line in a text file ends with a new line character (‘\n’).
Binary Files
A binary file contains data in binary form (i.e. 0’s and 1’s) instead of ASCII characters. They
contain data that is stored in a similar manner to how it is stored in the main memory.
● The binary files can be created only from within a program and their contents can
only be read by a program.
1. Creating a new file – fopen() with attributes as “a” or “a+” or “w” or “w+”
FILE* pointer_name;
For opening a file in C, the fopen() function is used with the filename or file path along with
the required access modes.
Syntax of fopen()
Parameters
● file_name: name of the file when present in the same directory as the source file.
Otherwise, full path.
Return Value
File opening modes or access modes specify the allowed operations on the file to be
opened. They are passed as an argument to the fopen() function. Some of the commonly
used file access modes are listed below:
As given above, if you want to perform operations on a binary file, then you have to append
‘b’ at the last. For example, instead of “w”, you have to use “wb”, instead of “a+” you have to
use “a+b”.
Opening
Description
Modes
NULL.
Open for reading in binary mode. If the file does not exist,
rb
fopen( ) returns NULL.
Open for reading in text mode. If the file exists, its contents
Open for both reading and writing in binary mode. If the file
rb+
does not exist, fopen( ) returns NULL.
Searches file. If the file exists, its contents are overwritten. If
Open for both reading and writing in binary mode. If the file
wb+ exists, its contents are overwritten. If the file does not exist,
it will be created.
#include <stdio.h>
#include <stdlib.h>
int main()
// fopen
FILE* fptr;
if (fptr == NULL) {
"now exit.");
exit(0);
return 0;
Output : The file is not opened. The program will now exit.
The file is not opened because it does not exist in the source directory. But the fopen()
function is also capable of creating a file if it does not exist. It is shown below
The fopen() function can not only open a file but also can create a file if it does not exist
already. For that, we have to use the modes that allow the creation of a file if not found such
as w, w+, wb, wb+, a, a+, ab, and ab+.
FILE *fptr;
fptr = fopen("filename.txt", "w");
int main()
{
// file pointer
FILE* fptr;
return 0;
}
Output
The file is created Successfully.
So, it depends on you if you want to read the file line by line or character by character.
Example:
FILE * fptr;
char c = fgetc(fptr);
The getc() and some other file reading functions return EOF (End Of File) when they reach
the end of the file while reading. EOF indicates the end of the file and its value is
implementation-defined.
Note: One thing to note here is that after reading a particular part of the file, the file pointer
will be automatically moved to the end of the last read character.
Example:
FILE *fptr ;
fptr = fopen(“fileName.txt”, “w”);
fprintf(fptr, "%s %s %s %d", "We", "are", "in", 2012);
fputc("a", fptr);
The fclose() function is used to close the file. After successful file operations, you must
always close a file to remove it from the memory.
Syntax of fclose()
fclose(file_pointer);
FILE *fptr ;
fclose(fptr);
Example 1: Program to Create a File, Write in it, And Close the File
int main()
{
if (strlen(dataToBeWritten) > 0) {
// writing in the file using fputs()
fputs(dataToBeWritten, filePointer);
fputs("\n", filePointer);
}
return 0;
}
Output
The file is now opened.
Data successfully written in file GfgTest.c
The file is now closed.
This program will create a file named GfgTest.c in the same directory as the source file
which will contain the following text: “GeeksforGeeks-A Computer Science Portal for Geeks”.
Example 2: Program to Open a File, Read from it, And Close the File
int main()
{
printf(
"Data successfully read from file GfgTest.c\n");
printf("The file is now closed.");
}
return 0;
}
Output
This program reads the text from the file named GfgTest.c which we created in the previous
example and prints it in the console.
Binary Files
Till now, we have only discussed text file operations. The operations on a binary file are
similar to text file operations with little difference.
1.1 Opening a Binary File
To open a file in binary mode, we use the rb, rb+, ab, ab+, wb, and wb+ access mode in the
fopen() function. We also use the .bin file extension in the binary filename.
Example
We use fwrite() function to write data to a binary file. The data is written to the binary file in
the from of bits (0’s and 1’s).
Syntax of fwrite()
Parameters:
Return Value:
Example:
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main()
{
int n;
// Structure variable declared here.
struct threeNum num;
FILE* fptr;
if ((fptr = fopen("C:\\program.bin", "wb")) == NULL) {
printf("Error! opening file");
// If file pointer will return NULL
// Program will exit.
exit(1);
}
int flag = 0;
int flag = 0;
// else it will return a pointer to the file.
for (n = 1; n < 5; ++n) {
num.n1 = n;
num.n2 = 5 * n;
num.n3 = 5 * n + 1;
flag = fwrite(&num, sizeof(struct threeNum), 1,
fptr);
fclose(fptr);
return 0;
}
Output
The fread() function can be used to read data from a binary file in C. The data is read from
the file in the same form as it is stored i.e. binary form.
Syntax of fread()
Parameters:
Return Value:
Example:
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
};
int main()
int n;
FILE* fptr;
exit(1);
num.n3);
fclose(fptr);
return 0;
Output
1.4 fseek() in C
If we have multiple records inside a file and need to access a particular record that is at a
specific position, so we need to loop through all the records before it to get the record. Doing
this will waste a lot of memory and operational time. To reduce memory consumption and
operational time we can use fseek() which provides an easier way to get to the required
data. fseek() function in C seeks the cursor to the given record in the file.
Example :
#include <stdio.h>
int main()
{
FILE* fptr;
fptr = fopen("file.txt", "w+");
fprintf(fptr, "Geeks for Geeks\n");
// using rewind()
rewind(fptr);
printf("%s", buf);
return 0;
}
Output
81
The following table lists some more functions that can be used to perform file operations or
assist in performing them.
Functions Description
getw()
chapter
1. Memory Management
1) Text Segment: A text segment, also known as a code segment or simply as text, is
one of the sections of a program in an object file or in memory, which contains
executable instructions.
As a memory region, a text segment may be placed below the heap or stack in order
to prevent heaps and stack overflows from overwriting it. Usually, the text segment is
sharable so that only a single copy needs to be in memory for frequently executed
programs, such as text editors, the C compiler, the shells, and so on. Also, the text
segment is often read-only, to prevent a program from accidentally modifying its
instructions.
2) Initialized Data Segment: Initialized data segment, usually called simply the Data
Segment. A data segment is a portion of the virtual address space of a program,
which contains the global variables and static variables that are initialized by the
programmer.
Note that, the data segment is not read-only, since the values of the variables can be
altered at run time. This segment can be further classified into the initialized read-
only area and the initialized read-write area.
For instance, the global string defined by char s[] = “hello world” in C and a C
statement like int debug=1 outside the main (i.e. global) would be stored in the
initialized read-write area. And a global C statement like const char* string = “hello
world” makes the string literal “hello world” to be stored in the initialized read-only
area and the character pointer variable string in the initialized read-write area.
Ex: static int i = 10 will be stored in the data segment and global
int i = 10 will also be stored in data segment
3) Uninitialized Data Segment: Uninitialized data segment often called the “bss”
segment, named after an ancient assembler operator that stood for “block started by
symbol.” Data in this segment is initialized by the kernel to arithmetic 0 before the
program starts executing uninitialized data starts at the end of the data segment and
contains all global variables and static variables that are initialized to zero or do not
have explicit initialization in source code.
For instance, a variable declared static int i; would be contained in the BSS segment.
For instance, a global variable declared int j; would be contained in the BSS
segment.
4) Stack: The stack area traditionally adjoined the heap area and grew in the opposite
direction; when the stack pointer met the heap pointer, free memory was exhausted.
(With modern large address spaces and virtual memory techniques they may be
placed almost anywhere, but they still typically grow in opposite directions.)
The stack area contains the program stack, a LIFO structure, typically located in the
higher parts of memory. On the standard PC x86 computer architecture, it grows
toward address zero; on some other architectures, it grows in the opposite direction.
A “stack pointer” register tracks the top of the stack; it is adjusted each time a value
is “pushed” onto the stack. The set of values pushed for one function call is termed a
“stack frame”; A stack frame consists at minimum of a return address.
Stack, where automatic variables are stored, along with information that is saved
each time a function is called. Each time a function is called, the address of where to
return to and certain information about the caller’s environment, such as some of the
machine registers, are saved on the stack. The newly called function then allocates
room on the stack for its automatic variables. This is how recursive functions in C can
work. Each time a recursive function calls itself, a new stack frame is used, so one
set of variables doesn’t interfere with the variables from another instance of the
function.
5) Heap: Heap is the segment where dynamic memory allocation usually takes place.
The heap area begins at the end of the BSS segment and grows to larger addresses
from there. The Heap area is managed by malloc, realloc, and free, which may use
the brk and sbrk system calls to adjust its size (note that the use of brk/sbrk and a
single “heap area” is not required to fulfill the contract of malloc/realloc/free; they may
also be implemented using mmap to reserve potentially non-contiguous regions of
virtual memory into the process’ virtual address space). The Heap area is shared by
all shared libraries and dynamically loaded modules in a process.
Examples:
The size(1) command reports the sizes (in bytes) of the text, data, and bss segments. ( for
more details please refer man page of size(1) )
int main(void)
{
return 0;
}
b) Let us add one global variable in the program, now check the size of bss (highlighted in
red color).
#include <stdio.h>
int main(void)
{
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 248 12 1220 4c4 memory-layout
#include <stdio.h>
int main(void)
{
static int i; /* Uninitialized static variable stored in bss
*/
return 0;
}
d) Let us initialize the static variable which will then be stored in the Data Segment
(DS)
#include <stdio.h>
int main(void)
{
static int i = 100; /* Initialized static variable stored in
DS*/
return 0;
}
f) Let us initialize the global variable which will then be stored in the Data Segment
(DS)
#include <stdio.h>
int global = 10; /* initialized global variable stored in DS*/
int main(void)
{
static int i = 100; /* Initialized static variable stored in
DS*/
return 0;
}
Since C is a structured language, it has some fixed rules for programming. One of them
includes changing the size of an array. An array is a collection of items stored at contiguous
memory locations.
As can be seen, the length (size) of the array above is 9. But what if there is a requirement
to change this length (size)?
For example,
● If there is a situation where only 5 elements are needed to be entered in this array. In
this case, the remaining 4 indices are just wasting memory in this array. So there is a
requirement to lessen the length (size) of the array from 9 to 5.
● Take another situation. In this, there is an array of 9 elements with all 9 indices filled.
But there is a need to enter 3 more elements in this array. In this case, 3 indices
more are required. So the length (size) of the array needs to be changed from 9 to
12.
This procedure is referred to as Dynamic Memory Allocation in C.
Therefore, C Dynamic Memory Allocation can be defined as a procedure in which the size of
a data structure (like Array) is changed during the runtime.
C provides some functions to achieve these tasks. There are 4 library functions provided by
C defined under <stdlib.h> header file to facilitate dynamic memory allocation in C
programming. They are:
1. malloc()
2. calloc()
3. free()
4. realloc()
a) Syntax of malloc() in C
Since the size of int is 4 bytes, this statement will allocate 400 bytes of memory. And, the
pointer ptr holds the address of the first byte in the allocated memory.
If space is insufficient, allocation fails and returns a NULL pointer.
Example of malloc() in C
#include <stdio.h>
#include <stdlib.h>
int main()
{
return 0;
}
Output
a) Syntax of calloc() in C
For Example:
Example of calloc() in C
#include <stdio.h>
#include <stdlib.h>
int main()
{
return 0;
}
Output
“free” method in C is used to dynamically de-allocate the memory. The memory allocated
using functions malloc() and calloc() is not de-allocated on their own. Hence the free()
method is used, whenever the dynamic memory allocation takes place. It helps to reduce
wastage of memory by freeing it.
a) Syntax of free() in C
free(ptr);
Example of free() in C
#include <stdio.h>
#include <stdlib.h>
int main()
{
return 0;
}
Output
a) Syntax of realloc() in C
Example of realloc() in C
#include <stdio.h>
#include <stdlib.h>
int main()
{
free(ptr);
}
return 0;
}
Output
4. malloc() has high time efficiency calloc() has low time efficiency
malloc() does not add any extra calloc() adds some extra memory
9.
memory overhead overhead
Array in C is static in nature, so its size should be known at compile time and we can’t
change the size of the array after its declaration. Due to this, we may encounter situations
where our array doesn’t have enough space left for required elements or we allotted more
than the required memory leading to memory wastage. To solve this problem, dynamic
arrays come into the picture.
A Dynamic Array is allocated memory at runtime and its size can be changed later in the
program.
Syntax:
We can use this function to create a dynamic array of any type by simply allocating a
memory block of some size and then typecasting the returned void pointer to the pointer of
the required type.
Example:
In the above example, we have created a dynamic array of type int and size 100 elements.
Note: It is to be noted that if malloc fails to allocate the required memory, it returns the NULL
pointer. So, it is a good practice to check for NULL pointers to see if the memory is
successfully allocated or not.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Memory allocated
printf("Memory successfully allocated using "
"malloc.\n");
return 0;
}
Output:
Enter size of elements:5
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5,
The process of creating a dynamic array using calloc() is similar to the malloc() method. The
difference is that calloc() takes arguments instead of one as compared to malloc(). Here, we
provide the size of each element and the number of elements required in the dynamic array.
Also, each element in the array is initialized to zero.
Syntax:
Example:
In the above example, we have created a dynamic array of type float having five elements.
Let’s take another example to create a dynamic array using the calloc() method.
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Memory allocated
printf("Memory successfully allocated using "
"malloc.\n");
return 0;
}
Output:
Enter size of elements:6
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5, 6,
Syntax:
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {
printf("Memory successfully allocated using "
"calloc.\n");
}
// inserting elements
for (int j = 0; j < size; ++j) {
ptr[j] = j + 1;
}
printf("\n");
size = 10;
// using realloc
ptr = realloc(ptr, size * sizeof(int));
if (!ptr) {
printf("Memory Re-allocation failed.");
ptr = temp;
}
else {
printf("Memory successfully re-allocated using "
"realloc.\n");
}
Output
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
Memory successfully re-allocated using realloc.
The new elements of the array are: 1, 2, 3, 4, 5, 15, 16, 17, 18,
19,
Variable length arrays or VLAs, are those arrays in which we can determine the size of the
array at the run time. It allocates the memory in the stack and it’s based on the local scope
level.
The size of a variable length array cannot be changed once it is defined and using variable
length array as its found down sides as compared to above methods.
Example:
#include <stdio.h>
int main()
{
int n;
printf("Enter the size of the array: ");
scanf("%d", &n);
int arr[n];
scanf("%d", &arr[i]);
}
return 0;
}
Output:
Enter the size of the array: 5
Enter elements: 1 2 3 4 5
Elements of VLA of Given Size: 1 2 3 4 5
The flexible array members are the array that is defined inside a structure without any
dimension and their size is flexible. This feature was introduced in C99 standard.
We can control the size of a flexible member using malloc() function.
There are a few rules to follow in the case of flexible array members:
● The array inside the structure should preferably be declared as the last member of
the structure and its size is variable(can be changed at runtime).
● The structure must contain at least one more named member in addition to the
flexible array member.
struct student
{
int len;
int
};
// defining struct
typedef struct {
int len;
int arr[];
} fam;
int main()
{
// creating an array member of size 5
fam* fam1
= (fam*)malloc(sizeof(fam*) + 5 * sizeof(int));
// inserting elements
for (int i = 0; i < 5; i++) {
fam1->arr[i] = i + 1;
}
for (int i = 0; i < 10; i++) {
fam2->arr[i] = i + 10;
}
// printing elements
printf("Array of Size 5:\n");
for (int i = 0; i < 5; i++) {
printf("%d, ", fam1->arr[i]);
}
printf("\n");
#include <stdio.h>
#include <stdlib.h>
// defining struct
typedef struct {
int len;
int arr[];
} fam;
int main()
{
// creating an array member of size 5
fam* fam1
= (fam*)malloc(sizeof(fam*) + 5 * sizeof(int));
// inserting elements
for (int i = 0; i < 5; i++) {
fam1->arr[i] = i + 1;
}
for (int i = 0; i < 10; i++) {
fam2->arr[i] = i + 10;
}
// printing elements
printf("Array of Size 5:\n");
for (int i = 0; i < 5; i++) {
printf("%d, ", fam1->arr[i]);
}
printf("\n");
Output
Array of Size 5:
1, 2, 3, 4, 5,
Array of size 10:
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
chapter
1.1 Preprocessor
Preprocessors are programs that process the source code before compilation. A number of
steps are involved between writing a program and executing a program in C / C++. Let us
have a look at these steps before we actually start learning about Preprocessors.
You can see the intermediate steps in the above diagram. The source code written by
programmers is first stored in a file, let the name be “program.c“. This file is then processed
by preprocessors and an expanded source code file is generated named “program.i”. This
expanded file is compiled by the compiler and an object code file is generated named
“program.obj”. Finally, the linker links this object code file to the object code of the library
functions to generate the executable file “program.exe”.
1.2 Preprocessor Directives in C/C++
Preprocessor programs provide preprocessor directives that tell the compiler to preprocess
the source code before compiling. All of these preprocessor directives begin with a ‘#’ (hash)
symbol. The ‘#’ symbol indicates that whatever statement starts with a ‘#’ will go to the
preprocessor program to get executed. We can place these preprocessor directives
anywhere in our program.
Examples of some preprocessor directives are: #include, #define, #ifndef, etc.
Note: Remember that the # symbol only provides a path to the preprocessor, and a
command such as include is processed by the preprocessor program. For example, #include
will include the code or content of the specified file in your program.
These preprocessors can be classified based on the type of function they perform.
1.3 Types of C/C++ Preprocessors
There are 4 Main Types of Preprocessor Directives:
1) Macros
2) File Inclusion
3) Conditional Compilation
4) Other directives
1) Macros
In C/C++, Macros are pieces of code in a program that is given some name. Whenever this
name is encountered by the compiler, the compiler replaces the name with the actual piece
of code. The ‘#define’ directive is used to define a macro.
where after preprocessing, the token will be expanded to its value in the program.
Example of a Macro
#include <stdio.h>
// macro definition
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
printf("%d \n", i);
}
return 0;
}
Output
0
1
2
3
4
In the above program, when the compiler executes the word LIMIT, it replaces it with 5. The
word ‘LIMIT’ in the macro definition is called a macro template and ‘5’ is macro expansion.
Note: There is no semi-colon (;) at the end of the macro definition. Macro definitions do not
need a semi-colon to end.
There are also some Predefined Macros in C which are useful in providing various
functionalities to our program.
We can also pass arguments to macros. Macros defined with arguments work similarly to
functions.
Example
#define foo(a, b) a + b
#define func(r) r * r
int main()
{
int l1 = 10, l2 = 5, area;
return 0;
}
Output
We can see from the above program that whenever the compiler finds AREA(l, b) in the
program, it replaces it with the statement (l*b). Not only this, but the values passed to the
macro template AREA(l, b) will also be replaced in the statement (l*b). Therefore AREA(10,
5) will be equal to 10*5.
2) File Inclusion
This type of preprocessor directive tells the compiler to include a file in the source code
program. The #include preprocessor directive is used to include the header files in the C/C+
+ program.
There are two types of files that can be included by the user in the program:
The standard header files contain definitions of pre-defined functions like printf(), scanf(),
etc. These files must be included to work with these functions. Different functions are
declared in different header files.
For example, standard I/O functions are in the ‘iostream’ file whereas functions that perform
string operations are in the ‘string’ file.
Syntax:
#include <file_name>
where file_name is the name of the header file to be included. The ‘<‘ and ‘>’ brackets tell
the compiler to look for the file in the standard directory.
When a program becomes very large, it is a good practice to divide it into smaller files and
include them whenever needed. These types of files are user-defined header files. These
files can be included as:
#include "filename"
3) Conditional Compilation
Conditional Compilation in C/C++ directives is a type of directive that helps to compile a
specific portion of the program or to skip the compilation of some specific part of the program
based on some conditions. There are the following preprocessor directives that are used to
insert conditional code:
1. #if Directive
2. #ifdef Directive
3. #ifndef Directive
4. #else Directive
5. #elif Directive
6. #endif Directive
#endif directive is used to close off the #if, #ifdef, and #ifndef opening directives which
means the preprocessing of these directives is completed.
Syntax
#ifdef macro_name
statement1;
statement2;
statement3;
.
.
.
statementN;
#endif
If the macro with the name ‘macro_name‘ is defined, then the block of statements will
execute normally, but if it is not defined, the compiler will simply skip this block of
statements.
4) Other Directives
Apart from the above directives, there are two more directives that are not commonly used.
These are:
1. #undef Directive
2. #pragma Directive
a) #undef Directive
The #undef directive is used to undefine an existing macro. This directive works as:
#undef LIMIT
Using this statement will undefine the existing macro LIMIT. After this statement, every
“#ifdef LIMIT” statement will evaluate as false.
b) #pragma Directive
This directive is a special purpose directive and is used to turn on or off some features.
These types of directives are compiler-specific, i.e., they vary from compiler to compiler.
Some of the #pragma directives are discussed below:
1. #pragma warn -rvl: This directive hides those warnings which are raised when a
function that is supposed to return a value does not return a value.
2. #pragma warn -par: This directive hides those warnings which are raised when a
function does not use the parameters passed to it.
3. #pragma warn -rch: This directive hides those warnings which are raised when a
code is unreachable. For example, any code written after the return statement in a
function is unreachable.
Example:
#include <stdio.h>
void func1();
void func2();
// driver code
int main()
{
void func1();
void func2();
printf("Inside main()\n");
return 0;
}
Output
Inside main()
Expected Output
Inside func1()
Inside main()
Inside func2()
The above code will produce the output as given below when run on GCC compilers:
Inside main()
This happens because GCC does not support #pragma startup or exit. However, you can
use the below code for the expected output on GCC compilers.
#include <stdio.h>
void func1();
void func2();
void func1()
{
printf("Inside func1()\n");
}
void func2()
{
printf("Inside func2()\n");
}
int main()
{
printf("Inside main()\n");
return 0;
}
Output
Inside func1()
Inside main()
Inside func2()
In the above program, we have used some specific syntaxes so that one of the functions
executes before the main function and the other executes after the main function.
● The preprocessor doesn’t know about the scope rules of C. Preprocessor directives
like #define come into effect as soon as they are seen and remain in effect until the
end of the file that contains them; the program’s block structure is irrelevant.
You will see the output with the code having no comments.
This file is saved with a ‘.i’ extension (prog.i) which will be input to the
compiler.
2. File inclusion : Including all the files from the library that our program needs.
In HLL we write #include which is a directive for the preprocessor that tells it
to include the contents of the library file specified. For example, #include will
tell the preprocessor to include all the contents in the library file stdio.h.
This can also be written using double quotes – #include “stdio.h”
Note: If the filename is enclosed within angle brackets, the file is searched for
in the standard compiler include paths. If the filename is enclosed within
double quotes, the search path is expanded to include the current source
directory.
3. Macro expansion : Macros can be called as small functions that are not as
overhead to process. If we have to write a function (having a small definition)
that needs to be called recursively (again and again), then we should prefer a
macro over a function.
So, defining these macros is done by a preprocessor.
#define SI 1000
is a simple example of a macro.
There are two types of macros: Object-like (do not take parameters) and function-like (Can
take parameters)
// object-like macro
#define
// function-like macro
● #define ()
You can delete a macro definition with #undef:
// delete the macro
● # undef
● We can write multi-line macro same like function,
but each statement ends with “\”.
#include <stdio.h>