Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 71

Module IV

continuation
Syllabus

• Command line arguments

• Dynamic memory allocation

• Linked lists (concepts only)

• Preprocessor directives

• macro substitution directives - Simple macros - macros with arguments - nesting


of macros, compiler control directives.
Command Line Arguments

• It is possible to pass some values from the command line to your C programs
when they are executed.

• These values are called command line arguments and many times they are
important for your program especially when you want to control your program
from outside instead of hard coding those values inside the code.
• Command-line arguments are the values given after the name of the program in the
command-line shell of Operating Systems. Command-line arguments are handled by
the main() function of a C program.

• To pass command-line arguments, we typically define main() with two arguments: the
first argument is the number of command-line arguments and the second is a list of
command-line arguments.
Command line arguments are the arguments specified after the program name in the operating
system's command line. These argument values are passed to your program during execution from
your operating system. To use this concept in your program, you have to understand the complete
declaration of how the main() function works with the command-line argument to fetch values that
earlier took no arguments with it (main() without any argument).

So you can program the main() in such a way that it can essentially accept two arguments where
the first argument denotes the number of command line arguments and the second denotes the
complete list of every command line argument.
Syntax :

int main(int argc, char *argv[]) { /* ... */ }

• argc (ARGument Count) denotes the number of arguments to be


passed
• argv [ ] (ARGument Vector) denotes a pointer array pointing to every
argument that has been passed to your program.
• argc (ARGument Count) is an integer variable that stores the number of
command-line arguments passed by the user including the name of the
program. So if we pass a value to a program, the value of argc would be 2 (one
for argument and one for program name).The value of argc should be non-
negative.

• argv (ARGument Vector) is an array of character pointers listing all the


arguments.If argc is greater than zero, the array elements from argv[0] to
argv[argc-1] will contain pointers to strings.argv[0] is the name of the program
, After that till argv[argc-1] every element is command -line arguments.
// program named mainreturn.c
#include <stdio.h>

// defining main with arguments


int main(int argc, char* argv[])
{
printf("You have entered %d arguments:\n", argc);

for (int i = 0; i < argc; i++) {


printf("%s\n", argv[i]);
}
return 0;
}
PS F:\Devagiri\Programming methodology\programs2> ./commandline lzbx zhxcubh
uHZXCUh uhZCuh
You have entered 5 arguments:
F:\Devagiri\Programming methodology\programs2\commandline.exe
lzbx
zhxcubh
uHZXCUh
uhZCuh
PS F:\Devagiri\Programming methodology\programs2>
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Program name is: %s", argv[0]);
if (argc == 1)
printf("\nNo Extra Command Line Argument Passed "
"Other Than Program Name");
if (argc >= 2) {
printf("\nNumber Of Arguments Passed: %d", argc);
printf("\n----Following Are The Command Line "
"Arguments Passed----");
for (int i = 0; i < argc; i++)
printf("\nargv[%d]: %s", i, argv[i]);
}
return 0;
}
PS F:\Devagiri\Programming methodology\programs2> ./command2 nzxb chcbxzhb xbchbxzhc bizhbizxb
hBZXichbias hzxhc as ussuhc bbhuhsbduhb uhbshvahdbb uhdsssssu
sjdbihbvhbhbfaduhvbd
Program name is: F:\Devagiri\Programming methodology\programs2\command2.exe
Number Of Arguments Passed: 13
----Following Are The Command Line Arguments Passed----
argv[0]: F:\Devagiri\Programming methodology\programs2\command2.exe
argv[1]: nzxb
argv[2]: chcbxzhb
argv[3]: xbchbxzhc
argv[4]: bizhbizxb
argv[5]: hBZXichbias
argv[6]: hzxhc
argv[7]: as
argv[8]: ussuhc
argv[9]: bbhuhsbduhb
argv[10]: uhbshvahdbb
argv[11]: uhdsssssu
argv[12]: sjdbihbvhbhbfaduhvbd
PS F:\Devagiri\Programming methodology\programs2>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {


if (argc != 3) {
exit(1);

// Convert command line arguments to integers


int num1 = atoi(argv[1]);
int num2 = atoi(argv[2]);

// Perform addition
int sum = num1 + num2;

// Display the result


printf("Sum of %d and %d is %d\n", num1, num2, sum);

return 0;
}
PS F:\Devagiri\Programming methodology\programs2> ./add2command 12 13
Sum of 12 and 13 is 25
PS F:\Devagiri\Programming methodology\programs2> ./add2command 12 13 14
PS F:\Devagiri\Programming methodology\programs2> ./add2command 12 13 14
PS F:\Devagiri\Programming methodology\programs2> ./add2command 12 13
Sum of 12 and 13 is 25
Properties of Command Line Arguments:

• They are passed to the main() function.

• They are parameters/arguments supplied to the program when it is invoked.

• They are used to control programs from outside instead of hard coding those values
inside the code.

• argv[argc] is a NULL pointer.

• argv[0] holds the name of the program.

• argv[1] points to the first command line argument


Dynamic Memory Allocation in C

• As you know, an array is a collection of a fixed number of values. Once the size of
an array is declared, you cannot change it.

• Sometimes the size of the array you declared may be insufficient. To solve this
issue, you can allocate memory manually during run-time. This is known as
dynamic memory allocation in C programming.
Dynamic Memory Allocation in 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()
malloc()

• The name "malloc" stands for memory allocation.

• The malloc() function reserves a block of memory of the specified number of


bytes.

• And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc()
ptr = (castType*) malloc(size);

Example
ptr = (float*) malloc(100 * sizeof(float));
The above statement allocates 400 bytes of memory. It's because the size of float is
4 bytes. And, the pointer ptr holds the address of the first byte in the allocated
memory.

The expression results in a NULL pointer if the memory cannot be allocated.


C calloc()

• The name "calloc" stands for contiguous allocation.

• The malloc() function allocates memory and leaves the memory uninitialized,
whereas the calloc() function allocates memory and initializes all bits to zero.

• Syntax of calloc()

ptr = (castType*)calloc(n, size);


• Example:

• ptr = (float*) calloc(25, sizeof(float));

• The above statement allocates contiguous space in memory for 25 elements of


type float.

• Syntax of free()
• free(ptr);

• This statement frees the space allocated in the memory pointed by ptr.
printf("Enter elements: ");
for(i = 0; i < n; ++i) {
// Program to calculate the sum of n numbers entered scanf("%d", ptr + i);
by the user sum += *(ptr + i);
}
#include <stdio.h>
#include <stdlib.h> printf("Sum = %d", sum);

int main() { // deallocating the memory


int n, i, *ptr, sum = 0; free(ptr);

printf("Enter number of elements: "); return 0;


scanf("%d", &n); }

ptr = (int*) malloc(n * sizeof(int));

// if memory cannot be allocated


if(ptr == NULL) { Output
printf("Error! memory not allocated.");
Enter number of elements: 3
exit(0);
} Enter elements: 100 20 36 Sum

= 156
// Program to calculate the sum of n numbers entered printf("Enter elements: ");
by the user for(i = 0; i < n; ++i) {
scanf("%d", ptr + i);
#include <stdio.h> sum += *(ptr + i);
#include <stdlib.h> }

int main() { printf("Sum = %d", sum);


int n, i, *ptr, sum = 0; free(ptr);
printf("Enter number of elements: "); return 0;
scanf("%d", &n); }

ptr = (int*) calloc(n, sizeof(int));


if(ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
Output
Enter number of elements: 3 Enter
elements: 100 20 36 Sum = 156
C realloc()
If the dynamically allocated memory is insufficient or more than required,
you can change the size of previously allocated memory using the realloc()
function.

Syntax of realloc()
ptr = realloc(ptr, x);
Here, ptr is reallocated with a new size x.
// rellocating the memory
ptr = realloc(ptr, n2 * sizeof(int));

#include <stdio.h> printf("Addresses of newly allocated memory:\n");


#include <stdlib.h> for(i = 0; i < n2; ++i)
printf("%pc\n", ptr + i);
int main() {
int *ptr, i , n1, n2; free(ptr);
printf("Enter size: ");
scanf("%d", &n1); return 0;
}
ptr = (int*) malloc(n1 * sizeof(int)); Output
printf("Addresses of previously allocated memory:\n"); Enter size: 2
for(i = 0; i < n1; ++i) Addresses of previously allocated memory:
printf("%pc\n",ptr + i); 26855472
26855476
printf("\nEnter the new size: ");
scanf("%d", &n2); Enter the new size: 4
Addresses of newly allocated memory:
26855472
26855476
26855480
26855484
Linked lists
• Node Structure: A node in a linked list typically consists of two components:

1. Data: It holds the actual value or data associated with the node.

2. Next Pointer: It stores the memory address (reference) of the next node in the
sequence.

• Head and Tail: The linked list is accessed through the head node, which points to
the first node in the list. The last node in the list points to NULL or nullptr,
indicating the end of the list. This node is known as the tail node.
Why linked list data structure needed?
• Dynamic Data structure: The size of memory can be allocated or de-allocated at run
time based on the operation insertion or deletion.

• Ease of Insertion/Deletion: The insertion and deletion of elements are simpler than
arrays since no elements need to be shifted after insertion and deletion, Just the
address needed to be updated.

• Efficient Memory Utilization: As we know Linked List is a dynamic data structure


the size increases or decreases as per the requirement so this avoids the wastage of
memory.

• Implementation: Various advanced data structures can be implemented using a


linked list like a stack, queue, graph, hash maps, etc.
Types of linked lists:

• There are mainly three types of linked lists:

1. Single-linked list

2. Double linked list

3. Circular linked list


1. Single-linked list:

• In a singly linked list, each node contains a reference to the next node in the
sequence. Traversing a singly linked list is done in a forward direction.
2. Double-linked list:

• In a doubly linked list, each node contains references to both the next and
previous nodes. This allows for traversal in both forward and backward directions,
but it requires additional memory for the backward reference.
3. Circular linked list:

• In a circular linked list, the last node points back to the head node, creating a
circular structure. It can be either singly or doubly linked.
Operations on Linked Lists
• Insertion: Adding a new node to a linked list involves adjusting the pointers of the
existing nodes to maintain the proper sequence. Insertion can be performed at the
beginning, end, or any position within the list

• Deletion: Removing a node from a linked list requires adjusting the pointers of the
neighboring nodes to bridge the gap left by the deleted node. Deletion can be performed
at the beginning, end, or any position within the list.

• Searching: Searching for a specific value in a linked list involves traversing the list from
the head node until the value is found or the end of the list is reached.
Advantages of Linked Lists

• Dynamic Size: Linked lists can grow or shrink dynamically, as memory allocation is
done at runtime.

• Insertion and Deletion: Adding or removing elements from a linked list is


efficient, especially for large lists.

• Flexibility: Linked lists can be easily reorganized and modified without requiring a
contiguous block of memory.
Disadvantages of Linked Lists
• Random Access: Unlike arrays, linked lists do not allow direct access to elements
by index. Traversal is required to reach a specific node.

• Extra Memory: Linked lists require additional memory for storing the pointers,
compared to arrays.
Preprocessor directives
The C preprocessor is a micro processor that is used by
compiler to transform your code before compilation. It is called
micro preprocessor because it allows us to add macros.

Proprocessor direcives are executed before compilation.

All preprocessor directives starts with hash # symbol.


Preprocessors :
1. #include
2. #define
3. #undef
4. #ifdef
5. #ifndef
6. #if
7. #else
8. #elif
9. #endif
10. #error
11. #pragma
• The preprocessor directives are divided into three categories.
They are:
1. Macro Substitution Directives

2. File Inclusion Directives

3. Compiler Control Directives


Macros

A macro is a piece of code in a program that is replaced by the value of the macro.
Macro is defined by #define directive. Whenever a macro name is encountered by
the compiler, it replaces the name with the definition of the macro. Macro
definitions need not be terminated by a semi-colon(;).
// C program to illustrate macros
#include <stdio.h>

// Macro definition
#define LIMIT 5

int main()
{

printf("The value of LIMIT is %d",LIMIT);

return 0;
}

Output The value of LIMIT is 5


Pre-defined C++ Macros

Pre-defined macros in C++ are ones that are already defined by the
compiler in comparison to the macros that are defined by the user in a
C++ program itself, the user can't re-define these macros in C++
program. We can use pre-defined macros directly in a C++ program.
Pre-defined Macros Definition

It is an integer literal value that represents the C++ compiler version and it is defined by the
__cplusplus compatible C++ compilers during the compilation of a C++ program. For
example, 201703201703 value represents the 2017 C++ version.

__DATE__ It is a constant length string literal displayed in Mmm dd yyyy format and it is replaced by
the date at which our source code file is compiled.

__TIME__ It is a character string literal displayed in hh:mm:ss format and it is replaced by the time at
which our source code file is compiled.

__FILE__ It is also character string literal which is replaced by the source code file path/name from where
it is stored in the computer, during the pre-processing.

__LINE__ It is an integer literal value and this directive is replaced by the line number in the source code
where it is encountered by the compiler during pre-processing.

__STDC__ To validate the compiler version __STDC__ macro is used. It usually has the value 1, indicating
that the compiler complies with ISO Standard C. Otherwise, it is undefined.
#include<stdio.h>
int main(){
C++ Compiler Version : 201703
printf("File :%s\n", __FILE__ );
Date : Feb 6 2022
printf("Date :%s\n", __DATE__ ); Time : 10:36:15
File Name : solution.cpp
printf("Time :%s\n", __TIME__ );
Line Number : 11
printf("Line :%d\n", __LINE__ ); STDC : 1
printf("STDC :%d\n", __STDC__ );
return 0;
}
Macro substitution directives
• Macro substitution is a process where an identifier in a program is replaced by a predefined string
composed of one or more tokens. The preprocessor accomplishes this task under the direction
of #define statement.

• Defining a Macro:

To define a macro, you use the #define directive followed by the macro name and its
replacement value or code. The general syntax is:

#define MACRO_NAME replacement


#include <stdio.h>

// Macro definition
#define DATE 31

int main()
{
// Print the message
printf("Lockdown will be extended upto %d-MAY-2020",DATE);
return 0;
}

Output
Lockdown will be extended upto 31-MAY-2020
• This replacement happens before the actual compilation process starts.

• Benefits of Macros:

1. Readability and Maintainability: Macros make your code more readable by replacing magic numbers or

complex expressions with meaningful names. This can significantly improve code maintainability and make

it easier for others to understand your code.

2. Consistency: Macros ensure that the same value or code snippet is used consistently throughout your

program. If you need to change a constant, you can do it in one place (the macro definition) rather than

searching for and modifying every occurrence in your code.

3. Code Reusability: Macros can encapsulate reusable pieces of code, which can be handy for avoiding code

duplication.
There are different forms of macro substitution. The most common are:

1. Simple macro substitution

2. Argumented macro substitution

3. Nested macro substitution


Simple Macro Substitution

The simple macro substitutions are generally used for declaring constants in
a C program. Some valid examples for simple macro substitution are:
define-examples

Whenever the preprocessor comes across the simple macros, the identifier will be replaced
with the corresponding string. For example, in a C program, all the occurrences of PI will be
replaced with 3.1412.
#include <stdio.h>
#define size 120
void main ()
{
int x; By using #define we can
x = ++size; create a symbolic
printf ("x=%d", x); constant value (i.e. at the
} time of pre-processing
actual data will be
substituted) which is not
possible to change at the
time of execution.
#define A 2+3
#define B 4+5
int main () Output: C = 19
{ Logic
int c; C=A*b
c = A * B; =2+3*4+5
printf ("c = %d", c); = 2 +12+5
getch (); = 19
return 0;
}
#include <stdio.h>
#define A (2+3)
#define B (4+5)
void main ()
{
int c; Output: c=45
c = A * B;
printf ("c=%d", c);
}
Argumented Macro Substitution

• The preprocessor allows us to define more complex and more useful form of
substitutions. The Argumented macro substitution takes the following form:

• Care should be taken that there is no space between the identifier and the left parentheses. The
identifiers arg1, arg2, …. , argn are the formal macro arguments that are analogous to the formal
arguments in a function definition.

• In the program, the occurrence of a macro with arguments is known as a macro call. When a
macro is called, the preprocessor substitutes the string, replacing the formal parameters with
actual parameters.
• For example, if the Argumented macro is declared as shown below:


and the macro is called as shown below:

Then the preprocessor will expand the above statement as:


// C Program to illustrate function like macros
#include <stdio.h>

// macro with parameter


#define AREA(l, b) (l * b)

int main()
{
int A = 10, B = 5, area;

area = AREA(A, B);

printf("Area of rectangle is: %d", area);

return 0;
}

Output Area of rectangle is: 50


Nested Macro Substitution

• We can use one macro inside the definition of another macro. Such
macros are known as nested macros. Example for a nested macro is
shown below:
#include<stdio.h>

#define NO no
#define SQUARE(x) (x*x)
#define CUBE(x) (SQUARE(x)*x)

int main()
{
int no;

printf("Enter the number=");


scanf("%d",&no);

printf("\n\nThe square of %d is= %d",no,SQUARE(no));


printf("\n\nThe cube of %d is= %d",no,CUBE(no));

return 0;
}
#include<stdio.h>
#define Area(x) x*x
#define Costpaint(x,y,z) (z*y + Area (x))
void main()
{
int A = 8, B= 6, C = 4;
clrscr();
printf("The area of square= %d\n", Area(A));
printf("Cost of paint= %d\n", Costpaint(A,B,C));
}
File Inclusion Directives

• The external files containing functions or macro definitions can be linked with our
program so that there is no need to write the functions and macro definitions
again. This can be achieved by using the #include directive.

• The syntax for this directive is as shown below:


• We can use either of the above statements to link our program with other files. If
the filename is included in double quotes, the file is searched in the local
directory. If the filename is included in angular brackets, then the file is searched
in the standard directories.
Standard Header Files
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.

User-defined Header Files


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"
The double quotes ( ” ” ) tell the compiler to search for the header file in the source file’s
directory.
Compiler Control Directives
Conditional Compilation in 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

Directive Purpose
#ifdef Test for a macro definition
#endif Specifies the end of #if
Tests whether a macro is not
#ifndef
defined

#if Test a compile-time condition

#else Specifies alternative when #if fails


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.
#if
The #if preprocessor directive evaluates the expression or condition. If condition is true, it executes
the code otherwise #elseif or #else or #endif code is executed.

#include<stdio.h>
#define NUMBER 0
int main()
{
#if (NUMBER==0)
printf("Value of Number is: %d",NUMBER);
#endif
return 0;
}
Output:

Value of Number is: 0


#include <stdio.h>
#include <conio.h>
Output:
#define NUMBER 1
2 Value of Number is: 1
void main()
{
clrscr();
#if (NUMBER==0)
printf("1 Value of Number is: %d",NUMBER);
#endif
#if (NUMBER==1)
printf("2 Value of Number is: %d",NUMBER);
#endif
getch();
}
#else
The #else preprocessor directive evaluates the expression or condition if condition of #if is false. It can be
used with #if, #elif, #ifdef and #ifndef directives.

Syntax:
#if expression #if expression
//if code //if code
#else #elif expression
//else code //elif code
#endif #else
//else code
#endif
#include <stdio.h>
#include <conio.h>
#define NUMBER 1
void main()
{
#if NUMBER==0
printf("Value of Number is: %d",NUMBER);
#else
print("Value of Number is non-zero");
#endif
getch();
}

Output:
Value of Number is non-zero
#ifdef
The #ifdef preprocessor directive checks if macro is defined by #define. If yes, it executes the code
otherwise #else code is executed, if present.

Syntax:
#ifdef MACRO
//code
#endif
#include <stdio.h>
#include <conio.h>
#define NOINPUT
void main()
{
int a=0;
#ifdef NOINPUT
a=2;
#else
printf("Enter a:");
scanf("%d", &a);
#endif
printf("Value of a: %d\n", a);
getch();
}
#ifndef
The #ifndef preprocessor directive checks if macro is not defined by #define. If yes, it executes
the code otherwise #else code is executed, if present.
Syntax:
#ifndef MACRO
//code
#endif
Syntax with #else:
#ifndef MACRO
//successful code
#else
//else code
#endif
#include <stdio.h>
#include <conio.h>
#define INPUT
void main()
{
int a=0;
#ifndef INPUT
a=2;
#else
printf("Enter a:");
scanf("%d", &a);
#endif
printf("Value of a: %d\n", a);
getch();
}

Output:
Enter a:5 Value of a: 5

You might also like