[go: up one dir, main page]

0% found this document useful (0 votes)
212 views17 pages

Unit - 5 OODA

Memory management in programming involves controlling and coordinating a computer's main memory, focusing on proper allocation and deallocation to prevent memory leaks, especially with polymorphism and file handling. Key aspects include the use of new and delete operators in C++ for dynamic memory allocation, the importance of virtual destructors for polymorphic pointers, and effective file stream management. Polymorphism allows different types of objects to be treated as a single superclass, enhancing code reusability and flexibility.

Uploaded by

chappisumaiya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
212 views17 pages

Unit - 5 OODA

Memory management in programming involves controlling and coordinating a computer's main memory, focusing on proper allocation and deallocation to prevent memory leaks, especially with polymorphism and file handling. Key aspects include the use of new and delete operators in C++ for dynamic memory allocation, the importance of virtual destructors for polymorphic pointers, and effective file stream management. Polymorphism allows different types of objects to be treated as a single superclass, enhancing code reusability and flexibility.

Uploaded by

chappisumaiya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 17

UNIT-5

Memory management is the process of controlling and coordinating a computer's main


memory. It ensures that blocks of memory space are properly managed and allocated so the
operating system (OS), applications and other running processes have the memory they
need to carry out thei000r operations.When dealing with polymorphism and files
in programming, memory management primarily focuses on ensuring that
dynamically allocated memory used to store file data and objects with
polymorphic behavior is properly allocated and deallocated to prevent
memory leaks, especially when working with file streams and object
hierarchies that can involve multiple derived classes.
Key aspects of memory management in polymorphism and files:
Object creation and destruction:
Polymorphic pointers: When using a base class pointer to reference derived class
objects (polymorphism), you must ensure that the derived objects are properly
created using new and destroyed using delete to avoid memory leaks.
Virtual destructors: In C++, implementing a virtual destructor in the base class is
crucial to guarantee that the correct destructor is called when deleting a polymorphic
pointer, preventing potential memory issues.
File stream management:
Opening and closing files: Always close file streams explicitly using fclose (C) or the
equivalent function in other languages to release the associated system resources.
Error handling: Implement proper error handling mechanisms to gracefully handle
potential file opening failures and close the file stream if an error occurs.
Dynamic memory allocation for file data:
Reading large files: When dealing with large files, consider allocating memory
dynamically in chunks to avoid loading the entire file into memory at once.
Memory management with buffers: When reading data from a file into buffers,
make sure to allocate and deallocate the buffer memory appropriately.
Important considerations:
Garbage collection (in languages like Java):
If your language has automatic garbage collection, you still need to be mindful of
potential memory leaks related to file streams and dynamic memory allocation, as the
garbage collector may not always reclaim memory efficiently in complex scenarios.
Resource management frameworks:
In certain languages, utilize provided resource management frameworks to simplify
memory management, especially when dealing with files and complex object
hierarchies.
Example scenario:
Imagine a program that reads data from various types of files (text, CSV, XML) using a
base class "FileHandler" with derived classes like "TextFileHandler", "CSVFileHandler",
and "XMLFileHandler".
Polymorphism:
A single "FileHandler" pointer can be used to point to different derived class objects,
allowing the program to read data from various file types using a unified interface.
Memory management:
When opening a file, the derived class would dynamically allocate memory for the file
data and ensure that this memory is correctly deallocated using the destructor when
the file is closed.
How does Memory Management work in C++?
Memory Management is one of the pivotal and important concepts for any
programming language so is the case with C++. Concept outline of Memory management
primarily revolves around the time-space trade-off and memory allocation concept. It
helps in managing the space and memory-related issues with the help of Arrays. Arrays
are the data structure that is the main component or can be said that aids memory
management concept. How to let’s check the flow. Arrays are the data structure that
contains all the data stored in the memory by an efficient allocation of resources with
the appropriate time and space as it allocates memory at the time of array declaration
and then to avoid the wastage of memory need to use the new operator to allocate
memory dynamically at the run-time.
Sometimes it might happen that the programmer declares an array with the maximum
size and then allocates the memory according to the requirement but then in that case
there will be some memory space or cells that will remain unused. To avoid such kind of
undesirable activity it Is very much needed to keep in mind the memory allocation
technique of declaring an array with the new keyword which will take care of this kind
of situation.
Also, any programmer must keep in mind at the time of implementation that how the
program flow will be and how the resources can manage the time-space trade efficiently
with respect to memory management. Although the memory management operators are
there to take care of the memory allocation at the time of runtime but still should be
more precautious as it will help them not strive for any kind of memory allocation. If
compared with another programming language like C there the Memory Management
also happens in a similar fashion just with a minor change in the naming constraint
which involves the calloc and malloc functions in C for memory management.
In C++ memory management, the memory operators make use of the new and delete
operators. Unlike C language which makes use of the malloc and calloc functions
allocate the memory dynamically at the time of run-time and then makes use of free()
function to deallocate the dynamically allocated memory, C++ memory management
makes use of the unary operator like new and delete as mentioned earlier to perform
the same task of allocating memory and creating free space for the efficient resource
allocation.
Memory Management Operators in C++
Memory management is one of the key processing techniques for any programming
language which needs to be handled for executing any code base efficiently. It involves
certain unary operators for memory management in C++ which are as follows:
New Operator
Delete Operator
New Operator
A new operator is used for creating the object which exists and remains in active mode
which means the allocation of memory will still be active. This remains in active state
i.e. the existence of a new object is there until the delete() operator is called which will
be discussed in the next section.
The syntax flow for the new operator with respect to the memory management
allocation is as follows:
ptr_var = new data_tp
ptr_var: This represents the name of the pointer variable.
new: operator for the creation of the object for allocation.
data_tp: represents the type of data used while allocation.
Example: This program demonstrates the New Operator which is used for creation of
new object for object allocation and memory management as shown in the output.
Code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int no;
cout << "Total_Students_In_One_Batch";
cin >> no;
float* pon_tr;
pon_tr = new float[no];
cout << "Marks_Of_Students" << endl;
for (int k = 0; k < no; ++k)
{
cout << "Student_mrk" << k + 1 << ": ";
cin >> *(pon_tr + k);
}
cout << "\nDisplay the Total marks of Students" << endl;
for (int k = 0; k < no; ++k) {
cout << "Student_mrk" << k + 1 << " :" << *(pon_tr + k) << endl;
}
delete [] pon_tr;
return 0;
}
Output:

Delete Operator
On the other hand, Delete Operator is also a unary operator used for memory
management and comes into the picture only when the new operator is used for
memory allocation which signifies another fact that the delete operator is fully
dependent on the new operator. Once the new operator finishes its work of allocation
and tries to free its memory or to remove the unused or excess memory allocated it will
immediately call for the Delete Operator.
Syntax:
delete ptr_var;
delete: This represents the unary operator that needs to be used after calling the new
operator.
ptr_var: This points to the object created by the new unary operator for further deletion.
Example: This program demonstrates the delete unary operator functionality in
memory management as shown in the output.
Code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int* p1 = new int;
int* p2 = new int(11);
cout << "display_val_for_p1 = " << *p1 << "\n";
cout << "display_val_for_p2 = " << *p2 << "\n";
delete p1;
delete p2;
return 0;
}
Output:

What is the meaning of polymorphism in Ooad?


Polymorphism is a feature of object-oriented programming languages that allows a specific
routine to use variables of different types at different times. Polymorphism in programming
gives a program the ability to redefine methods for derived classes.
Polymorphism is a core concept in object-oriented programming (OOP) that allows
different types of objects to be treated as a single superclass. It's a feature that enables
code reusability and flexibility by allowing multiple classes to implement the same
method in different ways.
Here are some key aspects of polymorphism in OOP:
Interface
Polymorphism allows a programming language to present the same interface for
different underlying data types.
Code reusability
Polymorphism increases the ability to reuse the same lines of code on multiple
occasions.
Variable names
Polymorphism allows a single variable name to be used to store variables of multiple
data types.
Abstractions
Polymorphism allows for simple abstractions to be composed into more complex and
powerful ones.
Types
Polymorphism is mainly divided into two types: compile-time and runtime.
The word polymorphism comes from Greek and means "having multiple forms". The
concept is borrowed from biology, where an organism or species can have many
different forms or stages.
Difference between Inheritance and Polymorphism
Inheritance is one in which a new class is created that inherits the
properties of the already exist class. It supports the concept of code
reusability and reduces the length of the code in object-oriented
programming.
Types of Inheritance are:
Single inheritance
Multi-level inheritance
Multiple inheritances
Hybrid inheritance
Hierarchical inheritance
Example of Inheritance:
#include <iostream>
using namespace std;
class A {
int a, b;
public:
void add(int x, int y)
{
a = x;
b = y;
cout << "addition of a+b is:" << (a + b) << endl;
}
};
class B : public A {
public:
void print(int x, int y)
{
add(x, y);
}
};
int main()
{
B b1;
b1.print(5, 6);
return 0;
}
Output
addition of a+b is:11
Here, class B is the derived class which inherit the property(add method)
of the base class A.
Polymorphism:
Polymorphism is that in which we can perform a task in multiple forms or
ways. It is applied to the functions or methods. Polymorphism allows the
object to decide which form of the function to implement at compile-time
as well as run-time.
Types of Polymorphism are:
Compile-time polymorphism (Method overloading)
Run-time polymorphism (Method Overriding)
Difference between Inheritance and Polymorphism:
S.NO Inheritance Polymorphism

Inheritance is one in
which a new class is
Whereas
created (derived class)
polymorphism is that
1. that inherits the
which can be defined in
features from the
multiple forms.
already existing
class(Base class).

Whereas it is basically
It is basically applied
2. applied to functions or
to classes.
methods.

Polymorphism allows
Inheritance supports the object to decide
the concept of which form of the
3. reusability and reduces function to implement
code length in object- at compile-time
oriented programming. (overloading) as well as
run-time (overriding).

Whereas it can be
compiled-time
Inheritance can be
polymorphism
single, hybrid, multiple,
4. (overload) as well as
hierarchical and
run-time
multilevel inheritance.
polymorphism
(overriding).

It is used in pattern While it is also used in


5.
designing. pattern designing.
S.NO Inheritance Polymorphism

Example :
Example : The class bike can have
The class bike can be method name
inherit from the class set_color(), which
6.
of two-wheel vehicles, changes the bike’s color
which is turn could be based on the name of
a subclass of vehicles. color you have
entered.
What is a Virtual Function in C++?A virtual function in C++ is a base class
member function that you can redefine in a derived class to achieve
polymorphism. You can declare the function in the base class using the vissrtual
keyword. Once you declare the function in the base class, you can use a pointer
or reference to call the virtual class and execute its virtual version in the derived
class. Thus, it asks the compiler to determine the object’s type during run-time
and create a function bind (late binding or dynamic linkage).
The functions cannot be static
 You derive them using the “virtual” keyword
 Virtual functions in C++ needs to be a member of some other class (base class)
 They can be a friend function of another class
 The prototype of these functions should be the same for both the base and
derived class
 Virtual functions are accessible using object pointers
 Redefining the virtual function in the derived class is optional, but it needs to be
defined in the base class
 The function call resolving is done at run-time
 You can create a virtual destructor but not a constructor
Using a Virtual Function in C++
Now that you know the fundamentals of the virtual function in C++, it’s time to head on
to an example of using it. In the below example, you will create a base class and a
derived class. In both classes, you will create two functions: Output and Display. To see
the difference between the virtual function and a regular function, you will only declare
the Output function of the base class as virtual, and keep the display function as it is.
#include <iostream>
using namespace std;
class Base{
public:
virtual void Output(){
cout << "Output Base class" << endl;
}void Display(){
cout << "Display Base class" << endl;
}
};
class Derived : public Base{
public:
void Output(){
cout << "Output Derived class" << endl;
}
void Display()
{
cout << "Display Derived class" << endl;
}
};
int main(){
Base* bpointr;
Derived dpointr;
bpointr = &dpointr;
// virtual function binding
bpointr->Output();
// Non-virtual function binding
bpointr->Display();
}
Output:
Output derived class
Display derived classs
FILES
object-oriented analysis and design (OOAD), files can store objects that persist beyond
the application session. These objects can be retrieved in another application session
and will have the same state and relationships as when they were saved.
Here are some other things to know about files in OOAD:
File handling
Programs communicate with the target environment by reading and writing files.
File opening modes
In C++, file opening modes include:
in: Open for reading
out: Open for writing
ate: Seek to end of file upon original open
app: Append mode
File pointers
C++ uses a get pointer and put pointer for reading from and writing to files,
respectively.
File models
File models can be based on modifiability criteria, such as mutable and immutable
files.
File Handling through C++ Class
File handling is used to store data permanently in a computer. Using file handling we
can store our data in secondary memory (Hard disk).
How to achieve the File Handling
For achieving file handling we need to follow the following steps:-
STEP 1-Naming a file
STEP 2-Opening a file
STEP 3-Writing data into the file
STEP 4-Reading data from the file
STEP 5-Closing a file.
Streams in C++ :-
We give input to the executing program and the execution program gives back the
output. The sequence of bytes given as input to the executing program and the sequence
of bytes that comes as output from the executing program are called stream. In other
words, streams are nothing but the flow of data in a sequence.
The input and output operation between the executing program and the devices like
keyboard and monitor are known as “console I/O operation”. The input and output
operation between the executing program and files are known as “disk I/O operation”.
Classes for File stream operations :-
The I/O system of C++ contains a set of classes which define the file handling methods.
These include ifstream, ofstream and fstream classes. These classes are derived from
fstream and from the corresponding iostream class. These classes, designed to manage
the disk files, are declared in fstream and therefore we must include this file in any
program that uses files. File handling is essential for data storage and retrieval in
applications.
1. ios:-
ios stands for input output stream.
This class is the base class for other classes in this class hierarchy.
This class contains the necessary facilities that are used by all the other derived classes
for input and output operations.
2. istream:-
istream stands for input stream.
This class is derived from the class ‘ios’.
This class handle input stream.
The extraction operator(>>) is overloaded in this class to handle input streams from
files to the program execution.
This class declares input functions such as get(), getline() and read().
3. ostream:-
ostream stands for output stream.
This class is derived from the class ‘ios’.
This class handle output stream.
The insertion operator(<<) is overloaded in this class to handle output streams to files
from the program execution.
This class declares output functions such as put() and write().
4. streambuf:-
This class contains a pointer which points to the buffer which is used to manage the
input and output streams.
5. fstreambase:-
This class provides operations common to the file streams. Serves as a base for fstream,
ifstream and ofstream class.
This class contains open() and close() function.
6. ifstream:-
This class provides input operations.
It contains open() function with default input mode.
Inherits the functions get(), getline(), read(), seekg() and tellg() functions from the
istream.
7. ofstream:-
This class provides output operations.
It contains open() function with default output mode.
Inherits the functions put(), write(), seekp() and tellp() functions from the ostream.
8. fstream:-
This class provides support for simultaneous input and output operations.
Inherits all the functions from istream and ostream classes through iostream.
9. filebuf:-
Its purpose is to set the file buffers to read and write.
We can also use file buffer member function to determine the length of the file.

In C++, files are mainly dealt by using three classes fstream, ifstream, ofstream available
in fstream headerfile.
ofstream: Stream class to write on files
ifstream: Stream class to read from files
fstream: Stream class to both read and write from/to files.

Now the first step to open the particular file for read or write operation. We can open
file by
1. passing file name in constructor at the time of object creation
2. using the open method
For e.g.
Open File by using constructor
ifstream (const char* filename, ios_base::openmode mode = ios_base::in);
ifstream fin(filename, openmode) by default openmode = ios::in
ifstream fin(“filename”);
Open File by using open method
Calling of default constructor
ifstream fin;
fin.open(filename, openmode)
fin.open(“filesname”);
Modes :
Member
Constant Stands For Access

ios::in input File open for reading: the internal stream buffer
Member
Constant Stands For Access

supports input operations.

File open for writing: the internal stream buffer


ios::out output
supports output operations.

Operations are performed in binary mode rather


ios::binary binary
than text.

ios::ate at end The output position starts at the end of the file.

All output operations happen at the end of the file,


ios::app append
appending to its existing contents.

Any contents that existed in the file before it is


ios::trunk truncate
open are discarded.

Do not
ios::nocreate Does not allow to create new file if it does not exist.
create

Do not
ios::noreplace Does not replace old file with new file.
replace

File Handling:
Purpose: Deals with reading from and writing to files on your computer.
Operations: Opening files, reading data, writing data, closing files.
Common Use Cases:
Storing and retrieving data from files (e.g., text files, CSV files).
Logging information.
Reading configuration files.
Example (Python):
Python
with open("myfile.txt", "r") as f:
content = f.read()
Exception Handling:
Purpose:
Gracefully handles errors and unexpected situations that might occur during program
execution.
Mechanism:
Uses try-except blocks (or similar constructs in different languages) to catch
exceptions and handle them appropriately.
Benefits:
Prevents program crashes.
Provides meaningful error messages.
Allows for recovery from errors or graceful termination.
Example (Python):
Python
Execution output
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
Cannot divide by zero!
String Handling:
Purpose: Manipulates strings (sequences of characters) to perform various operations.
Operations: Concatenation, splitting, searching, replacing, formatting, etc.
Common Use Cases:
Text processing.
Data cleaning.
Parsing data.
Example (Python):
Python
Execution output
name = "Alice"
greeting = "Hello, " + name + "!"
print(greeting)
Hello, Alice!
Key Differences:
Focus:
File handling deals with files, exception handling deals with errors, and string
handling deals with strings.
Functionality:
Each provides different operations and capabilities specific to its domain.
Interaction:
These concepts can be used together. For example, you might use exception handling
while reading data from a file, or you might manipulate strings read from a file.
EXCEPTION HANDLING IN C++
In C++, exceptions are runtime anomalies or abnormal conditions that a program
encounters during its execution. The process of handling these exceptions is called
exception handling. Using the exception handling mechanism, the control from one part
of the program where the exception occurred can be transferred to another part of the
code.
So basically using exception handling in C++, we can handle the exceptions so that our
program keeps running.
What is a C++ Exception?
An exception is an unexpected problem that arises during the execution of a program
our program terminates suddenly with some errors/issues. Exception occurs during the
running of the program (runtime).
Types of C++ Exception
There are two types of exceptions in C++
Synchronous: Exceptions that happen when something goes wrong because of a
mistake in the input data or when the program is not equipped to handle the current
type of data it’s working with, such as dividing a number by zero.
Asynchronous: Exceptions that are beyond the program’s control, such as disc failure,
keyboard interrupts, etc.
C++ try and catch
C++ provides an inbuilt feature for Exception Handling. It can be done using the
following specialized keywords: try, catch, and throw with each having a different
purpose.
Syntax of try-catch in C++
try {
// Code that might throw an exception
throw SomeExceptionType("Error message");
}
catch( ExceptionName e1 ) {
// catch block catches the exception that is thrown from try block
}
1. try in C++
The try keyword represents a block of code that may throw an exception placed inside
the try block. It’s followed by one or more catch blocks. If an exception occurs, try block
throws that exception.
2. catch in C++
The catch statement represents a block of code that is executed when a particular
exception is thrown from the try block. The code to handle the exception is written
inside the catch block.
3. throw in C++
An exception in C++ can be thrown using the throw keyword. When a program
encounters a throw statement, then it immediately terminates the current function and
starts finding a matching catch block to handle the thrown exception.
Note: Multiple catch statements can be used to catch different type of exceptions thrown
by try block.
The try and catch keywords come in pairs: We use the try block to test some code and If
the code throws an exception we will handle it in our catch block.
To understand how to handle exceptions and write robust code, our Complete C++
Course offers comprehensive lessons on exception handling and other error-handling
mechanisms.
Why do we need Exception Handling in C++?
The following are the main advantages of exception handling over traditional error
handling:
Separation of Error Handling Code from Normal Code: There are always if-else
conditions to handle errors in traditional error handling codes. These conditions and
the code to handle errors get mixed up with the normal flow. This makes the code less
readable and maintainable. With try/catch blocks, the code for error handling becomes
separate from the normal flow.

Functions/Methods can handle only the exceptions they choose: A function can
throw many exceptions, but may choose to handle some of them. The other exceptions,
which are thrown but not caught, can be handled by the caller. If the caller chooses not
to catch them, then the exceptions are handled by the caller of the caller.
In C++, a function can specify the exceptions that it throws using the throw keyword.
The caller of this function must handle the exception in some way (either by specifying
it again or catching it).

Grouping of Error Types: In C++, both basic types and objects can be thrown as
exceptions. We can create a hierarchy of exception objects, group exceptions in
namespaces or classes, and categorize them according to their types.
Examples of Exception Handling in C++
The following examples demonstrate how to use a try-catch block to handle exceptions
in C++.
// C++ program to demonstate the use of try,catch and throw
// in exception handling.
#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
// try block
try {
int numerator = 10
int denominator = 0; int res;
// check if denominator is 0 then throw runtime
// error
if (denominator == 0) {
throw runtime_error(
"Division by zero not allowed!");
}
// calculate result if no exception occu
res = numerator / denominator;
//[printing result after division
cout << "Result after division: " << res << endl;
}
// catch block to catch the thrown exception
catch (const exception& e) {
//print the exception
cout << "Exception " << e.what() << endl;
}
return 0;
}
Output
Exception Division by zero not allowed!
STRING HANDLING IN C++
C++ strings are sequences of characters stored in a char array. Strings are used to store
words and text. They are also used to store data, such as numbers and other types of
information. Strings in C++ can be defined either using the std::string class or the C-
style character arrays.
1. C Style Strings
These strings are stored as the plain old array of characters terminated by a null
character ‘\0’. They are the type of strings that C++ inherited from C language.
Syntax:
char str[] = "GeeksforGeeks";
Example:
// C++ Program to demonstrate strings
#include <iostream>
using namespace std;
int main()
{
char s[] = "GeeksforGeeks";
cout << s << endl;
return 0;
}
Output
GeeksforGeeks
2. std::string Class
These are the new types of strings that are introduced in C++ as std::string class defined
inside <string> header file. This provides many advantages over conventional C-style
strings such as dynamic size, member functions, etc.
Syntax:
std::string str("GeeksforGeeks");
Example:
// C++ program to create std::string objects
#include <iostream>
using namespace std;
int main()
{
string str("GeeksforGeeks");
cout << str;
return 0;
}
Output
GeeksforGeeks
One more way we can make strings that have the same character repeating again and
again.
Syntax:
std::string str(number,character);
Example:
#include <iostream>
using namespace std;
int main()
{
string str(5, 'g');
cout << str;
return 0;
}
Output:
ggggg
Ways to Define a String in C++
Strings can be defined in several ways in C++. Strings can be accessed from the standard
library using the string class. Character arrays can also be used to define strings. String
provides a rich set of features, such as searching and manipulating, which are
commonly used methods. Despite being less advanced than the string class, this method
is still widely used, as it is more efficient and easier to use. Ways to define a string in C+
+ are:
Using String keyword
Using C-style strings
1. Using string Keyword
It is more convenient to define a string with the string keyword instead of using the
array keyword because it is easy to write and understand.
Syntax:
string s = "GeeksforGeeks";
string s("GeeksforGeeks");
Example:
// C++ Program to demonstrate use of string keyword
#include <iostream
using namespace std;
int main()
{
string s = "GeeksforGeeks";
string str("GeeksforGeeks");
cout << "s = " << s << endl;
cout << "str = " << str << endl;
return 0;

}
Output
s = GeeksforGeeks
str = GeeksforGeeks
2. Using C-style strings
Using C-style string libraries functions such as strcpy(), strcmp(), and strcat() to define
strings. This method is more complex and not as widely used as the other two, but it can
be useful when dealing with legacy code or when you need performance.
char s[] = {'g', 'f', 'g', '\0'};
char s[4] = {'g', 'f', 'g', '\0'};
char s[4] = "gfg";
char s[] = "gfg";
Example:
// C++ Program to demonstrate C-style string declaration
#include <iostream
using namespace std;
int main()
{
char s1[] = { 'g', 'f', 'g', '\0' };
char s2[4] = { 'g', 'f', 'g', '\0' };
char s3[4] = "gfg";
char s4[] = "gfg";
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << end
cout << "s3 = " << s3 << endl;
cout << "s4 = " << s4 << endl;
return 0;
}
Output
s1 = gfg
s2 = gfg
s3 = gfg
s4 = gfg

You might also like