Computer Concepts and Programming in 'C' (MCA - 103)
Computer Concepts and Programming in 'C' (MCA - 103)
AND PROGRAMMING IN C
MCA 103
SELF LEARNING MATERIAL
DIRECTORATE
OF DISTANCE EDUCATION
1
SLM Module Developed By :
Author:
Reviewed by :
Assessed by:
Study Material Assessment Committee, as per the SVSU ordinance No. VI (2)
DISCLAIMER
No part of this publication which is material protected by this copyright notice may be reproduced
or transmitted or utilized or stored in any form or by any means now known or hereinafter invented,
electronic, digital or mechanical, including photocopying, scanning, recording or by any information
storage or retrieval system, without prior permission from the publisher.
Information contained in this book has been published by Directorate of Distance Education and has
been obtained by its authors from sources be lived to be reliable and are correct to the best of their
knowledge. However, the publisher and its author shall in no event be liable for any errors,
omissions or damages arising out of use of this information and specially disclaim and implied
warranties or merchantability or fitness for any particular use.
2
COMPUTER CONCEPTS AND PROGRAMMING IN C (MCA-103)
UNIT 1:
Introduction to any Operating System [Unix, Linux, Windows], Programming
Environment, Write and Execute the first program, Introduction to the Digital Computer;
Concept of an algorithm; termination and correctness. Algorithms to programs:
specification, top-down development and stepwise refinement. Introduction to
Programming, Use of high level programming language for the systematic development
of programs. Introduction to the design and implementation of correct, efficient and
maintainable programs, Structured Programming, Trace an algorithm to depict the logic,
Number Systems and conversion methods
UNIT 2:
Standard I/O in ―C‖, Fundamental Data Types and Storage Classes: Character types,
Integer, short, long, unsigned, single and double-precision floating point, storage
classes, automatic, register, static and external, Operators and Expressions: Using
numeric and relational operators, mixed operands and type conversion, Logical
operators, Bit operations, Operator precedence and associativity,
UNIT 3:
Conditional Program Execution: Applying if and switch statements, nesting if and else,
restrictions on switch values, use of break and default with switch, Program Loops and
Iteration: Uses of while, do and for loops, multiple loop variables, assignment operators,
using break and continue, Modular Programming: Passing arguments by value, scope
rules and global variables, separate compilation, and linkage, building your own
modules.
UNIT 4:
Arrays: Array notation and representation, manipulating array elements, using
multidimensional arrays, arrays of unknown or varying size, Structures: Purpose and
usage of structures, declaring structures, assigning of structures, Pointers to Objects:
Pointer and address arithmetic, pointer operations and declarations, using pointers as
function arguments, Dynamic memory allocation, defining and using stacks and linked
lists.
UNIT 5:
Sequential search, Sorting arrays, Strings, Text files, The Standard C Preprocessor:
Defining and calling macros, utilizing conditional compilation, passing values to the
compiler, The Standard C Library: Input/Output : fopen, fread, etc, string handling
functions, Math functions : log, sin, alike Other Standard C functions.
3
UNIT 1:
Unix:- UNIX is an operating system which was first developed in the 1960s, and has
been under constant development ever since. By operating system, we mean the suite
of programs which make the computer work. It is a stable, multi-user, multi-tasking
system for servers, desktops and laptops.
UNIX systems also have a graphical user interface (GUI) similar to Microsoft Windows
which provides an easy to use environment. However, knowledge of UNIX is required
for operations which aren't covered by a graphical program, or for when there is no
windows interface available, for example, in a telnet session.
Types of UNIX
There are many different versions of UNIX, although they share common
similarities. The most popular varieties of UNIX are Sun Solaris,
GNU/Linux, and MacOS X.
Here in the School, we use Solaris on our servers and workstations, and
Fedora Linux on the servers and desktop PCs.
The UNIX operating system is made up of three parts; the kernel, the shell and the
programs.
The kernel
The kernel of UNIX is the hub of the operating system: it allocates time and memory to
programs and handles the filestore and communications in response to system calls.
As an illustration of the way that the shell and the kernel work together, suppose a user
types rm myfile (which has the effect of removing the file myfile). The shell searches
the filestore for the file containing the program rm, and then requests the kernel,
through system calls, to execute the program rm on myfile. When the process rm
4
myfile has finished running, the shell then returns the UNIX prompt % to the user,
indicating that it is waiting for further commands.
The shell
The shell acts as an interface between the user and the kernel. When a user logs in,
the login program checks the username and password, and then starts another
program called the shell. The shell is a command line interpreter (CLI). It interprets the
commands the user types in and arranges for them to be carried out. The commands
are themselves programs: when they terminate, the shell gives the user another prompt
(% on our systems).
The adept user can customise his/her own shell, and users can use different shells on
the same machine. Staff and students in the school have the tcsh shell by default.
The tcsh shell has certain features to help the user inputting commands.
History - The shell keeps a list of the commands you have typed in. If you need to
repeat a command, use the cursor keys to scroll up and down the list or type history for
a list of previous commands.
A file is a collection of data. They are created by users using text editors, running
compilers etc.
Examples of files:
5
a document (report, essay etc.)
All the files are grouped together in the directory structure. The file-system is arranged
in a hierarchical structure, like an inverted tree. The top of the hierarchy is traditionally
called root (written as a slash / )
In the diagram above, we see that the home directory of the undergraduate
student "ee51vn" contains two sub-directories (docs and pics) and a file
called report.doc.
6
Starting an UNIX terminal
An UNIX Terminal window will then appear with a % prompt, waiting for you to start
entering commands.
7
Linux
Every time you switch on your computer, you see a screen where you can perform
different activities like write, browse the internet or watch a video. What is it that makes
8
the computer hardware work like that? How does the processor on your computer know
that you are asking it to run a mp3 file?
Well, it is the operating system or the kernel which does this work. So, to work on your
computer, you need an Operating System(OS). In fact, you are using one as you read
this on your computer. Now, you may have used popular OS's like Windows, Apple OS
X, but here we will learn introduction to Linux operating system, Linux overview and
what benefits it offers over other OS choices.
However, when his suggestions were rejected by the designers of UNIX, he thought of
launching an OS which will be receptive to changes, modifications suggested by its
users.
So Linus devised a Kernel named Linux in 1991. Though he would need programs like
File Manager, Document Editors, Audio -Video programs to run on it. Something as you
have a cone but no ice-cream on top.
As time passed by, he collaborated with other programmers in places like MIT and
applications for Linux started to appear. So around 1991, a working Linux operating
system with some applications was officially launched, and this was the start of one of
the most loved and open-source OS options available today.
The earlier versions of Linux OS were not so user-friendly as they were in use by
computer programmers and Linus Torvalds never had it in mind to commercialize his
product.
This definitely curbed the Linux's popularity as other commercially oriented Operating
System Windows got famous. Nonetheless, the open-source aspect of the Linux
operating system made it more robust.
9
The main advantage of Linux was that programmers were able to use the Linux Kernel
to design their own custom operating systems. With time, a new range of user-friendly
OS's stormed the computer world. Now, Linux is one of the most popular and widely
used Kernel, and it is the backbone of popular operating systems like Debian, Knoppix,
Ubuntu, and Fedora. Nevertheless, the list does not end here as there are thousands of
Best versions of Linux OS based on the Linux Kernel available which offer a variety of
functions to the users.
Linux Kernel is normally used in combination of GNU project by Dr. Richard Stallman.
All mordern distributions of Linux are actually distributions of Linux/GNU
Linux OS now enjoys popularity at its prime, and it's famous among programmers as
well as regular computer users around the world. Its main benefits are -
It offers a free operating system. You do not have to shell hundreds of dollars to get
the OS like Windows!
10
Being open-source, anyone with programming knowledge can modify it.
Once you have Linux installed you no longer need an antivirus! Linux is a highly
secure system. More so, there is a global development community constantly
looking at ways to enhance its security. With each upgrade, the OS becomes
more secure and robust
Linux freeware is the OS of choice for Server environments due to its stability
and reliability (Mega-companies like Amazon, Facebook, and Google use Linux
for their Servers). A Linux based server could run non-stop without a reboot for
years on end.
Users, who are new to Linux, usually shun it by falsely considering it as a difficult
and technical OS to operate but, to state the truth, in the last few years Linux
operating systems have become a lot more user-friendly than their counterparts
like Windows, so trying them is the best way to know whether Linux suits you or
not.
There are thousands of Best Linux OSs and Linux softwares available based on
the Linux Kernel; most of them offer state-of-the-art security and applications, all
of it for free!
This is what Linux is all about, and now we will move on to how to install
Linux and which Distribution you should choose.
UNIX is called the mother of operating systems which laid out the foundation to
Linux. Unix is designed mainly for mainframes and is in enterprises and
universities. While Linux is fast becoming a household name for computer users,
developers, and server environment. You may have to pay for a Unix kernel
while in Linux it is free.
But, the commands used on both the operating systems are usually the
same. There is not much difference between UNIX and Linux. Though they might
seem different, at the core, they are essentially the same. Since Linux is a clone
of UNIX. So learning one is same as learning another.
Windows
11
The oldest of all Microsoft‘s operating systems is MS-DOS (Microsoft Disk Operating
System). MS-DOS is a text-based operating system. Users have to type commands
rather than use the more friendly graphical user interfaces (GUI‘s) available today.
Despite its very basic appearance, MS-DOS is a very powerful operating system. There
are many advanced applications and games available for MS-DOS. A version of MS-
DOS underpins Windows. Many advanced administration tasks in Windows can only be
performed using MS-DOS.
The history of Microsoft Windows dates back to 1985, when Microsoft released
Microsoft Windows Version 1.01. Microsoft‘s aim was to provide a friendly user-interface
known as a GUI (graphical user interface) which allowed for easier navigation of the
system features. Windows 1.01 never really caught on. (The amazing thing about
Windows 1.01 is that it fitted on a single floppy disk!). In 1987 Microsoft revamped the
operating system and released Windows 2.03. The GUI was very slightly improved but
still looked too similar to Windows 1.01. The operating system again failed to capture a
wide audience.
Microsoft made an enormous impression with Windows 3.0 and 3.1. Graphics and
functionality were drastically improved. The Windows 3.x family provided multimedia
capabilities as well as vastly improved graphics and application support.
Building on the success of Windows 3.x, Microsoft released Microsoft Windows For
Workgroups 3.11. This gave Windows the ability to function on a network. It is not
uncommon to find companies still using Windows 3.11.
In 1993 Microsoft divided the operating system into two categories; Business and home
user. Windows NT (New Technology) was a lot more reliable than Windows 3.x.
Windows NT provided advanced network features. On the business front, Windows NT
continued to develop with the release of version 3.51. Different versions were provided
which offered different functionality. Server provided the higher network functions and
Workstation was mainly for the client machines.
In 1995 Windows went through a major revamp and Microsoft Windows 95 was
released. This provided greatly improved multimedia and a much more polished user
interface. The now familiar desktop and Start Menu appeared. Internet and networking
support was built in Although Windows 95 was a home user operating system, it proved
to be very popular in schools and businesses.
After the success of Windows 95, Microsoft improved the GUI interface of Windows NT
and released Windows NT 4.0. NT4 could be tailored to the size of the business, NT4
Server for small to medium sized businesses and Enterprise Server for larger networks.
Microsoft continued to improve the Windows format. Although Microsoft Windows 98
was very similar to Windows 95, it offered a much tidier display and enhanced
multimedia support.
Breaking with its own naming conventions, Microsoft released Windows 2000 (initially
called NT 5.0) for the business market. It appeared in 4 models: Professional -which
12
replaced Workstation, Server, Advanced Server and Datacenter Server catered for
differing business requirements.
Although Windows 2000 had a greatly improved user interface, the best of the
enhancements appeared on the server side. Active Directory was introduced which
allowed much greater control of security and organisation. Improvements to the overall
operating system allowed for easier configuration and installation.
One big advantage of Windows 2000 was that operating system settings could be
modified easily without the need to restart the machine. Windows 2000 proved to be a
very stable operating system that offered enhanced security and ease of administration.
The last incarnation of the Windows 9x family was Windows Millennium Edition (ME).
There were many different versions of Windows floating around at this stage that
Microsoft decided the next release of Windows would consolidate both the business and
home versions. Although Windows ME was visually similar to Windows 2000. Windows
ME was based on the Windows 9x line. Windows 9x/ME systems are not as secure and
stable as Windows NT and 2000 systems.
Because of the stability of Windows NT/2000, Microsoft decided to end the development
of the Windows 9x line, and merge both the consumer and business products. Microsoft
Windows XP comes as the Home Edition and Professional, each is based on Windows
2000. Windows 2000 Server has been upgraded to Windows 2003. This appears in four
variants: Web Server, Standard Server, Enterprise Server and Datacenter Server, each
fulfilling a different business role. Windows XP has a very polished look, but the overall
functionality is very similar to Windows 2000.
Programming Environment
Managing Data
13
For more information about the GT.M data management system, refer to the "Global
Directory Editor", "MUPIP" and "GT.M Journaling" chapters in the GT.M Administration
and Operations Guide.
Database Management Utilities
The Global Directory Editor (GDE) creates, modifies, maintains, and displays the
characteristics of Global Directories. GDE also maps LOCKs on resource names to the
region of the database specified for the corresponding global variables.
The M Peripheral Interchange Program (MUPIP) creates database files and provides
tools for GT.M database management and database journaling.
For more information regarding GT.M database utilities, refer to the "Global Directory
Editor", "MUPIP" and "GT.M Journaling" chapters in the GT.M Administration and
Operations Guide.
In the GT.M programming environment, source routines are generated and stored as
standard UNIX files. They are created and edited with standard UNIX text editors. GT.M
accepts source lines of up to 8192 bytes. When GT.M encounters a line with a length
greater than 8192 bytes in a source file, it emits an LSEXPECTED warning. This
warning identifies cases where a line greater than 8192 bytes is split into multiple lines,
which causes statements beyond the character prior to the limit to execute irrespective
of any starting IF, ELSE or FOR commands. The 8192 byte limit applies to XECUTE
command arguments and Direct Mode input as well.
GT.M is designed to work with the operating system utilities and enhances them when
beneficial. The following sections describe the process of programming and debugging
with GT.M and from the operating system.
Source File Management
In addition to standard M "percent" utilities, GT.M permits the use of the standard UNIX
file manipulation tools, for example, the diff, grep, cp, and mv commands. The GT.M
programmer can also use the powerful facilities provided by the UNIX directory
structure, such as time and date information, tree-structured directories, and file
protection codes.
GT.M programs are compatible with most source management software, for example,
RCS and SCCS.
Programming and Debugging Facilities
The GT.M programmer can use any UNIX text editor to create M source files. If you
generate a program from within the Direct Mode, it also accesses the UNIX text editor
specified by the environment variable EDITOR and provides additional capabilities to
automate and enhance the process.
14
The GT.M programmer also uses the Direct Mode facility to interactively debug, modify,
and execute M routines. In Direct Mode, GT.M executes each M command immediately,
as if it had been in-line at the point where GT.M initiated Direct Mode.
The following is a list of additional enhancements available from the Direct Mode:
The capability to issue commands from Direct Mode to the shell
A command recall function to display and reuse previously entered commands
Many language extensions that specifically optimize the debugging environment
The GT.M Compiler
The GT.M compiler operates on source files to produce object files consisting of
position-independent, native object code, which on some platforms can be linked into
shared object libraries. GT.M provides syntax error checking at compile-time and allows
you to enable or disable the compile-as-written mode. By default, GT.M produces an
object file even if the compiler detects errors in the source code. This compile-as-written
mode facilitates a flexible approach to debugging.
The Run-Time System
A GT.M programmer can execute an M routine from the shell or interactively, using the
M commands from Direct Mode.
The run-time system executes compile-as-written code as long as it does not encounter
the compile-time errors. If it detects an error, the run-time system suspends execution of
a routine immediately and transfers control to Direct Mode or to a user-written error
routine.
Automatic and Incremental Linking
The run-time system utilizes a GT.M facility called ZLINK to link in an M routine. When a
program or a Direct Mode command refers to an M routine that is not part of the current
process, GT.M automatically uses the ZLINK facility and attempts to link the referenced
routine (auto-ZLINK). The ZLINK facility also determines whether recompilation of the
routine is necessary. When compiling as a result of a ZLINK, GT.M typically ignores
errors in the source code.
The run-time system also provides incremental linking. The ZLINK command adds an M
routine to the current image. This feature facilitates the addition of code modifications
during a debugging session. The GT.M programmer can also use the feature to add
patches and generated code to a running M process.
Error Processing
The GT.M compiler detects and reports syntax errors at the following times:
o Compile-time - while producing the object module from a source file
15
o Run-time - while compiling code for M indirection and XECUTEs
o Run-time - when the user is working in Direct Mode.
The compile-time error message format displays the line containing the error and the
location of the error on the line. The error message also indicates what was incorrect
about the M statement.
GT.M can not detect certain types of errors associated with indirection, the functioning
of I/O devices, and program logic until run-time.
The compile-as-written feature allows compilation to continue and produces an object
module despite errors in the code. This permits testing of other pathways through the
code. The errors are reported at run-time, when GT.M encounters them in the execution
path.
The GT.M run-time system recognizes execution errors and reports them when they
occur. It also reports errors flagged by the compiler when they occur in the execution
path.
For more information, see Chapter 13: ―Error Processing‖.
Input-Output Processing
GT.M supports input and output processing with the following system components:
Terminals
Sequential disk files
Mailboxes
FIFOs
Null devices
Socket devices
GT.M input/output processing is device-independent. Copying information from one
device to another is accomplished without reformatting.
GT.M has special terminal-handling facilities. GT.M performs combined QIO operations
to enhance terminal performance. The terminal control facilities that GT.M provides
include escape sequences, control character traps, and echo suppression.
GT.M supports RMS sequential disk files that are accessed using a variety of
deviceparameters.
GT.M supports block I/O with fixed and variable length records for file-structured
(FILES-11) tapes and non-file-structured unlabeled (FOREIGN) tapes. GT.M supports
the ASCII character set for unlabeled FOREIGN and FILES-11 tapes. GT.M supports
16
the EBCDIC character set for FOREIGN tapes only. GT.M also supports FOREIGN
DOS-11 and ANSI labelled tapes or stream format records. It also supports ASCII and
EBCDIC character sets.
GT.M uses permanent or temporary mailboxes fifos for interprocess communication.
GT.M treats mailboxes as record-structured I/O devices.
GT.M provides the ability to direct output to a null device. This is an efficient way to
discard unwanted output.
GT.M provides device-exception processing so that I/O exception handling need not be
combined with process-related exception conditions. The OPEN, USE, and CLOSE
EXCEPTION parameters define an XECUTE string as an error handler for an I/O
device.
GT.M offers capabilities that allow you to optimize your programming environment.
These include allowing you to call into M routines from programs written in other
programming languages, access your M databases with interfaces that provide
functionality equivalent to M intrinsic database functions, and to alter your programming
environment when working with languages other than American English. These include
allowing you to call programs written in other programming languages that support C-
like interfaces and to alter your programming environment when working with languages
other than American English. This capability is described in more detail in chapters
throughout this manual.
GT.M routines can call external (non-M) routines using the external call function. This
permits access to functions implemented in other programming languages. For more
information, see Chapter 11: ―Integrating External Routines‖.
Internationalization
GT.M allows the definition of alternative collation sequences and pattern matching
codes for use with languages other than English. Chapter 12:
―Internationalization‖ describes the details and requirements of this functionality.
Write and Execute the first program
17
Learning Node.js will allow you to write your front-end code and your back-end code in
the same language. Using JavaScript throughout your entire stack can help reduce time
for context switching, and libraries are more easily shared between your back-end
server and front-end projects.
Also, thanks to its support for asynchronous execution, Node.js excels at I/O-intensive
tasks, which is what makes it so suitable for the web. Real-time applications, like video
streaming, or applications that continuously send and receive data, can run more
efficiently when written in Node.js.
In this tutorial you‘ll create your first program with the Node.js runtime. You‘ll be
introduced to a few Node-specific concepts and build your way up to create a program
that helps users inspect environment variables on their system. To do this, you‘ll learn
how to output strings to the console, receive input from the user, and access
environment variables.
Prerequisites
To complete this tutorial, you will need:
A basic knowledge of JavaScript, which you can find here: How To Code in
JavaScript.
nano hello.js
Copy
With the text editor opened, enter the following code:
hello.js
console.log("Hello World");
Copy
18
The console object in Node.js provides simple methods to write to stdout, stderr, or to
any other Node.js stream, which in most cases is the command line. The log method
prints to the stdout stream, so you can see it in your console.
In the context of Node.js, streams are objects that can either receive data, like
the stdout stream, or objects that can output data, like a network socket or a file. In the
case of the stdout and stderr streams, any data sent to them will then be shown in the
console. One of the great things about streams is that they‘re easily redirected, in which
case you can redirect the output of your program to a file, for example.
Save and exit nano by pressing CTRL+X, when prompted to save the file, press Y. Now
your program is ready to run.
node hello.js
Copy
The hello.js program will execute and display the following output:
Output
Hello World
The Node.js interpreter read the file and executed console.log("Hello World"); by calling
the log method of the global console object. The string "Hello World" was passed as an
argument to the log function.
Although quotation marks are necessary in the code to indicate that the text is a string,
they are not printed to the screen.
Having confirmed that the program works, let‘s make it more interactive.
Command line tools often accept various arguments that modify their behavior. For
example, running node with the --version argument prints the installed version instead
of running the interpreter. In this step, you will make your code accept user input via
command line arguments.
19
Create a new file arguments.js with nano:
nano arguments.js
Copy
Enter the following code:
arguments.js
console.log(process.argv);
Copy
The process object is a global Node.js object that contains functions and data all related
to the currently running Node.js process. The argv property is an array of strings
containing all the command line arguments given to a program.
Save and exit nano by typing CTRL+X, when prompted to save the file, press Y.
Now when you run this program, you provide a command line argument like this:
Output
[ '/usr/bin/node',
'/home/sammy/first-program/arguments.js',
'hello',
'world' ]
The first argument in the process.argv array is always the location of the Node.js binary
that is running the program. The second argument is always the location of the file
being run. The remaining arguments are what the user entered, in this
case: hello and world.
We are mostly interested in the arguments that the user entered, not the default ones
that Node.js provides. Open the arguments.js file for editing:
nano arguments.js
Copy
Change console.log(process.arg); to the following:
arguments.js
20
console.log(process.argv.slice(2));
Copy
Because argv is an array, you can use JavaScript‘s built-in slice method that returns a
selection of elements. When you provide the slice function with 2 as its argument, you
get all the elements of argv that comes after its second element; that is, the arguments
the user entered.
Re-run the program with the node command and the same arguments as last time:
Output
[ 'hello', 'world' ]
Now that you can collect input from the user, let‘s collect input from the program‘s
environment.
nano environment.js
Copy
Add the following code:
environment.js
console.log(process.env);
Copy
The env object stores all the environment variables that are available when Node.js is
running the program.
Save and exit like before, and run the environment.js file with the node command.
node environment.js
21
Copy
Upon running the program, you should see output similar to the following:
Output
{ SHELL: '/bin/bash',
SESSION_MANAGER:
'local/digitalocean:@/tmp/.ICE-unix/1003,unix/digitalocean:/tmp/.ICE-unix/1003',
COLORTERM: 'truecolor',
SSH_AUTH_SOCK: '/run/user/1000/keyring/ssh',
XMODIFIERS: '@im=ibus',
DESKTOP_SESSION: 'ubuntu',
SSH_AGENT_PID: '1150',
PWD: '/home/sammy/first-program',
LOGNAME: 'sammy',
GPG_AGENT_INFO: '/run/user/1000/gnupg/S.gpg-agent:0:1',
GJS_DEBUG_TOPICS: 'JS ERROR;JS LOG',
WINDOWPATH: '2',
HOME: '/home/sammy',
USERNAME: 'sammy',
IM_CONFIG_PHASE: '2',
LANG: 'en_US.UTF-8',
VTE_VERSION: '5601',
CLUTTER_IM_MODULE: 'xim',
GJS_DEBUG_OUTPUT: 'stderr',
LESSCLOSE: '/usr/bin/lesspipe %s %s',
TERM: 'xterm-256color',
LESSOPEN: '| /usr/bin/lesspipe %s',
USER: 'sammy',
DISPLAY: ':0',
SHLVL: '1',
PATH:
'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sn
ap/bin',
DBUS_SESSION_BUS_ADDRESS: 'unix:path=/run/user/1000/bus',
_: '/usr/bin/node',
OLDPWD: '/home/sammy' }
22
Keep in mind that many of the environment variables you see are dependent on the
configuration and settings of your system, and your output may look substantially
different than what you see here. Rather than viewing a long list of environment
variables, you might want to retrieve a specific one.
The process.env object is a simple mapping between environment variable names and
their values stored as strings. Like all objects in JavaScript, you access an individual
property by referencing its name in square brackets.
nano environment.js
Copy
Change console.log(process.env); to:
environment.js
console.log(process.env["HOME"]);
Copy
Save the file and exit. Now run the environment.js program:
node environment.js
Copy
The output now looks like this:
Output
/home/sammy
Instead of printing the entire object, you now only print the HOME property
of process.env, which stores the value of the $HOME environment variable.
Again, keep in mind that the output from this code will likely be different than what you
see here because it is specific to your system. Now that you can specify the
environment variable to retrieve, you can enhance your program by asking the user for
the variable they want to see.
23
Next, you‘ll use the ability to read command line arguments and environment variables
to create a command line utility that prints the value of an environment variable to the
screen.
nano echo.js
Copy
Add the following code:
echo.js
const args = process.argv.slice(2);
console.log(process.env[args[0]]);
Copy
The first line of echo.js stores all the command line arguments that the user provided
into a constant variable called args. The second line prints the environment variable
stored in the first element of args; that is, the first command line argument the user
provided.
Output
/home/sammy
The argument HOME was saved to the args array, which was then used to find its value
in the environment via the process.env object.
At this point you can now access the value of any environment variable on your system.
To verify this, try viewing the following variables: PWD, USER, PATH.
Retrieving single variables is good, but letting the user specify how many variables they
want would be better.
24
Step 7 — Viewing Multiple Environment Variables
Currently, the application can only inspect one environment variable at a time. It would
be useful if we could accept multiple command line arguments and get their
corresponding value in the environment. Use nano to edit echo.js:
nano echo.js
Copy
Edit the file so that it has the following code instead:
echo.js
const args = process.argv.slice(2);
args.forEach(arg => {
console.log(process.env[arg]);
});
Copy
The forEach method is a standard JavaScript method on all array objects. It accepts
a callback function that is used as it iterates over every element of the array. You
use forEach on the args array, providing it a callback function that prints the current
argument‘s value in the environment.
Save and exit the file. Now re-run the program with two arguments:
Output
/home/sammy
/home/sammy/first-program
The forEach function ensures that every command line argument in the args array is
printed.
Now you have a way to retrieve the variables the user asks for, but we still need to
handle the case where the user enters bad data.
25
node echo.js HOME PWD NOT_DEFINED
Copy
The output will look similar to the following:
Output
/home/sammy
/home/sammy/first-program
undefined
The first two lines print as expected, and the last line only has undefined. In JavaScript,
an undefined value means that a variable or property has not been assigned a value.
Because NOT_DEFINED is not a valid environment variable, it is shown as undefined.
It would be more helpful to a user to see an error message if their command line
argument was not found in the environment.
nano echo.js
Copy
Edit echo.js so that it has the following code:
echo.js
const args = process.argv.slice(2);
args.forEach(arg => {
let envVar = process.env[arg];
if (envVar === undefined) {
console.error(`Could not find "${arg}" in environment`);
} else {
console.log(envVar);
}
});
Copy
Here, you have modified the callback function provided to forEach to do the following
things:
1. Get the command line argument‘s value in the environment and store it in a
variable envVar.
2. Check if the value of envVar is undefined.
26
3. If the envVar is undefined, then we print a helpful message indicating that it could not be
found.
4. If an environment variable was found, we print its value.
Note: The console.error function prints a message to the screen via the stderr stream,
whereas console.log prints to the screen via the stdout stream. When you run this
program via the command line, you won‘t notice the difference between
the stdout and stderr streams, but it is good practice to print errors via the stderr stream
so that they can be easier identified and processed by other programs, which can tell
the difference.
Output
/home/sammy
/home/sammy/first-program
Could not find "NOT_DEFINED" in environment
Now when you provide a command line argument that‘s not an environment variable,
you get a clear error message stating so.
Conclusion
Your first program displayed ―Hello World‖ to the screen, and now you have written a
Node.js command line utility that reads user arguments to display environment
variables.
If you want to take this further, you can change the behavior of this program even more.
For example, you may want to validate the command line arguments before you print. If
an argument is undefined, you can return an error, and the user will only get output if all
arguments are valid environment variables.
27
The first electronic digital computer was developed in the late 1940s and was used
primarily for numerical computations.
By convention, the digital computers use the binary number system, which has two
digits: 0 and 1. A binary digit is called a bit.
A computer system is subdivided into two functional entities: Hardware and Software.
The hardware consists of all the electronic components and electromechanical devices
that comprise the physical entity of the device.
The software of the computer consists of the instructions and data that the computer
manipulates to perform various data-processing tasks.
28
o The Central Processing Unit (CPU) contains an arithmetic and logic unit for
manipulating data, a number of registers for storing data, and a control circuit for
fetching and executing instructions.
o The memory unit of a digital computer contains storage for instructions and data.
o The Random Access Memory (RAM) for real-time processing of the data.
o The Input-Output devices for generating inputs from the user and displaying the
final results to the user.
o The Input-Output devices connected to the computer include the keyboard,
mouse, terminals, magnetic disk drives, and other communication devices.
Concept of an algorithm
Although nowadays algorithms are primarily associated with software and computers,
their origins lie much further in the past. They have been used intuitively for centuries,
for example in the form of regulatory systems, instructions, rules for games,
architectural plans and musical scores.
Even some illustrated art books in the Renaissance period, for example Albrecht
Dürer‘s ―Four Books on Measurement‖ in 1525, were in fact structured instructions for
producing paintings, sculptures and buildings. In the history of music, too, from Bach
and Mozart to Schönberg and Schillinger, we see mathematical methods and even
small mechanical devices being used to make the process of musical composition
easier.
But what exactly is meant by the term algorithm? Over time, the following descriptions
have emerged as definitions: ―An algorithm is a procedure for decision-making or an
instruction on how to act which consists of a finite number of rules‖ or ―… a limited
sequence of unambiguous elementary instructions which exactly and completely
describe the way to solve a specific problem.‖ This applies regardless of whether it
relates to mathematics, fine art or music.
29
However, the most well-known application of algorithms is undoubtedly their use in
computer programming. A program is an algorithm that is formulated in a language that
allows it to be processed by a computer. Every computer program – a more advanced
machine language – is therefore an algorithm. In this way, people pass the work of
processing the procedures required in production or decision-making – often
calculations requiring days or hours – to a machine.
30
However, because the English inventor, mathematician and philosopher never
managed to complete his mechanical computing machine for general applications in his
lifetime, the algorithm for it was also never implemented.
―The Babbage machine was never built because it was too unwieldy and complicated,
even though the software for it was formulated,‖ reports Dr Manuel Bachmann, a
researcher at the University of Basel and lecturer at the University of Lucerne, in his
book ―The triumph of the algorithm – how the idea of software was invented‖.
Nevertheless, other computing machines did see the light of day and, in parallel, more
and more precise programming became necessary.
In recent decades, algorithms have become a key aspect of information science and the
theory of complexity and computability, in particular. Any problem that can be
programmed can be resolved by an algorithm. Even the most complex things can be
calculated using ones and zeros.
That includes the ―Dream of Pythagoras‖ – the ability to explain the world in the
relationships between whole numbers, and the vision of Gottfried Wilhelm Leibniz that
all rational truths are based on a kind of calculus. This is all reflected in a digital
philosophy and a view of the world based on algorithms which found its most recent
formulation in a book called ―A New Kind of Science‖, written in 2002 by the British
physicist and mathematician, Stephen Wolfram.
*DÜRER (21 May 1471 – 6 April 1528) was a painter, printmaker, and theorist of the
German Renaissance. Born in Nuremberg, Dürer established his reputation and
influence across Europe when he was still in his twenties due to his high-quality
woodcut prints.
31
A distinction is made between partial correctness, which requires that if an answer is
returned it will be correct, and total correctness, which additionally requires that the
algorithm terminates. Since there is no general solution to the halting problem, total
correctness is not decidable. A termination proof is a type of mathematical proof that
plays a critical role in formal verification because total correctness of an algorithm
depends on termination.[2]
For example, successively searching through integers 1, 2, 3, … to see if we can find an
example of some phenomenon—say an odd perfect number—it is quite easy to write a
partially correct program (using factorization to calculate each integer's aliquot sum).
But to say this program is totally correct would be to assert something currently not
known in number theory.
A proof would have to be a mathematical proof, assuming both the algorithm and
specification are given formally. In particular it is not expected to be a correctness
assertion for a given program implementing the algorithm on a given machine. That
would involve such considerations as limitations on computer memory.
A deep result in proof theory, the Curry–Howard correspondence, states that a proof of
functional correctness in constructive logic corresponds to a certain program in
the lambda calculus. Converting a proof in this way is called program extraction.
Hoare logic is a specific formal system for reasoning rigorously about the correctness of
computer programs.[3] It uses axiomatic techniques to define programming language
semantics and argue about the correctness of programs through assertions known as
Hoare triples.
Software testing is any activity aimed at evaluating an attribute or capability of a
program or system and determining that it meets its required results. Although crucial to
software quality and widely deployed by programmers and testers, software testing still
remains an art, due to limited understanding of the principles of software. The difficulty
in software testing stems from the complexity of software: we can not completely test a
program with moderate complexity. Testing is more than just debugging. The purpose of
testing can be quality assurance, verification and validation, or reliability estimation.
Testing can be used as a generic metric as well. Correctness testing and reliability
testing are two major areas of testing. Software testing is a trade-off between budget,
time and quality.
Algorithms to programs:-
Specification
The concept of an algorithm is fundamental to computer science. Algorithms exist
for many common problems. and designing efficient algorithms plays a crucial role
in developing large-scale computer systems. Therefore. before we proceed further. we
discuss this concept more fully. We begin with a definition.
32
Definition:
.(4) Finiteness. If we trace out the instructions of an algorithm, then for all cases,
the algorithm terminates after a finite number of steps.
Example 1.2 [Selection sort]: Suppose we must devise a program that sorts a
collection of > integers. A simple solution is given by the following:
From those integers that are currently unsorted. find the smallest and place it next in the
sorted list.
33
To turn Program 1.5 into a real C++ program, two clearly defined subtasks
remain: finding the smallest integer and interchanging it with a [i]. We can solve the
latter,problem by using the code:
temp = a[i]; a[i] = a [j]; a[j] = temp;
The first subtask can be solved by assuming the minimum is a [i], checking a [i] with [i +
1], a [i + 2], … and whenever a smaller element is found, regarding it as the new.
34
If x has not. been found and there are still integers to check, we recalculate middle
and continue the search. The algorithm contains two subtasks: (1) determining if there
are any integers left to check and (2) comparing x to a[middle].
At this point you might try the method out on some sample numbers. This method is
referred to as binary search. Note h~w at each stage the number of elements in
the remaining set ‗is decreased by about one-half. Note also that at each stage, x is
compared with a [middle] and depending on whether x > a [middle], x < a [middle], or x
== a [middle ]; we do a different thing. To implement this in c++ we could use the if-
else construct:
if (x > a [middle]) …
else if (x < a [middle])
else …
From this construct it is not readily apparent that we are considering the three cases
that can result from the comparison between x and a [i]. To make the program more
transparent, we introduce a compare function that has value >, <, or =, depending on
the outcome of the comparison. This function is given in Program 1.7.
Program 1.7
We can now refine the description of binary search to get a pseudo-Cs+ function.
The result is given in Program 1.8.
35
Program 1.8
Another refinement yields the C++ function of Program 1.9.
Program 1.9
To prove this program correct we make assertions about the relationship between
variables before and after-the Cor loop of lines 4-11. As we enter this loop and if x is
present in a, the following holds:
left < right && a[left] < x < a[right] && SORTED (a, n)
Now, if control passes out of the for loop past line II, then we know the condition of line
4 is false, so left> right. This, combined with the above assertion, implies that x is not
present.
Unfortunately, a complete proof takes us beyond the scope of this text. but those who
wish to pursue program-proving should consult the references at the end of this chapter,
Recursive Algorithms
36
Similarly, in recursion, we write a function to produce an output (say n!) for some input
(here, n) by assuming that the same function will compute the correct output for input n
– I. In mathematical induction, we need a basis which can be directly proved (that is, the
proof for the basis does not make any assumptions). Similarly, a recursive function
requires a terminating condition. When the input to the function satisfies this terminating
condition, the function directly computes the output without calling itself.
What kinds of problems are best solved by recursion? Typically, beginning
programmers view recursion as a somewhat mystical technique that is useful only for
some very special class of problems (such as computing factorials or Ackermann‘s
function). This is unfortunate because any program that can be written using
assignment, the if-else statement, and the while statement can also be written using
assignment, if-else, and recursion. Of course, this does not mean that the resulting
program will necessarily be easier to understand. However, there are many instances
when this will be the case. When is recursion an appropriate mechanism for algorithm
exposition? One instance is when the problem itself is recursively defined. Factorial fits
this category, as well as binomial coefficients where
We use two examples to show you how to develop a recursive algorithm. In the first
example, we take the binary search function that we created in Example 1.3
and transform it into a recursive function. In the second example, we generate all
possible permutations of a list of characters. To understand a recursive function, you
must.
(1) Formulate in your mind a statement of what it is that the function is supposed to do,
for a given input.
(2) Verify that the function does achieve its goal if the recursive invocations to itself do
what they are supposed to.
(3) Ensure that a finite number of recursive invocations of the function eventually lead to
an invocation which satisfies the terminating condition (otherwise, the function will keep
calling itself and not terminate!).·
(4) The function should perform the correct computations if the terminating condition is
encountered. .
Example 1.4 [Recursive binary search]: Program 1.9 gave the iterative version of binary
search. In the recursive version· We pass left and right as parameters (Program 1.10).
37
The for loop of Program. 1.9 has been replaced by recursive calls in Program 1.10. To
invoke the recursive function, we use the statement
BinarySearch (a, x, 0, n -1);
You should verify that Binary‘Search satisfies the four conditions stated above for
recursive function‘s. Notice that both the iterative (Program 1.9) and recursive (Program
1.10) functions perform the same computation.
Example 1.5 [Permutation generator]:· Given a set of n > 1 elements, the problem is
to print all possible permutations of this set. For example if the set is {a, b, c}, then the
set of permutations is {(a, b, c), (a, c, b),(b, a, c),(b, c, a),(c, a, b),(c, b, a)}. It is easy to
see that given n elements, there are n ! different permutations. A simple algorithm
can be obtained by looking at the the case of four elements (a,b,c,d). The answer can
be constructed by writing.
Program 1.10
(I) a followed by all permutations of (b,c,d)
38
Program 1.11
2. Given n Boolean variables x!….., Xn we wish to print all possible combinations ‗. of
truth values they can assume. For instance, if n=2, there are four possibilities: true, true;
true, false; false, true; false, false. Write a C++ program to accomplish this and do a
frequency count.
3. Write a C++ program that prints out the integer values of x. y. and z in
nondecreasing order. What is the computing time of your method?
4.. Write a C++ function that searches an array a [n] for the element x. If x occurs, then
set j to its position in the array. else set j to -I. Try writing this without using the goto
statement.
5. Trace the action of the code
39
on the elements 2..4,6,8. 10. 12. 14. 16. 18, and 20 searching for x= 1.3, 13. or 21.
6. Take any version of binary search, express it using assignment, if-else, and goto, and
then give an equivalent recursive program. .
7. The factorial function n! has value I when n ~ 1 and value n*(n-l)! when n > I. Write
both a recursive and an iterative C++ function to compute n l.
8. Write an iterative function to compute a binomial coefficient; then transform it into an
equivalent recursive function.
9. Ackermann‘s function A (m,n) is defined as follows:
10. The pigeonhole principle states that if a function f has n distinct inputs but less than
n distinct outputs, then there exist two inputs a and b such that a :1: band f(a) = f(b).
Write a program to find the values a and b for which the range values are equal.
Assume that the inputs are I, 2, … , n.
11. Given n, a positive integer, determine if n is the sum of all of its divisors i.e., if is the
sum of all t such that 1 < t < n, and t divides n.
12. Consider the function F (x) defined by
if (x is even) F = x /2;
else F = F(F(3x + 1))
Prove that F(x) terminates for all integers x. (Hint: Consider integers of the form (2i + I
)2k – I and use induction.)
13. If S is a set Of n elements, the powerset of S is the set of all possible subsets of
S. For example, if S = (a,b,c), then powerset (S) = ((), (a), (b), (c), (a,b), (a,c), b,c),
(a,b,c)}. Write a recursive function to compute powerset (S).
14. [Towers of Hanoi) There are three towers and sixty-four disks of different
diameters placed on the first tower. The disks are in order of decreasing diameter as
one scans up the tower. Monks were supposed to move the disks from tower I to tower
3 obeying the following rules: (a) only one disk can be moved at any time and (b) no
disk can be placed on top of a disk with smaller diameter. Write a recursive function that
prints the sequence of moves that accomplish this task.
Near the beginning of learning Java, you will hear something about top-down design,
stepwise refinement and decomposition. This post today will explain what those terms
40
mean as well as provide the reason why you need to tackle programming design with
this approach in mind.
Just for the sake of clarity, top-down design is the process of stepwise design and
decomposition.
Before you start writing any code for a new program you want to create, you first need
to design the program or at least have a specification so that you know exactly what you
need to create.
Now that you know what you need to accomplish with your program, you now need to
know how you can accomplish it. The approach used to do that is called top-down
design and this simply means putting all the important main parts of the program in to a
list.
An example I want to use is from a Karel world. In this example, Karel needs to collect
the beeper (which is called a newspaper in the assignment). The assignment states that
Karel‘s world doesn‘t change and that the door is always where it is and the paper is
always on point 6,3 and that when collected, Karel needs to return back to the start.
41
A top-down design approach could go something like this:
1. Walk to paper.
2. Pick it up.
This is our top level that describes what needs to be done in the most basic form. I
guess we could start at an even higher level and simply say ―Collect paper‖, but
programming problems can be tackled in many ways and the way above is simply the
way I have decided to do it.
Stepwise Refinement/Decomposition
The next process is what is called stepwise refinement or decomposition. Rather than
leaving step 1 as ―walk to paper‖, we need to be more clear than this. So, to break this
step down with stepwise refinement, we could say…
1. Walk to paper.
1c. move
As this program is relatively simple, I think it can be left at just the one breakdown.
However, more complicated programs will require that steps 1a, 1b, 1c, 1d and 1e are
decomposed several times.
For step 2 ―pick it up‖, the assignment says we can assume there will always be a paper
there. To be on the safe side, we might want to have a bit more detail here and put
checks in place such as using an if statement to check if a paper is present. Also, we
could look here at pre-conditions and post-conditions. We need to know where Karel will
be after step 1 and where he needs to be to start step 3. In the breakdown of ―walk to
paper‖ I decided to leave Karel at the inside of the door facing out… so a pre-condition
is that Karel needs to make 1 move to the paper. A post-condition I will set is for Karel is
that he has returned to inside the house facing west which means we need to
remember that as a pre-condition for step 3… returning to the start.
42
Breaking down part 2:
2. Pick it up
Now we know that Karel is in the house, facing west we can break down step 3 as
follows:
I decided to tackle point 3 a different way. Instead of sending Karel back to the couch
the same way he came in… along the top and right wall. I decided to make him simply
continue west till he hits the wall, then turn right and then move to the top wall.
Conclusion
When you are writing programs, remember to use an approach that helps. Top-down
design is one way of doing this. It breaks the program in to bite-sized chunks and allows
you to solve each problem one at a time, in any order. Remember that you need to
make a note of pre and post conditions so that when you write the program out of
sequence, or as part of a team, all people know that Karel is facing west at a certain
point and can safely assume they just need to move him to a wall.
Also notice that 1a, 3a and 3c could technically use the same method… perhaps called
―walkToWall()‖. As long as pre and post conditions are taken in to account, Karel is
doing the same thing for each of those steps which means you have solved the problem
in a more simple way.
The first assignment in Karel is relatively simple and top-down design with stepwise
refinement and decomposition still finds a use here. In larger projects that you may end
up working on as part of a team, a systematic approach is needed so that you can get
43
through a project more easily. Make sure your notes are up to speed and that you keep
practicing and not forgetting comments or top-down design when creating your first and
all other programs.
Introduction to Programming
Are you aiming to become a software engineer one day? Do you also want to develop a
mobile application that people all over the world would love to use? Are you passionate
enough to take the big step to enter the world of programming? Then you are in the right
place because through this article you will get a brief introduction to programming. Now
before we understand what programming is, you must know what is a computer. A
computer is a device that can accept human instruction, processes it and responds to it or
a computer is a computational device which is used to process the data under the control
of a computer program. Program is a sequence of instruction along with data.
The basic components of a computer are:
1. Input unit
3. Output unit
Most of us have heard that CPU is called the brain of our computer because it accepts
data, provides temporary memory space to it until it is stored(saved) on the hard disk,
performs logical operations on it and hence processes(here also means converts) data
into information. We all know that a computer consists of hardware and software.
Software is a set of programs that performs multiple tasks together. An operating system
is also a software (system software) that helps humans to interact with the computer
system.
A program is a set of instructions given to a computer to perform a specific operation. or
computer is a computational device which is used to process the data under the control of
a computer program. While executing the program, raw data is processed into a desired
output format. These computer programs are written in a programming language which
are high level languages. High level languages are nearly human languages which are
more complex then the computer understandable language which are called machine
language, or low level language. So after knowing the basics, we are ready to create a
very simple and basic program. Like we have different languages to communicate with
44
each other, likewise, we have different languages like C, C++, C#, Java, python, etc to
communicate with the computers. The computer only understands binary language (the
language of 0‘s and 1‘s) also called machine-understandable language or low-level
language but the programs we are going to write are in a high-level language which is
almost similar to human language.
The piece of code given below performs a basic task of printing ―hello world! I am learning
programming‖ on the console screen. We must know that keyboard, scanner, mouse,
microphone, etc are various examples of input devices and monitor(console screen),
printer, speaker, etc are the examples of output devices.
main()
{
clrscr();
printf(―hello world! I am learning to program);
getch();
}
At this stage, you might not be able to understand in-depth how this code prints
something on the screen. The main() is a standard function that you will always include in
any program that you are going to create from now onwards. Note that the execution of
the program starts from the main() function. The clrscr() function is used to see only the
current output on the screen while the printf () function helps us to print the desired output
on the screen. Also, getch() is a function that accepts any character input from the
keyboard. In simple words, we need to press any key to continue(some people may say
that getch() helps in holding the screen to see the output).
Between high-level language and machine language there are assembly language also
called symbolic machine code. Assembly language are particularly computer architecture
specific. Utility program (Assembler) is used to convert assembly code into executable
machine code. High Level Programming Language are portable but require Interpretation
or compiling toconvert it into a machine language which is computer understood.
45
Hierarchy of Computer language –
There have been many programming language some of them are listed below:
C Python C++
C# R Ruby
46
Racket Scheme Shimula
Matlab F F#
TCL D CPL
C
Python
C++
Java
SCALA
C#
R
Ruby
Go
Swift
JavaScript
47
Characteristics of a programming Language –
A programming language must be simple, easy to learn and use, have good
readability and human recognizable.
Computer Languages
The user of a computer must be able to communicate with it. That means, he must be able
to give the computer commands and understand the output that the computer generates.
This is possible due to the invention of computer languages.
Basically, there are two main categories of computer languages, namely Low Level
Language and High Level Language. Let us take a brief look at both these types of
computer languages.
48
1] Low Level Languages
Low level languages are the basic computer instructions or better known as machine
codes. A computer cannot understand any instruction given to it by the user in English or
any other high level language. These low level languages are very easily understandable
by the machine.
The main function of low level languages is to interact with the hardware of the computer.
They help in operating, syncing and managing all the hardware and system components
of the computer. They handle all the instructions which form the architecture of the
hardware systems.
Number Systems
Number System Conversions
Generations of Computers
Computer Organisation
Computer Memory
History of Computers
Computers Abbreviations
Basic Computer Terminology
Basic Internet Knowledge and Protocols
Hardware and Software
Keyboard Shortcuts
I/O Devices
Practice Problems On Basics Of Computers
Machine Language
This is one of the most basic low level languages. The language was first developed to
interact with the first generation computers. It is written in binary code or machine code,
which means it basically comprises of only two digits – 1 and 0.
49
Assembly Language
When we talk about high level languages, these are programming languages. Some
prominent examples are PASCAL, FORTRAN, C++ etc.
The important feature about such high level languages is that they allow the programmer
to write programs for all types of computers and systems. Every instruction in high level
language is converted to machine language for the computer to comprehend.
Scripting Languages
Scripting languages are easier to learn and execute than compiled languages. Some
examples are AppleScript, JavaScript, Pearl etc.
Object-Oriented Languages
These are high level languages that focus on the ‗objects‘ rather than the ‗actions‘. To
accomplish this, the focus will be on data than logic.
The reasoning behind is that the programmers really cares about the object they wish to
manipulate rather than the logic needed to manipulate them. Some examples include
Java, C+, C++, Python, Swift etc.
This is a type of programming language that has well structured steps and complex
procedures within its programming to compose a complete program.
50
Introduction to the design and implementation of correct
Software Design is the process to transform the user requirements into some suitable
form, which helps the programmer in software coding and implementation. During the
software design phase, the design document is produced, based on the customer
requirements as documented in the SRS document. Hence the aim of this phase is to
transform the SRS document into the design document.
The following items are designed and documented during the design phase:
Different modules required.
Control relationships among modules.
Interface among different modules.
Data structure among the different modules.
Algorithms required to implement among the individual modules.
1. Correctness:
A good design should be correct i.e. it should correctly implement all the
functionalities of the system.
2. Efficiency:
A good software design should address the resources, time and cost optimization
issues.
3. Understandability:
4. Completeness:
The design should have all the components like data structures, modules, and
external interfaces, etc.
5. Maintainability:
Concepts are defined as a principal idea or invention that comes in our mind or in thought
to understand something. The software design concept simply means the idea or
51
principle behind the design. It describes how you plan to solve the problem of designing
software, the logic, or thinking behind how you will design software. It allows the software
engineer to create the model of the system or software or product that is to be developed
or built. The software design concept provides a supporting and essential structure or
model for developing the right software. There are many concepts of software design and
some of them are given below:
52
Following points should be considered while designing a Software:
Abstraction simply means to hide the details to reduce complexity and increases
efficiency or quality. Different levels of Abstraction are necessary and must be
applied at each stage of the design process so that any error that is present can be
removed to increase the efficiency of the software solution and to refine the
software solution. The solution should be described in broadways that cover a wide
range of different things at a higher level of abstraction and a more detailed
description of a solution of software should be given at the lower level of
abstraction.
Modularity simply means to divide the system or project into smaller parts to
reduce the complexity of the system or project. In the same way, modularity in
design means to subdivide a system into smaller parts so that these parts can be
created independently and then use these parts in different systems to perform
different functions. It is necessary to divide the software into components known as
modules because nowadays there are different software available like Monolithic
software that is hard to grasp for software engineers. So, modularity is design has
now become a trend and is also important.
The pattern simply means a repeated form or design in which the same shape is
repeated several times to form a pattern. The pattern in the design process means
the repetition of a solution to a common recurring problem within a certain context.
53
6. Information Hiding- hide the information
Refactoring simply means to reconstruct something in such a way that it does not
affect the behavior or any other features. Refactoring in software design means to
reconstruct the design to reduce and complexity and simplify it without affecting the
behavior or its functions. Fowler has defined refactoring as ―the process of
changing a software system in a way that it won‘t affect the behavior of the design
and improves the internal structure‖.
1. Architectural Design:
The architecture of a system can be viewed as the overall structure of the system
& the way in which structure provides conceptual integrity of the system. The
architectural design identifies the software as a system with many components
interacting with each other. At this level, the designers get the idea of the proposed
solution domain.
Here the problem is decomposed into a set of modules, the control relationship
among various modules identified and also the interfaces among various modules
are identified. The outcome of this stage is called the program architecture. Design
representation techniques used in this stage are structure chart and UML.
3. Detailed design:
Once the high level design is complete, detailed design is undertaken. In detailed
design, each module is examined carefully to design the data structure and
algorithms. The stage outcome is documented in the form of a module
specification document.
54
efficient and maintainable programs
in this phase , the user‘s expectations are gathered to understand why the program or
software has to be developed. Then , all the gathered requirements are analysed and
the scope or objective of the over all software product is penned down. The last activity
in this phase involves documenting every identified requirement of the user in order to
avoid any doubts or uncertainty regarding the functionality of the program. The
functionality, capability, performance, and availability of hardware and software
components are all analysed in this phase.
Design:
The requirement documented in the previous phase act as the input to the design
phase. In this phase, a plan of actions is made before the actual development process
starts. This plan will be followed throughout the development process. Moreover, in the
design phase, the core structure of the software or program is broken down in to
modules. The solution of the program is then specified for each module in the form of
algorithms or flow charts . The design phase, therefore specifies how the program or
software will be developed.
Implementation:
In this phase, the designed algorithms are converted in to program code using any of
the high level languages. The particular choice of language will depend on the type of
program such as whether it is a system or an application program. C is preferred for
writing system programs, whereas Visual basic might be preferred for an application
program. The program codes are tested by the programmer to ensure their correctness.
Testing:
In this phase , all the modules are tested together to ensure that the overall system
works well as a whole product. In this phase, the software is tested using a large
number of varied inputs, also known as test data, to ensure that the software is working
as expected by the user‘s requirements identified in the requirements analysis phase.
55
Software deployment, training, and support:
After the code is tested and the software or the program is approved by the user‘s it is
then installed or deployed in the production environment.
Software training and support is a crucial phase. Program designers and developers
spend a lot of time creating the software, but if nobody in the organization knows how to
use it or to fix certain problems , then no one will want to use it.
Maintenance:
Maintenance and enhancements are ongoing activities that are done to cope with newly
discovered problems or new requirements. Such activities may take a long time to
complete.
Structured Programming
Since the invention by Von Neumann of the stored program computer, computer
scientists have known that a tremendous power of computing equipment was the ability
to alter its behavior, depending on the input data. Calculating machines had, for some
time, been able to perform fixed arithmetic operations on data, but the potential of
machines capable of making decisions opened up many new possibilities. Machines
that could make decisions were capable of sorting records, tabulating and summarizing
data, searching for information, and many more advanced operations that could not
even be imagined at the time.
In early programming languages, like Fortran (first invented in 1954) and various low
level machine languages, the goto statement allowed the computer to deviate from the
sequential execution of the program instructions. The goto statement was recognized to
be a very powerful construction, and soon, programs of increasing complexity and
power were developed.
However, the increasingly complex code that resulted from goto statements became
harder and harder to maintain. Dijkstra, in 1966, was one of the first persons to
recognize that this run away complexity of programs was due to the overuse of the goto
statement (Dijkstra, E. W., "Go To Considered Harmful," Communications of the ACM,
March 1966). In fact, it was determined shortly thereafter, that the goto statement is not
needed at all. Dijkstra showed that any program construction that could be created with
goto statements could be created more simply with the sequence, repetition and
decision constructions that are discussed in the following sections. This was the birth of
the discipline of Structured Programming.
56
Structured Programming in Everyday Life
Add flour.
Add salt.
Add yeast.
Mix.
Add water.
Knead.
Let rise.
Bake.
57
ElseIf pieceIsJunkMail Then
Throw in wastebasket.
End If
End While
Example:
x=5
y = 11
z=x+y
WriteLine(z)
While condition
action
End While
Example:
x=2
While x < 100
WriteLine(x)
x=x*x
End
58
If condition Then
action
End If
Example:
x = ReadLine()
If x Mod 2 = 0
WriteLine("The number is even.")
End If
To make programs easier to read, some additional constructs were added to the basic
three original structured programming constructs:
Example:
For i = 1 To 20
WriteLine(i)
Next i
Example:
For i = 20 To 1 Step -1
WriteLine(i)
Next
59
If condition1 Then
action1
ElseIf condition2 Then
action2
ElseIf condition3 Then
action3
Else
defaultAction
End If
Example:
If n = 1 Then
WriteLine("One")
ElseIf n = 2 Then
WriteLine("Two")
ElseIf n = 3 Then
WriteLine("Three")
Else
WriteLine("Many")
End If
Example:
Select Case n
Case 1
WriteLine("One")
Case 2
WriteLine("Two")
Case 3
60
WriteLine("Three")
Case Else
WriteLine("Many")
End Select
A trace table is a technique used to test algorithms in order to make sure that no logical
errors occur while the calculations are being processed. The table usually takes the
form of a multi-column, multi-row table; With each column showing a variable, and each
row showing each number input into the algorithm and the subsequent values of the
variables.
Trace tables are typically used in schools and colleges when teaching students how to
program. They can be an essential tool in teaching students how certain calculations
works and the systematic process that is occurring when the algorithm is executed.
They can also be useful for debugging applications, helping the programmer to easily
detect what error is occurring, and why it may be occurring.
Example [edit]
int i, x = 0;
for (i = 1; i <= 10; i++)
{
x = i * 2;
}
i x
? 0
1 2
2 4
3 6
61
4 8
5 10
6 12
7 14
8 16
9 18
10 20
11 20
This example shows the systematic process that takes place whilst the algorithm is
processed. The initial value of x is zero, but i, although defined, has not been assigned
a value. Thus, its initial value is unknown. As we execute the program, line by line, the
values of i and x change, reflecting each statement of the source code in execution.
Their new values are recorded in the trace table. When i reaches the value
of 11 because of the i++ statement in the for definition, the comparison i <=
10 evaluates to false, thus halting the loop. As we also reached the end of the program,
the trace table also ends.
62
Shortcut method − Octal to Binary
Shortcut method − Binary to Hexadecimal
Shortcut method − Hexadecimal to Binary
Steps
Step 1 − Divide the decimal number to be converted by the value of the new
base.
Step 2 − Get the remainder from Step 1 as the rightmost digit (least significant
digit) of new base number.
Step 3 − Divide the quotient of the previous divide by the new base.
Step 4 − Record the remainder from Step 3 as the next digit (to the left) of the
new base number.
Repeat Steps 3 and 4, getting remainders from right to left, until the quotient becomes
zero in Step 3.
The last remainder thus obtained will be the Most Significant Digit (MSD) of the new
base number.
Example −
Step 1 29 / 2 14 1
Step 2 14 / 2 7 0
Step 3 7/2 3 1
Step 4 3/2 1 1
63
Step 5 1/2 0 1
Steps
Step 1 − Determine the column (positional) value of each digit (this depends on
the position of the digit and the base of the number system).
Step 2 − Multiply the obtained column values (in Step 1) by the digits in the
corresponding columns.
Step 3 − Sum the products calculated in Step 2. The total is the equivalent value
in decimal.
Example
64
Other Base System to Non-Decimal System
Steps
Step 1 − Convert the original number to a decimal number (base 10).
Step 2 − Convert the decimal number so obtained to the new base number.
Example
Step 1 21 / 2 10 1
Step 2 10 / 2 5 0
Step 3 5 / 2 2 1
Step 4 2 / 2 1 0
65
Step 5 1 / 2 0 1
Steps
Step 1 − Divide the binary digits into groups of three (starting from the right).
Step 2 − Convert each group of three binary digits to one octal digit.
Example
Step 101012 28 58
2
Steps
Step 1 − Convert each octal digit to a 3 digit binary number (the octal digits may
be treated as decimal for this conversion).
Step 2 − Combine all the resulting binary groups (of 3 digits each) into a single
binary number.
66
Example
Steps
Step 1 − Divide the binary digits into groups of four (starting from the right).
Step 2 − Convert each group of four binary digits to one hexadecimal symbol.
Example
67
2
Steps
Step 1 − Convert each hexadecimal digit to a 4 digit binary number (the
hexadecimal digits may be treated as decimal for this conversion).
Step 2 − Combine all the resulting binary groups (of 4 digits each) into a single
binary number.
Example
68
UNIT II
When we say Input, it means to feed some data into a program. An input can be given
in the form of a file or from the command line. C programming provides a set of built-in
functions to read the given input and feed it to the program as per requirement.
When we say Output, it means to display some data on screen, printer, or in any file. C
programming provides a set of built-in functions to output the data on the computer
screen as well as to save it in text or binary files.
C programming treats all the devices as files. So devices such as the display are
addressed in the same way as files and the following three files are automatically
opened when a program executes to provide access to the keyboard and screen.
The file pointers are the means to access the file for reading and writing purpose. This
section explains how to read values from the screen and how to print the result on the
screen.
The int getchar(void) function reads the next available character from the screen and
returns it as an integer. This function reads only single character at a time. You can
use this method in the loop in case you want to read more than one character from the
screen.
69
The int putchar(int c) function puts the passed character on the screen and returns
the same character. This function puts only single character at a time. You can use this
method in the loop in case you want to display more than one character on the screen.
Check the following example –
#include <stdio.h>
int main( ) {
int c;
return 0;
}
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then the program proceeds and reads only a
single character and displays it as follows −
$./a.out
Enter a value : this is test
You entered: t
The char *gets(char *s) function reads a line from stdin into the buffer pointed to
by s until either a terminating newline or EOF (End of File).
The int puts(const char *s) function writes the string 's' and 'a' trailing newline
to stdout.
NOTE: Though it has been deprecated to use gets() function, Instead of using gets,
you want to use fgets().
#include <stdio.h>
int main( ) {
char str[100];
70
gets( str );
return 0;
}
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then the program proceeds and reads the
complete line till end, and displays it as follows −
$./a.out
Enter a value : this is test
You entered: this is test
The int scanf(const char *format, ...) function reads the input from the standard input
stream stdin and scans that input according to the format provided.
The int printf(const char *format, ...) function writes the output to the standard output
stream stdout and produces the output according to the format provided.
The format can be a simple constant string, but you can specify %s, %d, %c, %f, etc.,
to print or read strings, integer, character or float respectively. There are many other
formatting options available which can be used based on requirements. Let us now
proceed with a simple example to understand the concepts better –
#include <stdio.h>
int main( ) {
char str[100];
int i;
return 0;
}
71
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then program proceeds and reads the input
and displays it as follows −
$./a.out
Enter a value : seven 7
You entered: seven 7
Here, it should be noted that scanf() expects input in the same format as you provided
%s and %d, which means you have to provide valid inputs like "string integer". If you
provide "string string" or "integer integer", then it will be assumed as wrong input.
Secondly, while reading a string, scanf() stops reading as soon as it encounters a
space, so "this is test" are three strings for scanf().
Character types
A storage class represents the visibility and a location of a variable. It tells from what
part of code we can access a variable. A storage class is used to describe the following
things:
A lifetime of a variable.
NOTE: A variable is not only associated with a data type, its value but also a storage
class.
There are total four types of standard storage classes. The table below represents the
storage classes in 'C'.
72
Storage class Purpose
The variables defined using auto storage class are called as local variables. Auto
stands for automatic storage class. A variable is in auto storage class by default if it is
not explicitly specified.
The scope of an auto variable is limited with the particular block only. Once the control
goes out of the block, the access is destroyed. This means only the block in which the
auto variable is declared can access it.
A keyword auto is used to define an auto storage class. By default, an auto variable
contains a garbage value.
The program below defines a function with has two local variables
73
int add(void) {
int a=13;
auto int b=48;
return a+b;}
We take another program which shows the scope level "visibility level" for auto variables
in each block code which are independently to each other:
#include <stdio.h>
int main( )
{
auto int j = 1;
{
auto int j= 2;
{
auto int j = 3;
printf ( " %d ", j);
}
printf ( "\t %d ",j);
}
printf( "%d\n", j);}
OUTPUT:
321
Extern stands for external storage class. Extern storage class is used when we have
global functions or variables which are shared between two or more files.
The variables defined using an extern keyword are called as global variables. These
variables are accessible throughout the program. Notice that the extern variable cannot
be initialized it has already been defined in the original file
#include <stdio.h>
extern i;
main() {
74
printf("value of the external integer is = %d\n", i);
return 0;}
#include <stdio.h>
i=48;
Result:
In order to compile and run the above code, follow the below steps
75
Step 2) Select C and click Next
76
Step 4) Enter details and click Next
77
Step 6) Put the main code as shown in the previous program in the main.c file and save
it
Step 7) Create a new C file [File -> new -> Empty File , save (as original.c ) and add it
to the current project by clicking "OK" in the dialogue box .
Step 8) Put and save the C code of the original.c file shown in the previous example
without the main() function.
78
Step 9) Build and run your project. The result is shown in the next figure
The static variables are used within function/ file as local static variables. They can also
be used as a global variable
Static local variable is a local variable that retains and stores its value between
function calls or block and remains visible only to the function or block in which it
is defined.
Static global variables are global variables visible only to the file in which it is
declared.
Keep in mind that static variable has a default initial value zero and is initialized only
once in its lifetime.
Result:
Global variables are accessible throughout the file whereas static variables are
accessible only to the particular part of a code.
The lifespan of a static variable is in the entire program code. A variable which is
declared or initialized using static keyword always contains zero as a default value.
79
Register storage class
You can use the register storage class when you want to store local variables within
functions or blocks in CPU registers instead of RAM to have quick access to these
variables. For example, "counters" are a good candidate to be stored in the register.
The keyword register is used to declare a register storage class. The variables
declared using register storage class has lifespan throughout the program.
It is similar to the auto storage class. The variable is limited to the particular block. The
only difference is that the variables declared using register storage class are stored
inside CPU registers instead of a memory. Register has faster access than that of the
main memory.
The variables declared using register storage class has no default value. These
variables are often declared at the beginning of a program.
OUTPUT:
The next table summarizes the principal features of each storage class which are
commonly used in C programming
80
extern Outside all Memory Zero Entire the file program
functions and other files runtime
where the
variable is
declared as
extern
Summary
Auto, extern, register, static are the four storage classes in 'C'.
register is used to store the variable in CPU registers rather memory location for
quick access.
Static is used for both global and local variables. Each one has its use case
within a C program.
Integer
Every programming language has in-built types to differentiate between the nature of
various data (input or output or intermediate). Integer is a common data type which is
widely use in general programming and in scientific computing.
81
Integer is defined as a number which has no fractional component. Numbers which
have a fractional component is known floating point numbers. Despite the fact that
floating point numbers can represent numbers accurately, integers have their own place
in the world of computing due to:
Calculations using integers are much faster (over 2 times) due to hardware architecture
In C programming language, integer data is represented by its own datatype known
as int. It has several variants which differs based on memory consumption includes:
int
long
short
long long
Usage
In C, one can define an integer variable as:
int main()
{
int a = 1;
short b = 1;
long c = 1;
long long d = 1;
}
C
Copy
signed integers: range is equally divided among negative and positive numbers
(including 0)
unsigned integers: range starts from 0 to the upper positive number limit
Hence, unsigned integers are used when:
82
negative numbers are not required
int main()
{
unsigned int a = 1;
unsigned long b = 1;
}
C
Copy
int
unsigned int
short
unsigned short
long
unsigned long
long long
Format specifier
To print a value in C using printf, one needs to specify the datatype of the data to be
printed. The format specifier of each variant of integer datatype is different in C.
83
int main()
{
unsigned int a = 1;
int b = 1;
unsigned long c = 1;
long long d = 1;
printf("%u", a);
printf("%d", b);
printf("%lu", c);
printf("%lld", d);
}
C
Copy
int main()
{
printf("size of int : %d\n",sizeof(int));
printf("size of signed int : %d\n",sizeof(signed int));
printf("size of unsigned long : %d\n",sizeof(unsigned long));
return 0;
}
C
Copy
Ideally, memory consumed by the signed and unsigned variants are the same. It only
differs in the range.
If Integer data type int is of 4 bytes, then the range is calculated as follows:
4 bytes = 4 X 8 = 32 bits
Hence
The exact value of memory and range depends on the hardware but remains same
across several hardware types. Following table summarizes the values:
85
size of int <= size of long
Integer overflow
As we have seen that each integer datatype has a fixed range beyond which it will fail.
In case, a number falls beyond the range of a datatype, then the code will wrap around
to give an errorneous result.
Short
Short int is integer variable. They are used to store value upto -32,768 to 32,767. The
%hd is a short int placeholder(format specifier) that will be replaced by the value of
short integer variable ‗a‘ when the printf statement is executed.
Program
86
Program Source
#include <stdio.h>
int main()
return 0;
Long
Long is a data type used in programming languages, such as Java, C++, and C#.
A constant or variable defined as long can store a single 64-bit signed integer.
So what constitutes a 64-bit signed integer? It helps to break down each word, starting
from right to left. An integer is a whole number that does not include a decimal point.
Examples include 1, 99, or 234536. "Signed" means the number can be either positive
or negative, since it may be preceded by a minus (-) symbol. 64-bit means the number
can store 263 or 18,446,744,073,709,551,616 different values (since one bit is used for
the sign). Because the long data type is signed, the possible integers range from -
9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, including 0.
In modern programming languages, the standard integer (int) data type typically stores
a 32-bit whole number. Therefore, if a variable or constant may potentially store a
87
number larger than 2,147,483,647 (231 ÷ 2), it should be defined as a long instead of
an int.
Unsigned
char is the most basic data type in C. It stores a single character and requires a single
byte of memory in almost all compilers.
Now character datatype can be divided into 2 types:
1. signed char
2. unsigned char
88
unsigned char is a character datatype where the variable consumes all the 8 bits of the
memory and there is no sign bit (which is there in signed char). So it means that the
range of unsigned char data type ranges from 0 to 255.
Syntax:
Example:
#include <stdio.h>
int main()
{
return 0;
}
Output:
unsigned char: a
Initializing an unsigned char with signed value: Here we try to insert a char in the
unsigned char variable with the help of ASCII value. So the ASCII value -1 will be
first converted to a range 0-255 by rounding. So it will be 255. Now, this value will be
converted to a character value, i.e. ‗ÿ‘ and it will be inserted in unsigned char.
filter_none
edit
play_arrow
brightness_4
89
// C program to show unsigned char
#include <stdio.h>
int main()
{
return 0;
}
Output:
unsigned char: ÿ
There are a few different ways to think about pi. As apple, pumpkin and key lime … or
as the different ways to represent the mathematical constant of ℼ, 3.14159, or, in binary,
a long line of ones and zeroes.
In grade school, one might do the math by hand, stopping at 3.14. A high schooler‘s
graphing calculator might go to 10 decimal places — using a higher level of detail to
express the same number. In computer science, that‘s called precision. Rather than
decimals, it‘s usually measured in bits, or binary digits.
For complex scientific simulations, developers have long relied on high-precision math
to understand events like the Big Bang or to predict the interaction of millions of atoms.
Having more bits or decimal places to represent each number gives scientists the
flexibility to represent a larger range of values, with room for a fluctuating number of
digits on either side of the decimal point during the course of a computation. With this
range, they can run precise calculations for the largest galaxies and the smallest
particles.
90
But the higher precision level a machine uses, the more computational resources, data
transfer and memory storage it requires. It costs more and it consumes more power.
Since not every workload requires high precision, AI and HPC researchers can benefit
by mixing and matching different levels of precision. NVIDIA Tensor Core GPUs support
multi- and mixed-precision techniques, allowing developers to optimize computational
resources and speed up the training of AI applications and those
apps‘ inferencing capabilities.
The IEEE Standard for Floating-Point Arithmetic is the common convention for
representing numbers in binary on computers. In double-precision format, each number
takes up 64 bits. Single-precision format uses 32 bits, while half-precision is just 16 bits.
To see how this works, let‘s return to pi. In traditional scientific notation, pi is written as
3.14 x 100. But computers store that information in binary as a floating-point, a series of
ones and zeroes that represent a number and its corresponding exponent, in this case
1.1001001 x 21.
In single-precision, 32-bit format, one bit is used to tell whether the number is positive or
negative. Eight bits are reserved for the exponent, which (because it‘s binary) is 2
raised to some power. The remaining 23 bits are used to represent the digits that make
up the number, called the significand.
Double precision instead reserves 11 bits for the exponent and 52 bits for the
significand, dramatically expanding the range and size of numbers it can represent. Half
precision takes an even smaller slice of the pie, with just five for bits for the exponent
and 10 for the significand.
91
Difference Between Multi-Precision and Mixed-Precision Computing
In mixed precision, calculations start with half-precision values for rapid matrix math.
But as the numbers are computed, the machine stores the result at a higher precision.
For instance, if multiplying two 16-bit matrices together, the answer is 32 bits in size.
With this method, by the time the application gets to the end of a calculation, the
accumulated answers are comparable in accuracy to running the whole thing in double-
precision arithmetic.
NVIDIA Volta and Turing GPUs feature Tensor Cores, which are built to simplify and
accelerate multi- and mixed-precision computing. And with just a few lines of code,
developers can enable the automatic mixed-precision feature in the TensorFlow,
PyTorch and MXNet deep learning frameworks. The tool gives researchers speedups of
up to 3x for AI training.
The NGC catalog of GPU-accelerated software also includes iterative refinement solver
and cuTensor libraries that make it easy to deploy mixed-precision applications for
HPC.
92
For more information, check out our developer resources on training with mixed
precision.
Earth Sciences
Researchers from the University of Tokyo, Oak Ridge National Laboratory and the
Swiss National Supercomputing Center used AI and mixed-precision techniques for
earthquake simulation. Using a 3D simulation of the city of Tokyo, the scientists
modeled how a seismic wave would impact hard soil, soft soil, above-ground buildings,
underground malls and subway systems. They achieved a 25x speedup with their new
model, which ran on the Summit supercomputer and used a combination of double-,
single- and half-precision calculations.
A Gordon Bell prize-winning team from Lawrence Berkeley National Laboratory used AI
to identify extreme weather patterns from high-resolution climate simulations, helping
scientists analyze how extreme weather is likely to change in the future. Using the
mixed-precision capabilities of NVIDIA V100 Tensor Core GPUs on Summit, they
achieved performance of 1.13 exaflops.
Nuclear Energy
Nuclear fusion reactions are highly unstable and tricky for scientists to sustain for more
than a few seconds. Another team at Oak Ridge is simulating these reactions to give
physicists more information about the variables at play within the reactor. Using mixed-
93
precision capabilities of Tensor Core GPUs, the team was able to accelerate their
simulations by 3.5x.
storage classes
Storage classes in C are used to determine the lifetime, visibility, memory location, and
initial value of a variable. There are four types of storage classes in C
o Automatic
o External
o Static
o Register
extern RAM Zero Global Till the end of the main program
Maybe declared anywhere in the
program
static RAM Zero Local Till the end of the main program,
Retains value between multiple
functions call
Automatic
94
The scope of the automatic variables is limited to the block in which they are
defined.
o The automatic variables are initialized to garbage by default.
o The memory assigned to automatic variables gets freed upon exiting from the
block.
o The keyword used for defining automatic variables is auto.
o Every local variable is automatic in C by default.
Example 1
1. #include <stdio.h>
2. int main()
3. {
4. int a; //auto
5. char b;
6. float c;
7. printf("%d %c %f",a,b,c); // printing initial default value of automatic variables a, b, and c
.
8. return 0;
9. }
Output:
95
Output:
11 20 20 20 11
Static
o The variables defined as static specifier can hold their value between the multiple
function calls.
o Static local variables are visible only to the function or the block in which they are
defined.
o A same static variable can be declared many times but can be assigned at only
one time.
o Default initial value of the static integral variable is 0 otherwise null.
o The visibility of the static global variable is limited to the file in which it has
declared.
o The keyword used to define static variable is static.
Example 1
1. #include<stdio.h>
2. static char c;
3. static int i;
4. static float f;
5. static char s[100];
6. void main ()
7. {
8. printf("%d %d %f %s",c,i,f); // the initial default value of c, i, and f will be printed.
9. }
Output:
0 0 0.000000 (null)
Example 2
1. #include<stdio.h>
2. void sum()
3. {
4. static int a = 10;
5. static int b = 24;
6. printf("%d %d \n",a,b);
7. a++;
8. b++;
96
9. }
10. void main()
11. {
12. int i;
13. for(i = 0; i< 3; i++)
14. {
15. sum(); // The static variables holds their value between multiple function calls.
16. }
17. }
Output:
10 24
11 25
12 26
Register
o The variables defined as the register is allocated the memory into the CPU
registers depending upon the size of the memory remaining in the CPU.
o We can not dereference the register variables, i.e., we can not use &operator for
the register variable.
o The access time of the register variables is faster than the automatic variables.
o The initial default value of the register local variables is 0.
o The register keyword is used for the variable which should be stored in the CPU
register. However, it is compiler?s choice whether or not; the variables can be
stored in the register.
o We can store pointers into the register, i.e., a register can store the address of a
variable.
o Static variables can not be stored into the register since we can not use more
than one storage specifier for the same variable.
Example 1
1. #include <stdio.h>
2. int main()
3. {
4. register int a; // variable a is allocated memory in the CPU register. The initial default v
alue of a is 0.
5. printf("%d",a);
6. }
97
Output:
0
Example 2
1. #include <stdio.h>
2. int main()
3. {
4. register int a = 0;
5. printf("%u",&a); // This will give a compile time error since we can not access the addres
s of a register variable.
6. }
Output:
External
o The external storage class is used to tell the compiler that the variable defined as
extern is declared with an external linkage elsewhere in the program.
o The variables declared as extern are not allocated any memory. It is only
declaration and intended to specify that the variable is declared elsewhere in the
program.
o The default initial value of external integral type is 0 otherwise null.
o We can only initialize the extern variable globally, i.e., we can not initialize the
external variable within any block or method.
o An external variable can be declared many times but can be initialized at only
once.
o If a variable is declared as external then the compiler searches for that variable
to be initialized somewhere in the program which may be extern or static. If it is
not, then the compiler will show an error.
Example 1
1. #include <stdio.h>
2. int main()
3. {
4. extern int a;
5. printf("%d",a);
98
6. }
Output
Output
0
Example 3
1. #include <stdio.h>
2. int a;
3. int main()
4. {
5. extern int a = 0; // this will show a compiler error since we can not use extern and initiali
zer at same time
6. printf("%d",a);
7. }
Output
99
6. }
7. int a = 20;
Output
20
Example 5
1. extern int a;
2. int a = 10;
3. #include <stdio.h>
4. int main()
5. {
6. printf("%d",a);
7. }
8. int a = 20; // compiler will show an error at this line
Output
automatic
The variables which are declared inside a block are known as automatic or local
variables; these variables allocates memory automatically upon entry to that block and
free the occupied memory upon exit from that block.
These variables have local scope to that block only that means these can be accessed
in which variable declared.
Keyword 'auto' may be used to declare automatic variable but we can declare these
variable without using 'auto' keywords.
int main()
auto int a;
int b;
100
....
return 0;
An automatic or local variable can be declared in any user define function in the starting
of the block.
void myFunction(void)
{
int x;
float y;
char z;
...
}
int main()
{
int a,b;
myFunction();
....
return 0;
}
Register
Register variables tell the compiler to store the variable in CPU register instead of
memory. Frequently used variables are kept in registers and they have faster
accessibility. We can never get the addresses of these variables. ―register‖ keyword is
used to declare the register variables.
Scope − They are local to the function.
101
Default value − Default initialized value is the garbage value.
Lifetime − Till the end of the execution of the block in which it is defined.
Here is an example of register variable in C language,
Example
#include <stdio.h>
int main() {
auto int b = 8;
return 0;
Output
The value of register variable b : S
The sum of auto and register variable : 18
Register keyword can be used with pointer also. It can have address of memory
location. It will not create any error.
Here is an example of register keyword in C language
Example
#include<stdio.h>
int main() {
int i = 10;
getchar();
return 0;
102
}
Output
The value of pointer : 10
By default, functions and global variables are visible within all linked files.
But, this would mean that global variables are visible from everywhere.
So, ―static‖ keyword lets us limit the visibility of things within the same file. A
static global variable or a static function is ―seen‖ only in the file it‘s declared in (so that
the user won‘t be able to access them. This is encapsulation, a good practice).
This means that static variables are stored in static memory as opposed to stack. Thus,
having a static variable inside a function would keeps its value between function
invocations. This could lead to code being not thread-safe and harder to understand.
103
Here, variable ―I‖ is not found in file sum.c
104
Here, variable ―I‖ declared in sumWithI function has garbage value or zero initial value
[depending on system]
the static variable initialized in main.c does not allow the variable to be visible outside
the file.
the function sumWithI is made static and thus cannot be accessed from main.c
105
the static variable inside a function holds its value on successive function calls.
Recap: By default, variables declared inside functions have local lifetimes (stack-bound)
and using ―static‖ lets us change their storage class to static (aka ―global‖)
Caché supports many different operators, which perform various actions, including
mathematical actions, logical comparisons, and so on. Operators act on expressions,
which are variables or other entities that ultimately evaluated to a value. This chapter
describes expressions and the various ObjectScript operators. It contains the following
topics:
String-to-Number Conversion
Arithmetic Operators
Pattern Matching
Indirection
Operators are symbolic characters that specify the action to be performed on their
associated operands. Each operand consists of one or more expressions or expression
atoms. When used together, an operator and its associated operands have the following
form:
106
[operand] operator operand
Some operators take only one operand and are known as unary operators; others take
two operands and are known as binary operators.
An operator and any of its operands taken together constitute an expression. Such
expressions produce a result that is the effect of the operator on the operand(s). They
are classified based on the types of operators they contain.
ObjectScript Operators
* Multiplication
/ Division
107
\ Integer division
** Exponentiation
# Modulus (remainder)
_ Concatenation
'>
Not greater than (less than or equal to)
<=
'<
Not less than (greater than or equal to)
>=
[ Contains
] Follows
]] Sorts After
&
Logical AND (&& is ―short-circuit‖ AND)
&&
!
Logical OR (|| is ―short-circuit‖ OR)
||
108
@ Indirection
? Pattern Match
Operator Precedence
ObjectScript gives the unary negative operator precedence over the binary arithmetic
operators. ObjectScript first scans a numeric expression and performs any unary
negative operations. Then, ObjectScript evaluates the expression and produces a
result.
You can change the order of evaluation by nesting expressions within each other with
matching parentheses. The parentheses group the enclosed expressions (both
arithmetic and relational) and control the order in which ObjectScript performs
operations on the expressions. Consider the following expression:
109
SET TorF = ((4 + 7) > (6 + 6)) // False (0)
WRITE TorF
Here, because of the parentheses, four and seven are added, as are six and six; this
results in the logical expression 11 > 12, which is false. Compare this to:
In this case, precedence proceeds from left to right, so four and seven are added. Their
sum, eleven, is compared to six; since eleven is greater than six, the result of this
logical operation is one (TRUE). One is then added to six, and the result is seven.
Note that the precedence even determines the result type, since the first expression‘s
final operation results in a boolean and the second expression‘s final operation results
in a numeric.
Precedence from the innermost nested expression and proceeds out level by level,
evaluating left to right at each level.
Tip:
For all but the simplest ObjectScript expressions, it is good practice to fully
parenthesize expressions. This is to eliminate any ambiguity about the order of
evaluation and to also eliminate any future questions about the original intention of
the code.
For example, because the ―&&‖ operator, like all operators, is subject to left-to-right
precedence, the final statement in the following code fragment evaluates to 0:
SET x = 3
SET y = 2
IF x && y = 2 {
WRITE "True",! }
ELSE {
WRITE "False",! }
110
This is because the evaluation occurs as follows:
1. The first action is to check if x is defined and has a non-zero value. Since x equals
3, evaluation continues.
2. Next, there is a check if y is defined and has a non-zero value. Since y equals 2,
evaluation continues.
3. Next, the value of 3 && 2 is evaluated. Since neither 3 nor 2 equal 0, this
expression is true and evaluates to 1.
4. The next action is to compare the returned value to 2. Since 1 does not equal 2,
this evaluation returns 0.
SET x = 3
SET y = 2
IF x && (y = 2) {
WRITE "True",! }
ELSE {
WRITE "False",! }
Some types of expressions, such as functions, can have side effects. Suppose you
have the following logical expression:
ObjectScript first evaluates var1, then the function $$ONE, then var2. It then
multiplies var2 by 5. Finally, ObjectScript tests to see if the result of the addition is equal
to the value in var1. If it is, it executes the DO command to call the Test routine.
SET var8=25,var7=23
IF var8 = 25 * (var7 < 24) {
WRITE !,"True" }
ELSE {
WRITE !,"False" }
111
Caché evaluates expressions strictly left-to-right. The programmer must use
parentheses to establish any precedence. In this case, Caché first evaluates var8=25,
resulting in 1. It then multiplies this 1 by the results of the expression in parentheses.
Because var7 is less than 24, the expression in parentheses evaluates to 1. Therefore,
Caché multiplies 1 * 1, resulting in 1 (true).
Expressions
SET expr = 22
SET expr = "hello"
SET expr = x
You can create more complex expressions using arrays, operators, or one of the many
ObjectScript functions:
SET expr = +x
SET expr = x + 22
SET expr = array(1)
SET expr = ^data("x",1)
SET expr = $Length(x)
An expression may consist of, or include, an object property, instance method call, or
class method call:
You can directly invoke an ObjectScript routine call within an expression by placing $$
in front of the routine call:
Logical Expressions
Logical expressions use logical operators, numeric relational operators, and string
relational operators. They evaluate expressions and result in a Boolean value: 1 (TRUE)
or 0 (FALSE). Logical expressions are most commonly used with:
The IF command
The $SELECT function
Postconditional Expressions
113
In a Boolean test, any expression that evaluates to a non-zero numeric value returns a
Boolean 1 (TRUE) value. Any expression that evaluates to a zero numeric value returns
a Boolean 0 (FALSE) value. Caché evaluates a non-numeric string as having a zero
numeric value. For further details, refer to String-to-Number Conversion.
You can combine multiple Boolean logical expressions by using logical operators. Like
all Caché expressions, they are evaluated in strict left-to-right order. There are two
types of logical operators: regular logical operators (& and !) and short-circuit logical
operators (&& and ||).
When regular logical operators are used to combine logical expressions, Caché
evaluates all of the specified expressions, even when the Boolean result is known
before all of the expressions have been evaluated. This assures that all expressions are
valid.
When short-circuit logical operators are used to combine logical expressions, Caché
evaluates only as many expressions as are needed to determine the Boolean result. For
example, if there are multiple AND tests, the first expression that returns 0 determines
the overall Boolean result. Any logical expressions to the right of this expression are not
evaluated. This allows you to avoid unnecessary time-consuming expression
evaluations.
In the following example, the IF test uses a regular logical operator (&). Therefore, all
functions are executed even though the first function returns 0 (FALSE) which
automatically makes the result of the entire expression FALSE:
LogExp
IF $$One() & $$Two() {
WRITE !,"Expression is TRUE." }
ELSE {
WRITE !,"Expression is FALSE." }
One()
WRITE !,"one"
QUIT 0
Two()
WRITE !,"two"
QUIT 1
114
In the following example, the IF test uses a short-circuit logical operator (&&). Therefore,
the first function is executed and returns 0 (FALSE) which automatically makes the
result of the entire expression FALSE. The second function is not executed:
LogExp
IF $$One() && $$Two() {
WRITE !,"Expression is TRUE." }
ELSE {
WRITE !,"Expression is FALSE." }
One()
WRITE !,"one"
QUIT 0
Two()
WRITE !,"two"
QUIT 1
LogExp
IF $$One(),$$Two() {
WRITE !,"Expression is TRUE." }
ELSE {
WRITE !,"Expression is FALSE." }
One()
WRITE !,"one"
QUIT 0
Two()
WRITE !,"two"
QUIT 1
Assignment
Within ObjectScript the SET command is used along with the assignment operator ( = )
to assign a value to a variable. The right-hand side of an assignment command is an
expression:
115
SET value = 0
SET value = a + b
Within ObjectScript it is also possible to use certain functions on the left-hand side of an
assignment command:
String-to-Number Conversion
Numeric Strings
The PlusSign and MinusSign property values. By default these are the ―+‖ and ―-‖
characters, but are locale-dependent. Use
the %SYS.NLS.Format.GetFormatItem() method to return the current settings.
The DecimalSeparator property value. By default this is the ―.‖ character, but is
locale-dependent. Use the %SYS.NLS.Format.GetFormatItem() method to return
the current setting.
116
The letters ―e‖, and ―E‖ may be included as part of a numeric string when in a
sequence representing scientific notation, such as 4E3.
Note that the NumericGroupSeparator property value (the ―,‖ character, by default)
is not considered a numeric character. Therefore, the string "123,456" is a partially
numeric string that resolves to the number "123".
Numeric strings and partial numeric strings are converted to canonical form prior to
arithmetic operations (such as addition and subtraction) and greater than/less than
comparison operations (<, >, <=, >=). Numeric strings are not converted to canonical
form prior to equality comparisons (=, '=), because these operators are also used for
string comparisons.
The following example shows less than (<) comparisons of numeric strings:
117
WRITE "0" = 0,! // returns 1
WRITE "-0" = 0,! // returns 0
WRITE "-0" = -0,! // returns 0
Non-numeric Strings
If the leading characters of the string are not numeric characters, the string‘s numeric
value is 0 for all arithmetic operations. For <, >, '>, <=, '<, and >= comparisons a non-
numeric string is also treated as the number 0. Because the equal sign is used for both
the numeric equality operator and the string comparison operator, string comparison
takes precedence for = and '= operations. You can append the PlusSign property value
(+ by default) to force numeric evaluation of a string. This results in the following logical
values, when x and y are different non-numeric strings (for example x=‖Fred‖,
y=‖Wilma‖).
x=y is +x=y is
x=x is TRUE +x=+y is TRUE +x=+x is TRUE
FALSE FALSE
Arithmetic Operators
The arithmetic operators interpret their operands as numeric values and produce
numeric results. When operating on a string, an arithmetic operators treats the string as
its numeric value, according to the rules described in the section ―String-to-Number
Conversion.‖
118
Decimal and $DOUBLE Floating-Point Numbers
The unary positive operator (+) gives its single operand a numeric interpretation. If its
operand has a string value, it converts it to a numeric value. It does this by sequentially
parsing the characters of the string as a number, until it encounters an invalid character.
It then returns whatever leading portion of the string was a well-formed numeric. For
example:
If the string has no leading numeric characters, the unary positive operator gives the
operand a value of zero. For example:
119
WRITE + "Thirty-two dollars and 64 cents" // 0
The unary positive operator has no effect on numeric values. It does not alter the sign of
either positive or negative numbers. For example:
SET x = -23
WRITE " x: ", x,! // -23
WRITE "+x: ",+x,! // -23
The unary negative operator (-) reverses the sign of a numerically interpreted operand.
For example:
SET x = -60
WRITE " x: ", x,! // -60
WRITE "-x: ",-x,! // 60
If its operand has a string value, the unary negative operator interprets it as a numeric
value before reversing its sign. This numeric interpretation is exactly the same as that
performed by the unary positive operator, described above. For example:
SET x = -23
WRITE -"32 dollars and 64 cents" // -32
ObjectScript gives the unary negative operator precedence over the binary arithmetic
operators. ObjectScript first scans a numeric expression and performs any unary
negative operations. Then, ObjectScript evaluates the expression and produces a
result.
In the following example, ObjectScript scans the string and encounters the numeric
value of 2 and stops there. It then applies the unary negative operator to the value and
uses the Concatenate operator (_) to concatenate the value ―Rats‖ from the second
string to the numeric value.
To return the absolute value of a numeric expression, use the $ZABS function.
120
Addition Operator (+)
The addition operator produces the sum of two numerically interpreted operands. It
uses any leading valid numeric characters as the numeric values of the operands and
produces a value that is the sum of the numeric value of the operands.
SET x = 4
SET y = 5
WRITE "x + y = ",x + y // 9
The following example performs string arithmetic on two operands that have leading
digits, adding the resulting numerics:
The following example illustrates that leading zeros on a numerically evaluated operand
do not affect the results the operator produces:
WRITE "007" + 10 // 17
The subtraction operator produces the difference between two numerically interpreted
operands. It interprets any leading, valid numeric characters as the numeric values of
the operand and produces a value that is the remainder after subtraction.
121
SET x = 4
SET y = 5
WRITE "x - y = ",x - y // -1
The following example performs string arithmetic on two operands that have leading
digits, subtracting the resulting numerics:
If the operand has no leading numeric characters, ObjectScript assumes its value to be
zero. For example:
Binary Multiply produces the product of two numerically interpreted operands. It uses
any leading numeric characters as the numeric value of the operands and produces a
result that is the product.
SET x = 4
SET y = 5
WRITE x * y // 20
The following example performs string arithmetic on two operands that have leading
digits, multiplying the resulting numerics:
122
WRITE "8 apples"*"four oranges" // 0
Binary Divide produces the result of dividing two numerically interpreted operands. It
uses any leading numeric characters as the numeric value of the operands and
products a result that is the quotient.
SET x = 4
SET y = 5
WRITE x / y // .8
The following example performs string arithmetic on two operands that have leading
digits, dividing the resulting numerics:
If the operand has no leading numeric characters, Binary Divide assumes its value to be
zero. For example:
When the variables and constants of different types are mixed in an expression ,they
are all converted to the same type .
The compiler converts all operands up to the type of the largest operand , which is
called type promotion .
123
Generally , the lower type of the operator is promoted to higher type operand and the
result will be of the higher type .
Conversion Rules :
The following are the rules applicable to the arithmetic operations between two
operators having different data types .
· If char and short int values are used as operands , the char operand is automatically
elevated to int .
· If float and double values are used as operands , the float operand is automatically
elevated to double .
· If int and float values are used as operands , the int operand is automatically elevated
to float .
· If float and double values are used as operands ,the float is automatically elevated to
double .
· If long and unsigned int are used as operands , both the operands are automatically
elevated to unsigned long.
Type Casting :
This type of conversion is known as type casting . The operators with in C are grouped
hierarchically according to their precedence (i.e, order of evaluation).
Operations with higher precedence are carried out before operations having a lower
precedence . The natural order of evaluation can be altered through the use of
paranthesis.
124
The order in which consecutive operations with in the same precedence group are
carried out is known as associately .with in each of the precedence groups described
above , the associativity is from left to right.
Example Program:
Output :
125
Logical operators
Logical operators are mainly used to control program flow. Usually, you will find them as
part of an if, a while, or some other control statement (Chapter 6)
The concept of logical operators is simple. They allow a program to make a decision
based on multiple conditions. Each operand is considered a condition that can be
evaluated to a true or false value. Then the value of the conditions is used to determine
the overall value of the op1 operator op2 or !op1 grouping. The following examples
demonstrate different ways that logical conditions can be used.
The && operator is used to determine whether both operands or conditions are
true and.pl.
For example:
print("Error!");
};
If either of the two conditions is false or incorrect, then the print command is bypassed.
For example:
print("Error!");
If either of the two conditions is true, then the print command is run.
Caution If the first operand of the || operator evaluates to true, the second operand will
not be evaluated. This could be a source of bugs if you are not careful.
126
For instance, in the following code fragment:
The ! operator is used to convert true values to false and false values to true. In other
words, it inverts a value. Perl considers any non-zero value to be true-even string
values. For example:
$firstVar = 10;
$secondVar = !$firstVar;
if ($secondVar == 0) {
print("zero\n");
};
zero
You could replace the 10 in the first line with "ten," 'ten,' or any non-zero, non-null value.
Bit operations
The following table lists the Bitwise operators supported by C. Assume variable 'A'
holds 60 and variable 'B' holds 13, then −
& Binary AND Operator copies a bit to the result if it exists in both (A & B) =
operands. 12, i.e.,
0000
1100
127
0011
1101
^ Binary XOR Operator copies the bit if it is set in one operand but (A ^ B) =
not both. 49, i.e.,
0011
0001
~ (~A ) =
Binary One's Complement Operator is unary and has the effect ~(60),
of 'flipping' bits. i.e,. 1100
0011
<< Binary Left Shift Operator. The left operands value is moved left A << 2 =
by the number of bits specified by the right operand. 240 i.e.,
1111
0000
>> Binary Right Shift Operator. The left operands value is moved A >> 2 =
right by the number of bits specified by the right operand. 15 i.e.,
0000
1111
Example
Try the following example to understand all the bitwise operators available in C –
#include <stdio.h>
main() {
c = a | b; /* 61 = 0011 1101 */
128
printf("Line 2 - Value of c is %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - Value of c is %d\n", c );
Line 2 - Value of c is 61
Line 3 - Value of c is 49
Line 6 - Value of c is 15
Associativity: It defines the order in which operators of the same precedence are
evaluated in an expression. Associativity can be either from left to right or right to left.
24 + 5 * 4
Here we have two operators + and *, Which operation do you think will be evaluated
first, addition or multiplication? If the addition is applied first then answer will be 116 and
if the multiplication is applied first answer will be 44. To answer such question we need
to consult the operator precedence table.
129
In C, each operator has a fixed priority or precedence in relation to other operators. As a
result, the operator with higher precedence is evaluated before the operator with lower
precedence. Operators that appear in the same group have the same precedence. The
following table lists operator precedence and associativity.
Operators in the top have higher precedence and it decreases as we move towards the
bottom.
From the precedence table, we can conclude that the * operator is above
the + operator, so the * operator has higher precedence than the + operator, therefore
in the expression 24 + 5 * 4, subexpression 5 * 4 will be evaluated first.
130
Here are some more examples:
Example 1:
34 + 12/4 - 45
Here the / operator has higher precedence hence 12/4 is evaluated first. The
operators + and - have the same precedence because they are in the same group. So
which one of them will be evaluated first? To solve this problem you need to consult the
131
associativity of the operator. As you can see in the table, the operators + and - have the
same precedence and associates from left to right therefore in our expression 34 + 12/4
- 45 after division, addition (+) will be performed before subtraction (-).
Using Parentheses
If you look at the precedence table you will find that the precedence of parentheses (())
operator is the highest. Consequently, just as we did in school, we can use parentheses
to change the sequence of operations. Consider the following example:
3+4*2
Here, the * operator will be evaluated first followed by the + operator.
What if you want the addition to take place first followed by multiplication?
(3 + 4) * 2
Whatever you have wrapped inside the parentheses will be evaluated first. As a result,
in this expression the addition will take place first followed by multiplication.
(2 + (3 + 2) ) * 10
In such cases expression inside the innermost parentheses is evaluated first, then the
next innermost parentheses and so on.
We can also use parentheses to make complex expressions a little more readable. For
example:
1 age < 18 && height < 48 || age > 60 && height > 72
2 (age < 18 && height < 48) || (age > 60 && height > 72) // much better than the above
Both expressions give the same result, but adding parentheses makes our intent much
clear.
We haven't yet discussed relational and logical operators. So the above expression
might not make perfect sense. Relational and Logical operators are discussed in detail
in Relational Operators in C and Logical Operators in C, respectively. In the next
chapter, we will learn about the if else statement in C.
132
UNIT III
Conditional Program Execution:
The switch case statement is used when we have multiple options and we need to
perform a different task for each option.
Before we see how a switch case statement works in a C program, let‘s checkout the
syntax of it.
133
Example of Switch Case in C
Let‘s take a simple example to understand the working of a switch case statement in C
program.
#include <stdio.h>
int main()
{
int num=2;
switch(num+2)
{
case 1:
printf("Case1: Value is: %d", num);
case 2:
printf("Case1: Value is: %d", num);
case 3:
printf("Case1: Value is: %d", num);
default:
printf("Default: Value is: %d", num);
}
return 0;
}
Output:
Explanation:
In switch I gave an expression, you can give variable also. I gave num+2, where num
value is 2 and after addition the expression resulted 4. Since there is no case defined
with value 4 the default case is executed.
Before we discuss more about break statement, guess the output of this C program.
#include <stdio.h>
int main()
{
int i=2;
switch (i)
134
{
case 1:
printf("Case1 ");
case 2:
printf("Case2 ");
case 3:
printf("Case3 ");
case 4:
printf("Case4 ");
default:
printf("Default ");
}
return 0;
}
Output:
We can use break statement to break the flow of control after every case block.
Break statements are useful when you want your program-flow to come out of the
switch body. Whenever a break statement is encountered in the switch body, the control
comes out of the switch case statement.
I‘m taking the same above that we have seen above but this time we are using break.
#include <stdio.h>
int main()
{
int i=2;
switch (i)
{
135
case 1:
printf("Case1 ");
break;
case 2:
printf("Case2 ");
break;
case 3:
printf("Case3 ");
break;
case 4:
printf("Case4 ");
break;
default:
printf("Default ");
}
return 0;
}
Output:
Case 2
The control would itself come out of the switch after default so I didn‘t use it, however if
you want to use the break after default then you can use it, there is no harm in doing
that.
1) Case doesn‘t always need to have order 1, 2, 3 and so on. They can have any
integer value after case keyword. Also, case doesn‘t need to be in an ascending order
always, you can specify them in any order as per the need of the program.
#include <stdio.h>
int main()
{
char ch='b';
switch (ch)
{
case 'd':
printf("CaseD ");
break;
136
case 'b':
printf("CaseB");
break;
case 'c':
printf("CaseC");
break;
case 'z':
printf("CaseZ ");
break;
default:
printf("Default ");
}
return 0;
}
Output:
CaseB
3) The expression provided in the switch should result in a constant value otherwise it
would not be valid.
For example:
switch(1+2+23)
switch(1*2+3%4)
switch(ab+cd)
switch(a+b+c)
4) Nesting of switch statements are allowed, which means you can have switch
statements inside another switch. However nested switch statements should be avoided
as it makes program more complex and less readable.
5) Duplicate case values are not allowed. For example, the following program is
incorrect:
This program is wrong because we have two case ‗A‘ here which is wrong as we
cannot have duplicate case values.
#include <stdio.h>
int main()
{
137
char ch='B';
switch (ch)
{
case 'A':
printf("CaseA");
break;
case 'A':
printf("CaseA");
break;
case 'B':
printf("CaseB");
break;
case 'C':
printf("CaseC ");
break;
default:
printf("Default ");
}
return 0;
}
6) The default statement is optional, if you don‘t have a default in the program, it would
run just fine without any issues. However it is a good practice to have a default
statement so that the default executes if no case is matched. This is especially useful
when we are taking input from user for the case choices, since user can sometime enter
wrong value, we can remind the user with a proper error message that we can set in the
default statement.
In 'C' programming conditional statements are possible with the help of the following two
constructs:
1. If statement
2. If-else statement
138
It is also called as branching as a program decides which statement to execute based
on the result of the evaluated condition.
If statement
if (condition)
instruction;
The condition evaluates to either true or false. True is always a non-zero value, and
false is a value that contains zero. Instructions can be a single instruction or a code
block enclosed by curly braces { }.
#include<stdio.h>
int main()
{
int num1=1;
int num2=2;
if(num1<num2) //test-condition
{
printf("num1 is smaller than num2");
}
return 0;
}
Output:
The above program illustrates the use of if construct to check equality of two numbers.
139
1. In the above program, we have initialized two variables with num1, num2 with
value as 1, 2 respectively.
2. Then, we have used if with a test-expression to check which number is the
smallest and which number is the largest. We have used a relational expression
in if construct. Since the value of num1 is smaller than num2, the condition will
evaluate to true.
3. Thus it will print the statement inside the block of If. After that, the control will go
outside of the block and program will be terminated with a successful result.
Relational Operators
C has six relational operators that can be used to formulate a Boolean expression for
making a decision and testing conditions, which returns true or false :
140
== equal to
!= not equal to
Notice that the equal test (==) is different from the assignment operator (=) because it is
one of the most common problems that a programmer faces by mixing them up.
For example:
int x = 41;
x =x+ 1;
if (x == 42) {
printf("You succeed!");}
Output :
You succeed
Keep in mind that a condition that evaluates to a non-zero value is considered as true.
For example:
int present = 1;
if (present)
printf("There is someone present in the classroom \n");
Output :
141
The if-else is statement is an extended version of If. The general form of if-else is as
follows:
if (test-expression)
{
True block of statements
}
Else
{
False block of statements
}
Statements;
n this type of a construct, if the value of test-expression is true, then the true block of
statements will be executed. If the value of test-expression if false, then the false block
of statements will be executed. In any case, after the execution, the control will be
automatically transferred to the statements appearing outside the block of If.
We will initialize a variable with some value and write a program to determine if the
value is less than ten or greater than ten.
Let's start.
#include<stdio.h>
int main()
{
int num=19;
if(num<10)
{
printf("The value is less than 10");
}
else
{
printf("The value is greater than 10");
}
return 0;
}
Output:
142
1. We have initialized a variable with value 19. We have to find out whether the
number is bigger or smaller than 10 using a 'C' program. To do this, we have
used the if-else construct.
2. Here we have provided a condition num<10 because we have to compare our
value with 10.
3. As you can see the first block is always a true block which means, if the value of
test-expression is true then the first block which is If, will be executed.
4. The second block is an else block. This block contains the statements which will
be executed if the value of the test-expression becomes false. In our program,
the value of num is greater than ten hence the test-condition becomes false and
else block is executed. Thus, our output will be from an else block which is "The
value is greater than 10". After the if-else, the program will terminate with a
successful result.
In 'C' programming we can use multiple if-else constructs within each other which are
referred to as nesting of if-else statements.
143
Conditional Expressions
For example:
#include <stdio.h>
int main() {
int y;
int x = 2;
y = (x >= 6) ? 6 : x;/* This is equivalent to: if (x >= 5) y = 5; else y = x; */
printf("y =%d ",y);
return 0;}
Output :
y =2
When a series of decision is required, nested if-else is used. Nesting means using one
if-else construct within another one.
#include<stdio.h>
int main()
{
int num=1;
if(num<10)
{
if(num==1)
{
printf("The value is:%d\n",num);
}
else
{
printf("The value is greater than 1");
}
}
else
{
printf("The value is greater than 10");
}
144
return 0;
}
Output:
The above program checks if a number is less or greater than 10 and prints the result
using nested if-else construct.
1. Firstly, we have declared a variable num with value as 1. Then we have used if-
else construct.
2. In the outer if-else, the condition provided checks if a number is less than 10. If
the condition is true then and only then it will execute the inner loop. In this case,
the condition is true hence the inner block is processed.
145
3. In the inner block, we again have a condition that checks if our variable contains
the value 1 or not. When a condition is true, then it will process the If block
otherwise it will process an else block. In this case, the condition is true hence
the If a block is executed and the value is printed on the output screen.
4. The above program will print the value of a variable and exit with success.
Try changing the value of variable see how the program behaves.
NOTE: In nested if-else, we have to be careful with the indentation because multiple if-
else constructs are involved in this process, so it becomes difficult to figure out
individual constructs. Proper indentation makes it easy to read the program.
The general syntax of how else-if ladders are constructed in 'C' programming is as
follows:
if (test - expression 1) {
statement1;
} else if (test - expression 2) {
Statement2;
} else if (test - expression 3) {
Statement3;
} else if (test - expression n) {
Statement n;
} else {
default;
}
Statement x;
This type of structure is known as the else-if ladder. This chain generally looks like a
ladder hence it is also called as an else-if ladder. The test-expressions are evaluated
from top to bottom. Whenever a true test-expression if found, statement associated with
it is executed. When all the n test-expressions becomes false, then the default else
statement is executed.
#include<stdio.h>
int main()
{
int marks=83;
if(marks>75){
146
printf("First class");
}
else if(marks>65){
printf("Second class");
}
else if(marks>55){
printf("Third class");
}
else{
printf("Fourth class");
}
return 0;
}
Output:
First class
The above program prints the grade as per the marks scored in a test. We have used
the else-if ladder construct in the above program.
147
1. We have initialized a variable with marks. In the else-if ladder structure, we have
provided various conditions.
2. The value from the variable marks will be compared with the first condition since
it is true the statement associated with it will be printed on the output screen.
3. If the first test condition turns out false, then it is compared with the second
condition.
4. This process will go on until the all expression is evaluated otherwise control will
go out of the else-if ladder, and default statement will be printed.
Try modifying the value and notice the change in the output.
Summary
Decision making or branching statements are used to select one path based on
the result of the evaluated expression.
We can also nest if-else within one another when multiple paths have to be
tested.
The else-if ladder is used when we have to check various ways based upon the
result of the expression.
In this tutorial, we will discuss what are Java switch statements, how to use them, the
allowed data types that can be used in the switch statements and the advantages and
restrictions that apply to them.
Contents hide
1 What is a ―switch‖ statement
2 How to use a switch statement
3 How does the ―break‖ keyword work
4 The ―default‖ case
5 Advantages of using a switch statement over a traditional if-else cascade
6 Restrictions on switch statements
6.1 Accepted data types to the switch statement input
6.2 Configuration restrictions to the switch cases
7 Summary
8 Related Posts
148
What is a ―switch‖ statement
An analogy can be drawn from the good old days with a telephone switch board. A
person calls the switch board staff and asks to be routed to a specific number, and the
operator on the switch board will connect your call to a specific routing port, depending
on the number you as for.
The following is an example of a switch statement. The switch statement is fed the
character value ―grade‖, and one of the paths will be executed depending on the value
of grade.
package com.nullbeans;
switch (grade){
case 'Á': System.out.println("Excellent!"); break;
case 'B': System.out.println("Very good!"); break;
case 'C': System.out.println("Average!"); break;
case 'D': System.out.println("Poor!"); break;
case 'E': System.out.println("Very poor!"); break;
case 'F': System.out.println("Failed"); break;
}
}
}
Very good!
149
Let us go over some keywords in that example:
switch: This signifies the start of a switch statement. The switch statement takes a
single input value to be evaluated.
case: The ―case‖ keyword‖ signifies an entry point for execution. Each case is defined
for a specific value. The entry point can be entered if the input value to the switch
statement matches the one in the case. As you can see in our example, since we used
the value ―B‖, we started the execution from the ―case B‖ part of the switch statement.
break: The ―break‖ keyword signals the program to exit the switch statement. It is not
mandatory to have the break keyword in each case. However, if it is missing, the
program will not exit the switch statement and will continue executing until either a
break statement is found, or we exit the program. Let us discuss this in more details in
the next section.
The break keyword is a java keyword that allows the execution to exit from its current
conditional scope. For example, if it is inside a ―while‖ loop, the program will skip the
execution of the loop and will exit the loop‘s scope. Similarly, if the break keyword is
encountered inside a switch statement, it will prompt Java to exit the while switch
statement.
Take for example the following diagram. Since the code of every case is followed by a
―break‖, only that code will be executed.
This diagram illustrates a switch statement with a break after each case. Since there is
a break after each case, only the code related to the single matching case is executed.
(Click to enlarge)
In our previous program, only one statement was executed, since after each case, a
break keyword was present. So what if we did not have a break keyword? Then the
program will continue execution until either a break statement is encountered or the end
of the switch statement is reached.
This diagram illustrates a switch statement where case 1 and case 3 do not have the
break keywords. Using this setup, if X is equal to 1, then the code from case 1 and 2 is
executed. The program stops at case 2 because there is a break keyword there. If X is
equal to 2, then only the code from case 2 is executed. If X is equal to 3, then the code
from case 3 is executed and the switch statement is terminated. (Click to enlarge)
150
Let us discuss the next example. The following program is used to print out the features
a customer would get when they choose a hosting plan from our imaginary web hosting
provider. We can describe the plans as follows:
Our plans start with a ―Basic‖ package with 2 free domain names.
Then there is a ―Basic plus‖ plan, which includes whatever is in the ―Basic‖ plan
plus unlimited bandwidth.
Then comes the ―Premium‖ plan which includes whatever is in ―Basic plus‖ and
―Basic‖, plus an extra 1GB of RAM.
And finally, there comes the ―Premium plus‖ plan. The plan includes whatever is
in the ―Premium‖, the ―Basic plus‖ and the ―Basic‖, plus an extra 1 CPU.
Now, let us model this program in Java using a switch statement. Since we can ristrict
the entry point using the ―case‖ keyword, we can write our program in a way that
includes all the correct features by simply defining the switch case order from the most
inclusive case to the least inclusive.
switch(hostingPlan){
Notice here that the println statement of the ―Premium plus‖ case was not executed as
the program did not enter the switch statement in this case. The program entered from
the ―Premium‖ case. Notice also that, even though the input value ―Premium‖ did not
match the ―Basic plus‖ and ―Basic‖ cases, the statements from these cases were
151
executed anyway. This is because the break statement was missing. Therefore,
nothing stopped the execution of the rest of the switch statement cases.
What if the input to the switch statement did not match any of the cases? Then non of
the statements would be executed. What if we wanted to print out an error, to tell the
user that they inserted an unrecognized value? The default case comes to the rescue.
The default case is a a switch statement case which is executed if non of the
other switch cases matches the switch statement input. Let us modify our previous
example to include a default case.
switch(hostingPlan){
Notice that we added the ―break‖ keyword after the ―Basic‖ case in order to stop the
execution of the switch statement if one of the cases match. Now let us run the
program.
Since non of the switch cases matches the input ―Super premium‖, the default case was
executed, Please note that the default case does not need to be the last case in the
switch statement. It can be added at the beginning or in the middle of the cases. It will
behave just like any other entry point. But in the ―default‖ case, it is entered only when
no other case is matched.
152
Advantages of using a switch statement over a traditional if-else cascade
While it is true that the same functionalities of the switch statement can also be
implemented using an if-else cascade, the switch statement allows us in certain
situations to write a more clear, compact and readable code.
if(hostingPlan.equals("Premium plus")){
System.out.println("- Extra 1 CPU");
System.out.println("- Extra 1GB RAM");
System.out.println("- Unlimited bandwidth");
System.out.println("- 2 Domain names");
}else if(hostingPlan.equals("Premium")){
System.out.println("- Extra 1GB RAM");
System.out.println("- Unlimited bandwidth");
System.out.println("- 2 Domain names");
}else if(hostingPlan.equals("Basic plus")){
System.out.println("- Unlimited bandwidth");
System.out.println("- 2 Domain names");
}else if(hostingPlan.equals("Basic")){
System.out.println("- 2 Domain names");
}else {
System.out.println("Hosting plan not recognized");
}
Notice that we have to perform a lot of code repetition. This is not ideal as if we need to
change something, we would have to change it in other places as well. This is error
prone and time consuming. For example, if we decide to provide 3 domain names
instead of 2, then we will have to update the if-then part of each if statement.
While switch statements can be very efficient and cleaner, they also have certain
restrictions. Let us go through these restrictions one by one.
153
Accepted data types to the switch statement input
The switch statement will accept the following data types as input:
byte
short
int
long
char
String (only Java version 7 and above)
Byte
Short
Integer
Long
Enum
Unlike if statements and the conditional operator, floating point numbers and other
Objects are not allowed to be used inside a switch statement.
Another restriction that comes to switch statements are the values provided to the case
configurations. Each case should be configured with either a constant value or a
final value variable. Otherwise, the program will not compile.
switch (x){
switch (x){
154
//.....
However, if we remove the final keyword as in the example below, we will get an error
that a ―constant expression is required‖.
switch (x){
Another restriction is that while switch statement inputs can be an Object such as
Integer, Byte, etc (as mentioned in the previous section), switch cases are more
restrictive and allow only primitive data types (int, short, byte, long, char), String
and enums.
Summary
In this post, we discussed how to use a Java switch statement. We discussed what is
the break keyword and how to use it. We also discussed the default keyword and its
purpose. We also discussed some of the advantages of using a switch statement over a
traditional if-then-else cascade. Finally, we discussed what are the restriction that apply
to switch statement inputs and case configurations.
In the last topic, we studied different types of loops. We also saw how loops can be
nested.
Normally, if we have to choose one case among many choices, if-else is used. But if the
number of choices is large, switch..case makes it a bit easier and less complex.
155
switch...case is another way to control and decide the execution of statements other
than if/else. This is used when we are given a number of choices (cases) and we want
to perform a different task for each choice.
Let's first have a look at its syntax.
switch(expression)
{
case constant1:
statement(s);
break;
case constant2:
statement(s);
break;
/* you can give any number of cases */
default:
statement(s);
}
#include <stdio.h>
int main()
{
char grade ;
printf("Enter your grade\n");
scanf(" %c" , &grade);
switch(grade)
{
case 'A':
printf("Excellent!\n");
break;
case 'B':
printf("Outstanding!\n");
156
break;
case 'C':
printf("Good!\n");
break;
case 'D':
printf("Can do better\n");
break;
case 'E':
printf("Just passed\n");
break;
case 'F':
printf("You failed\n");
break;
default:
printf("Invalid grade\n");
}
return 0;
}
Output
break is used to break or terminate a loop whenever we want and is also used
with switch.
In this example, the value of 'grade' is 'D'. Since the value of the constants of the first
three cases is not 'D', so case 'D' will be executed and 'Can do better' will be printed.
Then break statement will terminate the execution without checking the rest of the
cases.
If there is no break in any statement, then after execution of the correct case, every
case will also be executed. Look at the following code for an example.
#include <stdio.h>
int main()
{
157
char grade ;
printf("Enter your grade\n");
scanf(" %c" , &grade);
switch(grade)
{
case'A':
printf("Excellent!\n");
case 'B':
printf("Outstanding!\n");
case 'C':
printf("Good!\n");
case 'D':
printf("Can do better\n");
case 'E':
printf("Just passed\n");
case 'F':
printf("You failed\n");
default:
printf("Invalid grade\n");
}
return 0;
}
Output
158
In the above example, value of grade is 'D', so the control jumped to case 'D'. Since
there is no break statement after any case, so all the statements after case 'D' also get
executed.
As you can see, all the cases after case D have been executed.
If you want to execute only that case whose constant value equals the value of
expression of the switch statement, then use the break statement.
Always enclose the character values within ' '.
Now let's see an example with the expression value as an integer.
#include <stdio.h>
int main()
{
int i = 2;
switch(i)
{
case 1:
printf("Number is 1\n");
break;
case 2:
printf("Number is 2\n");
break;
default:
printf("Number is greater than 2\n");
}
return 0;
}
Output
159
We can also terminate a loop in the middle of its execution using break. Just
type break; after the statement after which you want to break the loop. As simple as
that!
Let's consider an example.
#include <stdio.h>
int main()
{
int a;
for(a = 1; a <= 10; a ++)
{
printf("Hello World\n");
if(a == 2)
{
//loop will now stop
break;
}
}
return 0;
}
Output
In this example, after the first iteration of the loop, a++ increases the value of 'a' to 2
and 'Hello World' got printed. Since the condition of if satisfies this time, break will be
executed and the loop will terminate.
Continue
The continue statement works similar to break statement. The only difference is
that break statement terminates the loop whereas continue statement passes control to
the conditional test i.e., where the condition is checked, skipping the rest of the
statements of the loop.
#include <stdio.h>
int main()
160
{
int a ;
for(a = 1; a <= 10; a ++)
{
printf("Hello World\n");
if (a == 2)
{
//this time further statements will not be executed. Control will go to for
continue;
}
printf("a is not 2\n");
}
return 0;
}
Output
Notice that at the second time, 'a is not 2' is not printed. It means that when 'a' was 2,
then 'continue' got executed and control went to for loop without executing further
codes.
Uses of while
A Loop executes the sequence of statements many times until the stated condition
becomes false. A loop consists of two parts, a body of a loop and a control statement.
The control statement is a combination of some conditions that direct the body of the
loop to execute until the specified condition becomes false. The purpose of the loop is
to repeat the same code a number of times.
Types of Loops in C
While Loop in C
Do-While loop in C
161
For loop in C
Break Statement in C
Continue Statement in C
Which loop to Select?
Types of Loops in C
In an exit controlled loop, a condition is checked after executing the body of a loop. It
is also called as a post-checking loop.
Sample Loop
162
The control conditions must be well defined and specified otherwise the loop will
execute an infinite number of times. The loop that does not stop executing and
processes the statements number of times is called as an infinite loop. An infinite loop
is also called as an "Endless loop." Following are some characteristics of an infinite
loop:
The specified condition determines whether to execute the loop body or not.
While Loop in C
A while loop is the most straightforward looping structure. Syntax of while loop in C
programming language is as follows:
while (condition) {
statements;
}
After exiting the loop, the control goes to the statements which are immediately after the
loop. The body of a loop can contain more than one statement. If it contains only one
statement, then the curly braces are not compulsory. It is a good practice though to use
the curly braces even we have a single statement in the body.
In while loop, if the condition is not true, then the body of a loop will not be executed, not
even once. It is different in do while loop which we will see shortly.
#include<stdio.h>
163
#include<conio.h>
int main()
{
int num=1; //initializing the variable
while(num<=10) //while loop with condition
{
printf("%d\n",num);
num++; //incrementing operation
}
return 0;
}
Output:
1
2
3
4
5
6
7
8
9
10
The above program illustrates the use of while loop. In the above program, we have
printed series of numbers from 1 to 10 using a while loop.
164
1. We have initialized a variable called num with value 1. We are going to print from
1 to 10 hence the variable is initialized with value 1. If you want to print from 0,
then assign the value 0 during initialization.
2. In a while loop, we have provided a condition (num<=10), which means the loop
will execute the body until the value of num becomes 10. After that, the loop will
be terminated, and control will fall outside the loop.
3. In the body of a loop, we have a print function to print our number and an
increment operation to increment the value per execution of a loop. An initial
value of num is 1, after the execution, it will become 2, and during the next
execution, it will become 3. This process will continue until the value becomes 10
and then it will print the series on console and terminate the loop.
\n is used for formatting purposes which means the value will be printed on a new line.
Do-While loop in C
A do...while loop in C is similar to the while loop except that the condition is always
executed after the body of a loop. It is also called an exit-controlled loop.
do {
statements
} while (expression);
As we saw in a while loop, the body is executed if and only if the condition is true. In
some cases, we have to execute a body of the loop at least once even if the condition is
false. This type of operation can be achieved by using a do-while loop.
In the do-while loop, the body of a loop is always executed at least once. After the body
is executed, then it checks the condition. If the condition is true, then it will again
execute the body of a loop otherwise control is transferred out of the loop.
Similar to the while loop, once the control goes out of the loop the statements which are
immediately after the loop is executed.
The critical difference between the while and do-while loop is that in while loop the while
is written at the beginning. In do-while loop, the while condition is written at the end and
terminates with a semi-colon (;)
#include<stdio.h>
#include<conio.h>
165
int main()
{
int num=1; //initializing the variable
do //do-while loop
{
printf("%d\n",2*num);
num++; //incrementing operation
}while(num<=10);
return 0;
}
Output:
2
4
6
8
10
12
14
16
18
20
In the above example, we have printed multiplication table of 2 using a do-while loop.
Let's see how the program was able to print the series.
166
1. First, we have initialized a variable 'num' with value 1. Then we have written a
do-while loop.
2. In a loop, we have a print function that will print the series by multiplying the
value of num with 2.
3. After each increment, the value of num will increase by 1, and it will be printed on
the screen.
4. Initially, the value of num is 1. In a body of a loop, the print function will be
executed in this way: 2*num where num=1, then 2*1=2 hence the value two will
be printed. This will go on until the value of num becomes 10. After that loop will
be terminated and a statement which is immediately after the loop will be
executed. In this case return 0.
For loop in C
A for loop is a more efficient loop structure in 'C' programming. The general structure of
for loop syntax in C is as follows:
#include<stdio.h>
int main()
{
int number;
for(number=1;number<=10;number++) //for loop to print 1-10 numbers
{
printf("%d\n",number); //to print the number
}
return 0;
}
Output:
167
1
2
3
4
5
6
7
8
9
10
The above program prints the number series from 1-10 using for loop.
2. In for loop, in the initialization part, we have assigned value 1 to the variable
number. In the condition part, we have specified our condition and then the
increment part.
3. In the body of a loop, we have a print function to print the numbers on a new line
in the console. We have the value one stored in number, after the first iteration
the value will be incremented, and it will become 2. Now the variable number has
the value 2. The condition will be rechecked and since the condition is true loop
will be executed, and it will print two on the screen. This loop will keep on
168
executing until the value of the variable becomes 10. After that, the loop will be
terminated, and a series of 1-10 will be printed on the screen.
In C, the for loop can have multiple expressions separated by commas in each part.
For example:
Also, we can skip the initial value expression, condition and/or increment by adding a
semicolon.
For example:
int i=0;
int max = 10;
for (; i < max; i++) {
printf("%d\n", i);
}
Notice that loops can also be nested where there is an outer loop and an inner loop. For
each iteration of the outer loop, the inner loop repeats its entire cycle.
Consider the following example, that uses nested for loop in C programming to output a
multiplication table:
#include <stdio.h>
int main() {
int i, j;
int table = 2;
int max = 5;
for (i = 1; i <= table; i++) { // outer loop
for (j = 0; j <= max; j++) { // inner loop
printf("%d x %d = %d\n", i, j, i*j);
}
printf("\n"); /* blank line between tables */
}}
Output:
1x0=0
1x1=1
169
1x2=2
1x3=3
1x4=4
1x5=5
2x0=0
2x1=2
2x2=4
2x3=6
2x4=8
2 x 5 = 10
The nesting of for loops can be done up-to any level. The nested loops should be
adequately indented to make code readable. In some versions of 'C,' the nesting is
limited up to 15 loops, but some provide more.
The nested loops are mostly used in array applications which we will see in further
tutorials.
Break Statement in C
The break statement is used mainly in in the switch statement. It is also useful for
immediately stopping a loop.
We consider the following program which introduces a break to exit a while loop:
#include <stdio.h>
int main() {
int num = 5;
while (num > 0) {
if (num == 3)
break;
printf("%d\n", num);
num--;
}}
Output:
5
4
170
Continue Statement in C
When you want to skip to the next iteration but remain in the loop, you should use the
continue statement.
For example:
#include <stdio.h>
int main() {
int nb = 7;
while (nb > 0) {
nb--;
if (nb == 5)
continue;
printf("%d\n", nb);
}}
Output:
6
4
3
2
1
Selection of a loop is always a tough task for a programmer, to select a loop do the
following steps:
Analyze the problem and check whether it requires a pre-test or a post-test loop.
Summary
171
A block of looping statements in C are executed for number of times until the
condition becomes false.
In this tutorial, you will learn to create while and do...while loop in C programming with
the help of examples.
In programming, loops are used to repeat a block of code until a specified condition is
met.
1. for loop
2. while loop
3. do...while loop
In the previous tutorial, we learned about for loop. In this tutorial, we will learn
about while and do..while loop.
while loop
while (testExpression)
{
// statements inside the body of the loop
}
172
How while loop works?
The while loop evaluates the test expression inside the parenthesis ().
If the test expression is true, statements inside the body of while loop are executed.
Then, the test expression is evaluated again.
The process goes on until the test expression is evaluated to false.
To learn more about test expression (when the test expression is evaluated to true and
false), check out relational and logical operators.
173
// Print numbers from 1 to 5
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 5)
{
printf("%d\n", i);
++i;
}
return 0;
}
Output
1
2
3
4
5
do...while loop
The do..while loop is similar to the while loop with one important difference. The body
of do...while loop is executed at least once. Only then, the test expression is evaluated.
The syntax of the do...while loop is:
do
174
{
// statements inside the body of the loop
}
while (testExpression);
The body of do...while loop is executed once. Only then, the test expression is
evaluated.
If the test expression is true, the body of the loop is executed again and the test
expression is evaluated.
printf("Sum = %.2lf",sum);
return 0;
}
Output
C programming allows to use one loop inside another loop. The following section shows
a few examples to illustrate the concept.
Syntax
176
for ( init; condition; increment ) {
while(condition) {
while(condition) {
statement(s);
}
statement(s);
}
The syntax for a nested do…while loop statement in C programming language is as
follows −
do {
statement(s);
do {
statement(s);
}while( condition );
}while( condition );
A final note on loop nesting is that you can put any type of loop inside any other type of
loop. For example, a ‗for‘ loop can be inside a ‗while‘ loop or vice versa.
Example
The following program uses a nested for loop to find the prime numbers from 2 to 100
− Live Demo
#include <stdio.h>
int main () {
177
if(!(i%j)) break; // if factor found, not prime
if(j > (i/j)) printf("%d is prime\n", i);
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
2 is prime
3 is prime
5 is prime
7 is prime
11 is prime
13 is prime
17 is prime
19 is prime
23 is prime
29 is prime
31 is prime
37 is prime
41 is prime
43 is prime
47 is prime
53 is prime
59 is prime
61 is prime
67 is prime
71 is prime
73 is prime
79 is prime
83 is prime
89 is prime
97 is prime
assignment operators
The following table lists the assignment operators supported by the C language −
178
operands to left side operand of A + B
to C
179
&= Bitwise AND assignment operator. C &= 2 is
same as
C=C&2
Example
Try the following example to understand all the assignment operators available in C –
#include <stdio.h>
main() {
int a = 21;
int c ;
c = a;
printf("Line 1 - = Operator Example, Value of c = %d\n", c );
c += a;
printf("Line 2 - += Operator Example, Value of c = %d\n", c );
c -= a;
printf("Line 3 - -= Operator Example, Value of c = %d\n", c );
c *= a;
printf("Line 4 - *= Operator Example, Value of c = %d\n", c );
c /= a;
printf("Line 5 - /= Operator Example, Value of c = %d\n", c );
c = 200;
c %= a;
180
printf("Line 6 - %= Operator Example, Value of c = %d\n", c );
c <<= 2;
printf("Line 7 - <<= Operator Example, Value of c = %d\n", c );
c >>= 2;
printf("Line 8 - >>= Operator Example, Value of c = %d\n", c );
c &= 2;
printf("Line 9 - &= Operator Example, Value of c = %d\n", c );
c ^= 2;
printf("Line 10 - ^= Operator Example, Value of c = %d\n", c );
c |= 2;
printf("Line 11 - |= Operator Example, Value of c = %d\n", c );
}
When you compile and execute the above program, it produces the following result −
Line 1 - = Operator Example, Value of c = 21
Line 2 - += Operator Example, Value of c = 42
Line 3 - -= Operator Example, Value of c = 21
Line 4 - *= Operator Example, Value of c = 441
Line 5 - /= Operator Example, Value of c = 21
Line 6 - %= Operator Example, Value of c = 11
Line 7 - <<= Operator Example, Value of c = 44
Line 8 - >>= Operator Example, Value of c = 11
Line 9 - &= Operator Example, Value of c = 2
Line 10 - ^= Operator Example, Value of c = 0
Line 11 - |= Operator Example, Value of c = 2
Just think what will you do when you want to jump out of the loop even if the condition is
true or continue repeated execution of code skipping some of the parts?
181
For this C provides break and continue statements. By the help of these statements, we
can jump out of loop anytime and able continue looping by skipping some part of the
code.
It interrupts the flow of the program by breaking the loop and continues the execution of
code which is outside the loop.
The common use of break statement is in switch case where it is used to skip remaining
part of the code.
182
Structure of Break statement
In while loop
while (test_condition)
statement1;
if (condition )
break;
statement2;
In do…while loop
do
statement1;
if (condition)
break;
statement2;
}while (test_condition);
In for loop
183
for (int-exp; test-exp; update-exp)
statement1;
if (condition)
break;
statement2;
Now in above structure, if test_condition is true then the statement1 will be executed
and again if the condition is true then the program will encounter break statement which
will cause the flow of execution to jump out of loop and statement2 below if statement
will be skipped.
Programming Tips
break statement is always used with if statement inside a loop and loop will be
terminated whenever break statement is encountered.
Example: C program to take input from the user until he/she enters zero.
#include <stdio.h>
int main ()
int a;
while (1)
184
printf("enter the number:");
scanf("%d", &a);
if ( a == 0 )
break;
return 0;
Explanation
In above program, while is an infinite loop which will be repeated forever and there is no
exit from the loop.
So the program will ask for input repeatedly until the user will input 0.
When the user enters zero, the if condition will be true and the compiler will encounter
the break statement which will cause the flow of execution to jump out of the loop.
When used in while, for or do...while loop, it skips the remaining statements in the body
of that loop and performs the next iteration of the loop.
Unlike break statement, continue statement when encountered doesn‘t terminate the
loop, rather interrupts a particular iteration.
185
How continue statement work?
while (test_condition)
statement1;
186
if (condition )
continue;
statement2;
In do…while loop
do
statement1;
if (condition)
continue;
statement2;
}while (test_condition);
In for loop
statement1;
if (condition)
continue;
187
statement2;
Explanation
In above structures, if test_condition is true then the continue statement will interrupt the
flow of control and block of statement2 will be skipped, however, iteration of the loop will
be continued.
int main ()
int a,sum = 0;
if ( a % 2 == 0 )
continue;
sum = sum + a;
printf("sum = %d",sum);
return 0;
188
}
Output
sum = 25
Modular Programming:
I will call what you are passing in a to a function the actual parameters, and where you
receive them, the parameters in the function, the formal parameters. They are also
called actual and formal arguments.
When passing parameters, what it is called and what happens can be confusing. It is
less essential that you call it the "correct" thing than you know exactly what is
happening. It is critical to have a good mental model, a valid memory picture of the
process.
Recall that when you call a function, a chunk of memory called an activation record is
allocated. Critical to the discussion here is that this memory holds the formal parameter
values and function local variables.
By definition, pass by value means you are making a copy in memory of the actual
parameter's value that is passed in, a copy of the contents of the actual parameter. Use
pass by value when when you are only "using" the parameter for some computation, not
changing it for the client program.
In pass by reference (also called pass by address), a copy of the address of the actual
parameter is stored. Use pass by reference when you are changing the parameter
passed in by the client program.
Consider a swapping function to demonstrate pass by value vs. pass by reference. This
function, which swaps ints, cannot be done in Java.
main() {
int i = 10, j = 20;
swapThemByVal(i, j);
cout << i << " " << j << endl; // displays 10 20
swapThemByRef(i, j);
cout << i << " " << j << endl; // displays 20 10
...
}
189
void swapThemByVal(int num1, int num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
Contrast this with passing by reference. The addresses of i and j are passed
(noted by the arrows) by reference. The compiler knows they are references so when
the parameters are referred to in the function, the compiler dereferences num1 and
num2 automatically so i and j of main's memory are changed.
+-------------+
swapThemByRef: |+--+ |
||..| temp |
main: |+--+ |
+----+ |+--+ |
i | 10 | <-------------||--| num1 |
+----+ |+--+ |
+----+ |+--+ |
j | 20 | <-------------||--| num2 |
+----+ |+--+ |
+-------------+
190
After the assignments:
+-------------+
swapThemByRef: |+--+ |
||10| temp |
main: |+--+ |
+----+ |+--+ |
i | 20 | <-------------||--| num1 |
+----+ |+--+ |
+----+ |+--+ |
j | 10 | <-------------||--| num2 |
+----+ |+--+ |
+-------------+
This is the essence of pass by value vs. pass by reference. It doesn't matter if the
parameters are primitive types, arrays, or objects, either a copy is made or an address
is stored. As noted elsewhere, when objects are copied, the copy constructor is called
to do the copying.
Typically if you aren't going to change a variable, you use pass by value. But if you are
passing something in that uses a lot of memory, i.e., passing an object or passing an
array, even if you aren't changing it, you use what I like to call fake pass by value.
For efficiency, you pass by reference so only the address is passed, but you put
a const in front of it. This casts it to a constant for use in the function. Note that if this
function passes to some other function, it is now constant object or array. For example:
main() {
SomeBigClass x(100);
// initialize and do whatever with x
doSomething(x);
...
}
Scope of an identifier is the part of the program where the identifier may directly be
accessible. In C, all identifiers are lexically(or statically) scoped. C scope rules can be
covered under the following two categories.
There are basically 4 scope rules:
191
SCOPE MEANING
Scope of a Identifier starts at the beginning of the file and ends at the
end of the file. It refers to only those Identifiers that are declared
outside of all functions. The Identifiers of File scope are visible all
File Scope over the file Identifiers having file scope are global
the end of the block / ‗}‘. Identifiers with block scope are local to their
Function
Scope prototype
Function scope begins at the opening of the function and ends with
Function declared is used as a target to goto statement and both goto and
Example 1:
#include <stdio.h>
192
// Global variable
int global = 5;
// main function
int main()
{
printf("Before change within main: ");
display();
separate compilation
C++ supports separate compilation, where pieces of the program can be compiled
independently through the two stage approach of compilation and then linking, so
changes to one class would not necessarily require the re-compilation of the other
classes. The compiled pieces of code ( .o or .obj files)[8] are combined through the use
of the linker (in the use of Borland C++ it is ilink32.exe). Separate compilation allows
programs to be compiled and tested one class at a time, even built into libraries for later
use. It is therefore good practice to place each class in a separate source file to take full
advantage of separate compilation with the C++ language.
193
The header file contains the declarations for the methods contained in the cpp file,
allowing for these cpp files to be compiled into libraries. The cpp file will define the
methods and by including the header file within the cpp file you will ensure consistency
between the declarations and definitions.
So the Account class would take the form of three separate files:
Application.cpp - That stores the application, i.e. the main() method for the
application.
1
2
3 #include<iostream>
4 #include<string>
5
6 using std::string; // only string is required
7
8 class Account{
9
10 protected:
11
12 int accountNumber;
13 float balance;
14 string owner;
15
16 public:
17
18 Account(string owner, float aBalance, int anAccountNumber);
19 Account(float aBalance, int anAccountNumber);
20 Account(int anAccountNumber);
21 Account(const Account &sourceAccount);
22
23 ...
24 };
25
You should not place using directives in header files where possible. If we were to
use using namespace std; in our header file, all cpp files that include this header
would also include this using directive. This would have the effect of turning off
namespaces in your project (in this case for std only).
194
The implementation file (Account.cpp) will have the form:
#include "Account.h"
Account::Account(int anAccNumber):
accountNumber(anAccNumber), balance(0.0f),
owner ("Not Defined") {}
...
#include "Account.h"
int main()
{
Account a = Account("Derek Molloy",35.00,34234324);
...
}
To compile the application, you must now specify the files to be used in the compilation.
So, to compile all the files at once use: bcc32 Application.cpp Account.cpp, where
one of the source files contains a main() method. This can be seen in Figure 3.11,
―Compilation, and the output from the Separately Compiled Example.‖.
195
Figure 3.11. Compilation, and the output from the Separately Compiled Example.
#define PI 3.14
#undef (removes definition), #if, #ifdef, #ifndef, #endif, #else, #elif (control directives to
remove part of a program depending on the condition),
#ifndef MAX_WIDTH
#define MAX_WIDTH 1000
#endif
196
#line (allows control over compile time error messages), #error (allows us to abort
compilation if required), e.g.
#ifndef __cplusplus
#error You need a C++ compiler for this code!
#endif
and #pragma (used for compiler options specific to a particular platform and compiler).
If there are multiple classes, some of which use the same parent, you can use compiler
directives to prevent the re-definition of the same class, which would result in a compiler
error. These directives can be placed around the class definition such as:
protected:
float overDraftLimit;
...
public:
#endif // currentAcount_h
In this case, the compiler directives simply state that if the CurrentAccount class is
already defined then do not redefine it. This is determined by
the currentAccount_h value, that if undefined is simply defined, and so used as a flag.
This process is to ensure that we have not broken the C++ single definition rule: You
can declare anything as many times as you want, but you can only define it once.
197
Linkage
Genetic linkage describes the way in which two genes that are located close to each
other on a chromosome are often inherited together. In 1905, William Bateson, Edith
Rebecca Saunders, and Reginald C. Punnett noted that the traits for flower color and
pollen shape in sweet pea plants appeared to be linked together. A few years later, in
1911, Thomas Hunt Morgan, who was studying heredity in fruit flies, noticed that the
eye color of a fly was associated with the fly's sex and hypothesized that the two traits
were linked together. These observations led to the concept of genetic linkage, which
describes how two genes that are closely associated on the same chromosome are
frequently inherited together. In fact, the closer two genes are to one another on a
chromosome, the greater their chances are of being inherited together or linked. In
contrast, genes located farther away from each other on the same chromosome are
more likely to be separated during recombination, the process that recombines DNA
during meiosis. The strength of linkage between two genes, therefore, depends upon
the distance between the genes on the chromosome.
This chapter describes how to create your own RADIUS module. Extending the
RADIUS server is a task for advanced users with special requirements. Creating new
modules requires C or C++ programming skills and an understanding of the RADIUS
protocol and thread programming.
Before creating your own module, be sure that the task you wish to accomplish cannot
be performed by one of the modules supplied with the RADIUS Manager.
You may write a custom module which authenticates and modifies incoming packets to
handle special conditions. You also might want to modify logins to provide greater
flexibility in managing requests. With custom modules, you can:
198
Authenticate a request against an alternate database.
Use mod_example as a template for your new module. Customize the required
sections, and link your custom modules with the core functionality module libraries to
produce new RADIUS server binaries.
This checklist provides an overview of tasks that must be performed when you create a
custom module. To create a custom module:
7. Build your custom module and link it with the libraries to produce a
new radiusid executable:
199
Modifying the Definitions File
....
ModuleDefFlags theFlags);
#ifdef __unix
#endif
{ 0, MDF_NONE, 0 }
};
200
Adding Functionality to a Custom Module
To add functionality to a custom module you must understand the C++ API interface
and the Module Class Module.
To create a new module type, declare new C++ classes which inherit from a set of base
classes, and then implement the module type-specific functionality. The virtual base
class for module masters is RadiusModule. See modbase.h for detailed information
about the RadiusModule.
The support header files (module.h) are self-documenting. See the following files for
details:
In source/apps/radius:
moddef.h
In source/apps/radius/include/general:
In source/apps/radius/include/modules:
In source/apps/radius/include/radius:
201
dict.h - Dictionary processing functions
packet.h - RADIUS packet processing functions
password.h - Processing the RADIUS password attribute
structdatatype.h - Support for the struct data type in the dictionary
types.h - Enumerated values for attributes and their types
Before writing a custom module, you must understand the Module Class Model and the
support APIs.
This section describes the C++ API interface to module masters and module workers. A
virtual base class inheritance model is used. This means that creating a new module
type involves declaring new C++ classes which inherit from a set of base classes and
then implement the module type's specific functionality.
Each module indicates what should happen next by setting a "return value":
MRT_ERROR indicates that an error has occurred and the request should be
discarded.
o Checks to see that the request matches its check sections. If not, it returns
MRT_CONTINUE.
o Optionally makes changes to the incoming request by adding, deleting, or
modifying attributes. (See mod_transform for an example).
o Optionally makes changes to the outgoing response by setting the response
type, and adding, deleting, or modifying attributes.
202
o Optionally adding attributes from any send sections to the outgoing
response.
o Returns MRT_CONTINUE, MRT_COMPLETE or MRT_ERROR as
appropriate.
o If the end of the module list is reached and no module has returned
MRT_COMPLETE, the request is discarded.
The virtual base class for module masters is RadiusModule. The salient parts are
shown here from modbase.h. See modbase.h for detailed information.
class RadiusModule {
protected:
ModuleDefFlags flags;
string name;
string type;
int ref_count;
pthread_mutex_t mutex;
/*
** use()
**
*/
void use();
203
public:
/*
** RadiusModule()
**
*/
/*
** ~RadiusModule()
**
** Automatically called when the reference count reaches 0 (see use(), unuse())
*/
virtual ~RadiusModule();
/*
** unuse()
**
*/
void unuse();
204
/*
** newConfig()
**
**
** It also searches for $CONFIG->(name) and stores the result (if found)
** in shared_config.
*/
/*
** createWorker()
**
**
*/
205
/*
** lock()
** unlock()
**
*/
void lock();
void unlock();
};
These methods may be defined in the derived class. See the source
for mod_example as an example.
Constructor
You must provide a constructor in order to initialize the module master. The base class
constructor must be called.
Example:
Destructor
206
Example:
RadiusModuleExample::~RadiusModuleExample()
newConfig()
This method is called both at startup and when a reconfiguration event occurs. It is the
responsibility of the module master to extract the appropriate configuration from the
configuration tree. The default implementation keeps a reference to both the module
type configuration (shared_config) and the per-module configuration (worker_config).
Thus, most modules do not require a special implementation of this method.
createWorker()
This method creates a new module worker and increments the reference count.
Typically, this method simply creates a new module worker of the appropriate type. The
module worker is responsible for taking a copy of both the per-module configuration
(worker_config) and the module type configuration (shared_config), when
appropriate. It must also call use() to ensure that the reference count is incremented.
Example:
RadiusModuleWorker *
RadiusModuleExample::createWorker(int thread_id)
assert(worker_config != 0);
use();
shared_config, thread_id));
207
The module worker is where most of the work of the module is accomplished.The virtual
base class for module workers is RadiusModuleWorker. The salient parts are shown
here from modbase.h. See modbase.h for detailed information.
Constructor (required)
Example:
RadiusModuleExampleWorker::RadiusModuleExampleWorker(RadiusModule
*parent_,
int thread_id)
action = config.getValue(MOD_EXAMPLE_ACTION);
if (action == "") {
action = MOD_EXAMPLE_ACTION_IGNORE;
208
}
Destructor
Example:
RadiusModuleExampleWorker::~RadiusModuleExampleWorker()
delete checksend;
acceptRequest()
RadiusModuleWorker::ModuleReturnType
RadiusModuleExampleWorker::acceptRequest(RadiusModuleRequest *request)
if (checksend->check(request->input, getSystemDict()) == 0) {
return(MRT_CONTINUE);
209
if (action == MOD_EXAMPLE_ACTION_DISCARD) {
return(MRT_DISCARD);
if (action == MOD_EXAMPLE_ACTION_IGNORE) {
return(MRT_CONTINUE);
if (action == MOD_EXAMPLE_ACTION_NAK) {
switch (request->input->getType()) {
case PW_ACCESS_REQUEST:
request->output->setType(PW_ACCESS_REJECT);
break;
case PW_ACCOUNTING_REQUEST:
request->output->setType(PW_ACCOUNTING_RESPONSE);
break;
default:
return(MRT_DISCARD);
switch (request->input->getType()) {
210
case PW_ACCESS_REQUEST:
request->output->setType(PW_ACCESS_ACCEPT);
break;
case PW_ACCOUNTING_REQUEST:
request->output->setType(PW_ACCOUNTING_RESPONSE);
break;
default:
return(MRT_DISCARD);
else {
return(MRT_ERROR);
checksend->addSendAttr(request->output, getSystemDict(),
RadiusCheckSend::ADD_APPEND);
return(MRT_COMPLETE);
The sections above describe the APIs to module masters and module workers;
however, they don't explain how module masters are instantiated.This is managed by a
special module definition table.The excerpt below is from moddef.cpp:
211
....
ModuleDefFlags theFlags);
#ifdef __unix
#endif
{ 0, MDF_NONE, 0 }
};
Note:
Configure the mod_pin module after configuring all the other modules
because mod_pin prepares the RADIUS response and sends it to the client.
This table associates Module Type names with functions that know how to create a
module master of the associated class.You can modify this table to add custom
modules.
212
RadiusModule *
This function creates an object of the appropriate type and returns it.
This sample prints the name of the incoming RADIUS attributes and their values and
appends the domain name to the user name attribute.
/* This code prints the names of the incoming RADIUS atttributes and their valus */
theAttr->getBuffer(),
theAttr->getBufferLength());
213
}
*/
if (add_domain != "") {
value += add_domain;
Example:
type=<mod_new>
status=enables
214
<check>
<send>
<etc.)
When you finish modifying the RADIUS configuration file you must restart the RADIUS
daemon.
1. Check to ensure that the RADIUS config file and dictionary file are in the
directory BRM_home/apps/radius.
3. If you want pin_radiusd to start automatically when you restart the machine.
215
UNIT IV
Arrays:
Arrays a kind of data structure that can store a fixed-size sequential collection of
elements of the same type. An array is used to store a collection of data, but it is often
more useful to think of an array as a collection of variables of the same type.
All arrays consist of contiguous memory locations. The lowest address corresponds to
the first element and the highest address to the last element.
Declaring Arrays
To declare an array in C, a programmer specifies the type of the elements and the
number of elements required by an array as follows −
double balance[10];
Here balance is a variable array which is sufficient to hold up to 10 double numbers.
Initializing Arrays
You can initialize an array in C either one by one or using a single statement as follows
−
If you omit the size of the array, an array just big enough to hold the initialization is
created. Therefore, if you write −
216
balance[4] = 50.0;
The above statement assigns the 5th element in the array with a value of 50.0. All arrays
have 0 as the index of their first element which is also called the base index and the last
index of an array will be total size of the array minus 1. Shown below is the pictorial
representation of the array we discussed above −
An element is accessed by indexing the array name. This is done by placing the index
of the element within square brackets after the name of the array. For example −
#include <stdio.h>
int main () {
return 0;
}
When the above code is compiled and executed, it produces the following result −
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
217
Element[8] = 108
Element[9] = 109
Syntax:
Examples:
218
data_type[][] array_name = new data_type[x][y];
For example: int[][] arr = new int[10][20];
Initialization – Syntax:
array_name[row_index][column_index] = value;
For example: arr[0][0] = 1;
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
Output:
arr[0][0] = 1
Syntax:
data_type[][] array_name = {
{valueR1C1, valueR1C2, ....},
{valueR2C1, valueR2C2, ....}
};
Example:
filter_none
edit
219
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][] arr = { { 1, 2 }, { 3, 4 } };
Output:
arr[0][0] = 1
arr[0][1] = 2
arr[1][0] = 3
arr[1][1] = 4
Elements in two-dimensional arrays are commonly referred by x[i][j] where ‗i‘ is the row
number and ‗j‘ is the column number.
Syntax:
x[row_index][column_index]
For example:
Note: In arrays if size of array is N. Its index will be from 0 to N-1. Therefore, for
row_index 2, actual row number is 2+1 = 3.
220
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][] arr = { { 1, 2 }, { 3, 4 } };
Output:
arr[0][0] = 1
Representation of 2D array in Tabular Format: A two – dimensional array can be seen
as a table with ‗x‘ rows and ‗y‘ columns where the row number ranges from 0 to (x-1) and
column number ranges from 0 to (y-1). A two – dimensional array ‗x‘ with 3 rows and 3
columns is shown below:
To output all the elements of a Two-Dimensional array, use nested for loops. For this two
for loops are required, One to traverse the rows and another to traverse columns.
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][] arr = { { 1, 2 }, { 3, 4 } };
221
}
System.out.println();
}
}
}
Output:
12
34
Initialization – Syntax:
array_name[array_index][row_index][column_index] = value;
For example: arr[0][0][0] = 1;
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
222
Syntax:
data_type[][][] array_name = {
{
{valueA1R1C1, valueA1R1C2, ....},
{valueA1R2C1, valueA1R2C2, ....}
},
{
{valueA2R1C1, valueA2R1C2, ....},
{valueA2R2C1, valueA2R2C2, ....}
}
};
For example: int[][][] arr = { {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}} };
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][][] arr = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
223
arr[1][0][1] = 6
arr[1][1][0] = 7
arr[1][1][1] = 8
Elements in three-dimensional arrays are commonly referred by x[i][j][k] where ‗i‘ is the
array number, ‗j‘ is the row number and ‗k‘ is the column number.
Syntax:
x[array_index][row_index][column_index]
For example:
int[][][] arr = new int[10][20][30];
arr[0][0][0] = 1;
The above example represents the element present in the first row and first column of the
first array in the declared 3D array.
Note: In arrays if size of array is N. Its index will be from 0 to N-1. Therefore, for
row_index 2, actual row number is 2+1 = 3.
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][][] arr = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
arr[0][0][0] = 1
Representation of 3D array in Tabular Format: A three – dimensional array can be
seen as a tables of arrays with ‗x‘ rows and ‗y‘ columns where the row number ranges
from 0 to (x-1) and column number ranges from 0 to (y-1). A three – dimensional array
with 3 array containing 3 rows and 3 columns is shown below:
224
Print 3D array in tabular format:
To output all the elements of a Three-Dimensional array, use nested for loops. For this
three for loops are required, One to traverse the arrays, second to traverse the rows and
another to traverse columns.
Example:
filter_none
edit
play_arrow
brightness_4
class GFG {
public static void main(String[] args)
{
int[][][] arr = { { { 1, 2 }, { 3, 4 } },
{ { 5, 6 }, { 7, 8 } } };
System.out.println();
}
System.out.println();
}
}
}
Output:
12
34
56
78
Inserting a Multi-dimensional Array during Runtime:
This topic is forced n taking user-defined input into a multidimensional array during
runtime. It is focused on the user first giving all the input to the program during runtime
and after all entered input, the program will give output with respect to each input
accordingly. It is useful when the user wishes to make input for multiple Test-Cases with
225
multiple different values first and after all those things done, program will start providing
output.
As an example, let‘s find the total number of even and odd numbers in an input array.
Here, we will use the concept of a 2-dimensional array. Here are a few points that explain
the use of the various elements in the upcoming code:
Row integer number is considered as the number of Test-Cases and Column
values are considered as values in each Test-Case.
One for() loop is used for updating Test-Case number and another for() loop is
used for taking respective array values.
As all input entry is done, again two for() loops are used in the same manner to
execute the program according to the condition specified.
The second line shows the total number of first array values.
Implementation:
filter_none
edit
play_arrow
brightness_4
import java.util.Scanner;
// totalTestCases = total
// number of TestCases
// eachTestCaseValues =
// values in each TestCase as
// an Array values
int totalTestCases, eachTestCaseValues;
226
totalTestCases = scanner.nextInt();
227
"Total Even numbers: " + nEvenNumbers
+ ", Total Odd numbers: " + nOddNumbers);
}
}
}
// This code is contributed by Udayan Kamble.
Input:
2
2
12
3
123
Output:
TestCase 0 with 2 values:
12
Total Even numbers: 1, Total Odd numbers: 1
TestCase 1 with 3 values:
123
Total Even numbers: 1, Total Odd numbers: 2
Input:
3
8
1 2 3 4 5 11 55 66
5
100 101 55 35 108
6
3 80 11 2 1 5
Output:
TestCase 0 with 8 values:
1 2 3 4 5 11 55 66
Total Even numbers: 3, Total Odd numbers: 5
TestCase 1 with 5 values:
100 101 55 35 108
Total Even numbers: 2, Total Odd numbers: 3
TestCase 2 with 6 values:
3 80 11 2 1 5
Total Even numbers: 2, Total Odd numbers: 4
228
arrays of unknown or varying size
Does someone know how to solve this issue ? Using C99 (no C++) and it should be
quite standard (working on gcc and icc at least).
EDIT: I may have forget something that matters. I am required to propose an array that
is usable through the "static array interface", I mean by that the multiple square bracket
(one per dimension).
You cannot declare a global multi dimensional VLA, because even if you use pointers,
all the dimensions except for the first one must be known at declaration time.
My best attempt would be to use a global void *. In C void * is a special pointer type that
can be used to store a pointer to any type, and is often used for opaque pointers.
Structures:
Lets say we need to store the data of students like student name, age, address, id etc.
One way of doing this would be creating a different variable for each attribute, however
when you need to store the data of multiple students then in that case, you would need
to create these several variables again for each student. This is such a big headache to
store data in this way.
We can solve this problem easily by using structure. We can create a structure that has
members for name, id, address and age and then we can create the variables of this
structure for each student. This may sound confusing, do not worry we will understand
this with the help of example.
We use struct keyword to create a structure in C. The struct keyword is a short form
of structured data type.
struct struct_name {
DataType member1_name;
DataType member2_name;
DataType member3_name;
…
};
230
Here struct_name can be anything of your choice. Members data type can be same or
different. Once we have declared the structure we can use the struct name as a data
type like int, float etc.
struct struct_name {
DataType member1_name;
DataType member2_name;
DataType member3_name;
…
} var_name;
var_name.member1_name;
var_name.member2_name;
…
var_name.memeber_name = value;
3) Designated initializers – We will discuss this later at the end of this post.
Example of Structure in C
#include <stdio.h>
/* Created a structure here. The name of the structure is
* StudentData.
*/
231
struct StudentData{
char *stu_name;
int stu_id;
int stu_age;
};
int main()
{
/* student is the variable of structure StudentData*/
struct StudentData student;
Output:
You can use a structure inside another structure, which is fairly possible. As I explained
above that once you declared a structure, the struct struct_name acts as a new data
type so you can include it in another struct just like the data type of other data members.
Sounds confusing? Don‘t worry. The following example will clear your doubt.
Structure 1: stu_address
struct stu_address
{
232
int street;
char *state;
char *city;
char *country;
}
Structure 2: stu_data
struct stu_data
{
int stu_id;
int stu_age;
char *stu_name;
struct stu_address stuAddress;
}
As you can see here that I have nested a structure inside another structure.
Lets take the example of the two structure that we seen above to understand the logic
printf("%s", mydata.stuAddress.city);
Use of typedef in Structure
typedef makes the code short and improves readability. In the above discussion we
have seen that while using structs every time we have to use the lengthy syntax, which
makes the code confusing, lengthy, complex and less readable. The simple solution to
this issue is use of typedef. It is like an alias of struct.
struct home_address {
233
int local_street;
char *town;
char *my_city;
char *my_country;
};
...
struct home_address var;
var.town = "Agra";
Instead of using the struct home_address every time you need to declare struct
variable, you can simply use addr, the typedef that we have defined.
We have already learned two ways to set the values of a struct member, there is
another way to do the same using designated initializers. This is useful when we are
doing assignment of only few members of the structure. In the following example the
structure variable s2 has only one member assignment.
#include <stdio.h>
struct numbers
{
int num1, num2;
};
int main()
{
// Assignment using using designated initialization
struct numbers s1 = {.num2 = 22, .num1 = 11};
struct numbers s2 = {.num2 = 30};
234
printf ("num1: %d, num2: %d\n", s1.num1, s1.num2);
printf ("num1: %d", s2.num2);
return 0;
}
Output:
declaring structures
1) Struct definition: introduces the new type struct name and defines its meaning
2) If used on a line of its own, as in struct name ;, declares but doesn't define the
struct name (see forward declaration below). In other contexts, names the previously-
declared struct, and attr-spec-seq is not allowed.
Explanation
Within a struct object, addresses of its elements (and the addresses of the bit field
allocation units) increase in order in which the members were defined. A pointer to a
struct can be cast to a pointer to its first member (or, if the member is a bit field, to its
allocation unit). Likewise, a pointer to the first member of a struct can be cast to a
pointer to the enclosing struct. There may be unnamed padding between any two
members of a struct or after the last member, but not before the first member. The size
of a struct is at least as large as the sum of the sizes of its members.
If a struct defines at least one named member, it is allowed to additionally (since C99)
declare its last member with incomplete array type. When an element of the
235
flexible array member is accessed (in an expression that uses
operator . or -> with the flexible array member's name as the right-hand-
side operand), then the struct behaves as if the array member had the
longest size fitting in the memory allocated for this object. If no additional
storage was allocated, it behaves as if an array with 1 element, except that
the behavior is undefined if that element is accessed or a pointer one past
that element is produced. Initialization, sizeof, and the assignment operator
ignore the flexible array member. Structures with flexible array members (or
unions who have a recursive-possibly structure member with flexible array
member) cannot appear as array elements or as members of other
structures.
// if sizeof (double) == 8
*dp = 42; // OK
// as double.
236
bytes are
struct v {
struct { long k, l; } w;
}; (since C11)
int m;
} v1;
v1.i = 2; // valid
v1.w.k = 5; // valid
237
nested structs or unions).
Forward declaration
hides any previously declared meaning for the name name in the tag name space and
declares name as a new struct name in current scope, which will be defined later. Until
the definition appears, this struct name has incomplete type.
struct y;
Note that a new struct name may also be introduced just by using a struct tag within
another declaration, but if a previously declared struct with the same name exists in the
tag name space, the tag would refer to that name
void g(void)
238
Keywords
struct
Notes
See struct initialization for the rules regarding the initializers for structs.
Because members of incomplete type are not allowed, and a struct type is not complete
until the end of the definition, a struct cannot have a member of its own type. A pointer
to its own type is allowed, and is commonly used to implement nodes in linked lists or
trees.
Because a struct declaration does not establish scope, nested types, enumerations and
enumerators introduced by declarations within struct-declaration-list are visible in the
surrounding scope where the struct is defined.
Example
#include <stddef.h>
#include <stdio.h>
int main(void)
struct car { char *make; char *model; int year; }; // declares the struct type
*pship = &ship;
239
printf("spaceship: %s %s %s\n", ship.year, ship.make, ship.model);
// A pointer to a struct can be cast to a pointer to its first member and vice versa
Possible output:
offset of char a = 0
offset of double b = 8
offset of char c = 16
sizeof(struct A) = 24
offset of char a = 0
240
offset of char b = 1
offset of double c = 8
sizeof(struct B) = 16
assigning of structures
2 int code;
3 char name[NAME_SIZE];
4 char *alias;
5}map_t;
If we want to assign map_t type variable struct2 to sturct1, we usually have below 3
ways:
2 struct1.code = struct2.code;
4 struct1.alias = struct2.alias;
10struct1 = struct2;
Consider above ways, most of programmer won‘t use way #1, since it‘s so stupid ways
compare to other twos, only if we are defining an structure assignment function.
So, what‘s the difference between way #2 and way #3? And what‘s the pitfall of the
241
structure assignment once there is array or pointer member existed? Coming sections
maybe helpful for your understanding.
The struct1=struct2; notation is not only more concise, but also shorter and leaves more
optimization opportunities to the compiler. The semantic meaning of = is an assignment,
while memcpy just copies memory. That‘s a huge difference in readability as well,
although memcpy does the same in this case.
Copying by straight assignment is probably best, since it‘s shorter, easier to read, and
has a higher level of abstraction. Instead of saying (to the human reader of the code)
―copy these bits from here to there‖, and requiring the reader to think about the size
argument to the copy, you‘re just doing a straight assignment (―copy this value from
here to here‖). There can be no hesitation about whether or not the size is correct.
Consider that, above source code also has pitfall about the pointer alias, it will lead
dangling pointer problem (It will be introduced below section). If we use straight
structure assignment ‗=‘ in C++, we can consider to overload the operator= function,
that can dissolve the problem, and the structure assignment usage does not need to do
any changes, but structure memcpy does not have such opportunity.
Beware though, that copying structs that contain pointers to heap-allocated memory can
be a bit dangerous, since by doing so you‘re aliasing the pointer, and typically making it
ambiguous who owns the pointer after the copying operation.
If the structures are of compatible types, yes, you can, with something like:
} The only thing you need to be aware of is that this is a shallow copy. In other words, if
you have a char * pointing to a specific string, both structures will point to the same
string.
And changing the contents of one of those string fields (the data that the char points to,
not the char itself) will change the other as well. For these situations a ―deep copy‖ is
really the only choice, and that needs to go in a function. If you want a easy copy
without having to manually do each field but with the added bonus of non-shallow string
copies, use strdup:
242
2dest_struct->strptr = strdup(source_struct->strptr);
This will copy the entire contents of the structure, then deep-copy the string, effectively
giving a separate string to each structure. And, if your C implementation doesn‘t have a
strdup (it‘s not part of the ISO standard), you have to allocate new memory
for dest_struct pointer member, and copy the data to memory address.
Example of trap:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #define NAME_SIZE 16
7 int code;
8 char name[NAME_SIZE];
9 char *alias;
10} map_t;
11
12int main()
13{
14 map_t a, b, c;
15
17 a.code = 1024;
20 a.alias = alias;
243
21
24
26 c = a;
27 return 0;
28}
Below diagram illustrates above source memory layout, if there is a pointer field
member, either the straight assignment or memcpy, that will be alias of pointer to point
same address. For example, b.alias and c.alias both points to address of a.alias. Once
one of them free the pointed address, it will cause another pointer as dangling
pointer. It‘s dangerous!!
244
Conclusion
If structure has pointer or array member, please consider the pointer alias problem, it
will lead dangling pointer once incorrect use. Better way is implement structure
assignment function in C, and overload the operator= function in C++.
to Objects:
Pointers variables are also known as address data types because they are used to store
the address of another variable. The address is the memory location that is assigned to
the variable. It doesn‘t store any value.
Hence, there are only a few operations that are allowed to perform on Pointers in C
language. The operations are slightly different from the ones that we generally use for
mathematical calculations. The operations are:
1. Increment/Decrement of a Pointer
Increment/Decrement of a Pointer
For Example:
If an integer pointer that stores address 1000 is incremented, then it will increment by
2(size of an int) and the new address it will points to 1002. While if a float type pointer is
incremented then it will increment by 4(size of a float) and the new address will be 1004.
Decrement: It is a condition that also comes under subtraction. When a pointer is
decremented, it actually decrements by the number equal to the size of the data type for
which it is a pointer.
For Example:
If an integer pointer that stores address 1000 is decremented, then it will decrement by
245
2(size of an int) and the new address it will points to 998. While if a float type pointer is
decremented then it will decrement by 4(size of a float) and the new address will be 996.
Below is the program to illustrate pointer increment/decrement:
filter_none
edit
play_arrow
brightness_4
// C program to illustrate
// pointer increment/decrement
#include <stdio.h>
// Driver Code
int main()
{
// Integer variable
int N = 4;
// Pointer to an integer
int *ptr1, *ptr2;
// Pointer stores
// the address of N
ptr1 = &N;
ptr2 = &N;
246
printf("Pointer ptr1 after"
" Decrement: ");
printf("%p \n\n", ptr1);
return 0;
}
Output:
Addition
When a pointer is added with a value, the value is first multiplied by the size of data type
and then added to the pointer.
filter_none
edit
play_arrow
brightness_4
// C program to illustrate pointer Addition
#include <stdio.h>
// Driver Code
int main()
{
// Integer variable
int N = 4;
// Pointer to an integer
int *ptr1, *ptr2;
247
// Addition of 3 to ptr2
ptr2 = ptr2 + 3;
printf("Pointer ptr2 after Addition: ");
printf("%p \n", ptr2);
return 0;
}
Output:
Subtraction
When a pointer is subtracted with a value, the value is first multiplied by the size of the
data type and then subtracted from the pointer.
Below is the program to illustrate pointer Subtraction:
filter_none
edit
play_arrow
brightness_4
// C program to illustrate pointer Subtraction
#include <stdio.h>
// Driver Code
int main()
{
// Integer variable
int N = 4;
// Pointer to an integer
int *ptr1, *ptr2;
// Subtraction of 3 to ptr2
ptr2 = ptr2 - 3;
printf("Pointer ptr2 after Subtraction: ");
248
printf("%p \n", ptr2);
return 0;
}
Output:
The subtraction of two pointers is possible only when they have the same data type. The
result is generated by calculating the difference between the addresses of the two
pointers and calculating how many bits of data it is according to the pointer data type. The
subtraction of two pointers gives the increments between the two pointers.
For Example:
// Driver Code
int main()
{
int x;
// Integer variable
int N = 4;
// Pointer to an integer
int *ptr1, *ptr2;
249
ptr1 = &N;
ptr2 = &N;
// Incrementing ptr2 by 3
ptr2 = ptr2 + 3;
return 0;
}
Output:
Pointers contain addresses. Adding two addresses makes no sense because there is no
idea what it would point to. Subtracting two addresses lets you compute the offset
between the two addresses. An array name acts like a pointer constant. The value of this
pointer constant is the address of the first element. For Example: if an array named arr
then arr and &arr[0] can be used to reference array as a pointer.
Below is the program to illustrate the Pointer Arithmetic on arrays:
Program 1:
filter_none
edit
play_arrow
brightness_4
// C program to illustrate the array
// traversal using pointers
#include <stdio.h>
// Driver Code
int main()
{
int N = 5;
250
// An array
int arr[] = { 1, 2, 3, 4, 5 };
Output:
12345
Program 2:
filter_none
edit
play_arrow
brightness_4
// C program to illustrate the array
// traversal using pointers in 2D array
#include <stdio.h>
int i, j;
251
// Travere columns of 2D matrix
for (j = 0; j < M; j++) {
// Driver Code
int main()
{
int N = 3, M = 2;
// A 2D array
int arr[][2] = { { 1, 2 },
{ 3, 4 },
{ 5, 6 } };
// Function Call
traverseArr((int*)arr, N, M);
return 0;
}
Output:
12
34
56
Pointers are the special type of data types which stores memory address (reference) of
another variable. Here we will learn how to declare and initialize a pointer variable with
the address of another variable?
Pointer Declarations
Pointer declaration is similar to other type of variable except asterisk (*) character
before pointer variable name.
252
Here is the syntax to declare a pointer
data_type *poiter_name;
int *ptr;
ptr is the name of pointer variable (name of the memory blocks in which address
of another variable is going to be stored).
The character asterisk (*) tells to the compiler that the identifier ptr should be
declare as pointer.
The data type int tells to the compiler that pointer ptr will store memory address
of integer type variable.
Finally, ptr will be declared as integer pointer which will store address of integer type
variable.
Pointer ptr is declared, but it not pointing to anything; now pointer should be initialized
by the address of another integer variable.
int x;
int *ptr;
ptr=&x;
Here, x is an integer variable and pointer ptr is initiating with the address of x.
We can get the value of ptr which is the address of x (an integer variable)
*ptr will print the value which is stored at the containing memory address in
the ptr (value of variable x).
253
#include <stdio.h>
int main()
{
int x=20; //int variable
int *ptr; //int pointer declaration
return 0;
}
Memory address of x: 0x7ffe64f5c814
Value x: 20
In this tutorial, you will learn how to pass a pointer to a function as an argument. To
understand this concept you must have a basic idea of Pointers and functions in C
programming.
Just like any other argument, pointers can also be passed to a function as an argument.
Lets take an example to understand how this is done.
Try this same program without pointer, you would find that the bonus amount will not
reflect in the salary, this is because the change made by the function would be done to
the local variables of the function. When we use pointers, the value is changed at the
address of variable
#include <stdio.h>
void salaryhike(int *var, int b)
{
*var = *var+b;
}
254
int main()
{
int salary=0, bonus=0;
printf("Enter the employee current salary:");
scanf("%d", &salary);
printf("Enter bonus:");
scanf("%d", &bonus);
salaryhike(&salary, bonus);
printf("Final salary: %d", salary);
return 0;
}
Output:
This is one of the most popular example that shows how to swap numbers using call by
reference.
Try this program without pointers, you would see that the numbers are not swapped.
The reason is same that we have seen above in the first example.
#include <stdio.h>
void swapnum(int *num1, int *num2)
{
int tempnum;
tempnum = *num1;
*num1 = *num2;
*num2 = tempnum;
}
int main( )
{
int v1 = 11, v2 = 77 ;
printf("Before swapping:");
printf("\nValue of v1 is: %d", v1);
printf("\nValue of v2 is: %d", v2);
255
swapnum( &v1, &v2 );
printf("\nAfter swapping:");
printf("\nValue of v1 is: %d", v1);
printf("\nValue of v2 is: %d", v2);
}
Output:
Before swapping:
Value of v1 is: 11
Value of v2 is: 77
After swapping:
Value of v1 is: 77
Value of v2 is: 11
1. malloc()
2. calloc()
3. realloc()
4. free()
Before learning above functions, let's understand the difference between static memory
allocation and dynamic memory allocation.
Now let's have a quick look at the methods used for dynamic memory allocation.
256
malloc() allocates single block of requested memory.
malloc() function in C
1. ptr=(cast-type*)malloc(byte-size)
1. #include<stdio.h>
2. #include<stdlib.h>
3. int main(){
4. int n,i,*ptr,sum=0;
5. printf("Enter number of elements: ");
6. scanf("%d",&n);
7. ptr=(int*)malloc(n*sizeof(int)); //memory allocated using malloc
8. if(ptr==NULL)
9. {
10. printf("Sorry! unable to allocate memory");
11. exit(0);
12. }
13. printf("Enter elements of array: ");
14. for(i=0;i<n;++i)
15. {
16. scanf("%d",ptr+i);
17. sum+=*(ptr+i);
18. }
19. printf("Sum=%d",sum);
20. free(ptr);
21. return 0;
22. }
257
Output
calloc() function in C
1. ptr=(cast-type*)calloc(number, byte-size)
1. #include<stdio.h>
2. #include<stdlib.h>
3. int main(){
4. int n,i,*ptr,sum=0;
5. printf("Enter number of elements: ");
6. scanf("%d",&n);
7. ptr=(int*)calloc(n,sizeof(int)); //memory allocated using calloc
8. if(ptr==NULL)
9. {
10. printf("Sorry! unable to allocate memory");
11. exit(0);
12. }
13. printf("Enter elements of array: ");
14. for(i=0;i<n;++i)
15. {
16. scanf("%d",ptr+i);
17. sum+=*(ptr+i);
18. }
19. printf("Sum=%d",sum);
20. free(ptr);
21. return 0;
22. }
258
Output
realloc() function in C
If memory is not sufficient for malloc() or calloc(), you can reallocate the memory by
realloc() function. In short, it changes the memory size.
1. ptr=realloc(ptr, new-size)
free() function in C
1. free(ptr)
Stack as we know is a Last In First Out(LIFO) data structure. It has the following
operations :
259
Implementation of Stack using Linked List
Stacks can be easily implemented using a linked list. Stack is a data structure to which
a data can be added using the push() method and data can be removed from it using
the pop() method. With Linked list, the push operation can be replaced by
the addAtFront() method of linked list and pop operation can be replaced by a function
which deletes the front node of the linked list.
In this way our Linked list will virtually become a Stack with push() and pop() methods.
First we create a class node. This is our Linked list node class which will have data in it
and a node pointer to store the address of the next node element.
class node
int data;
node *next;
};
260
Then we define our stack class,
class Stack
public:
Stack()
front = NULL;
void push(int);
void pop();
int top();
};
node *temp;
261
// setting data to it
temp->data = d;
if(front == NULL)
temp->next = NULL;
else
temp->next = front;
front = temp;
Now whenever we will call the push() function a new node will get added to our list in
the front, which is exactly how a stack behaves.
// if empty
if(front == NULL)
262
else
front = front->next;
delete(temp);
return front->data;
Conclusion
When we say "implementing Stack using Linked List", we mean how we can make a
Linked List behave like a Stack, after all they are all logical entities. So for any data
structure to act as a Stack, it should have push() method to add data on top
and pop() method to remove data from top. Which is exactly what we did and hence
accomplished to make a Linked List behave as a Stack.
263
UNIT V
Sequential search
When data items are stored in a collection such as a list, we say that they have a linear
or sequential relationship. Each data item is stored in a position relative to the others. In
Python lists, these relative positions are the index values of the individual items. Since
these index values are ordered, it is possible for us to visit them in sequence. This
process gives rise to our first searching technique, the sequential search.
The diagram below shows how this search works. Starting at the first item in the list, we
simply move from item to item, following the underlying sequential ordering until we
either find what we are looking for or run out of items. If we run out of items, we have
discovered that the item we were searching for was not present.
The Python implementation for this algorithm is shown below. The function needs the
list and the item we are looking for and returns a boolean value as to whether it is
present. Remember in practice we would use the Python in operator for this purpose, so
you can think of the below algorithm as what we would do if in were not provided for us.
return False
264
sequential_search(testlist, 13) # => True
If the item is not in the list, the only way to know it is to compare it against every item
present. If there are nn items, then the sequential search requires nn comparisons to
discover that the item is not there. In the case where the item is in the list, the analysis
is not so straightforward. There are actually three different scenarios that can occur. In
the best case we will find the item in the first place we look, at the beginning of the list.
We will need only one comparison. In the worst case, we will not discover the item until
the very last comparison, the nth comparison.
What about the average case? On average, we will find the item about halfway into the
list; that is, we will compare against \frac{n}{2}2n items. Recall, however, that as n gets
large, the coefficients, no matter what they are, become insignificant in our
approximation, so the complexity of the sequential search, is O(n)O(n):
We assumed earlier that the items in our collection had been randomly placed so that
there is no relative order between the items. What would happen to the sequential
search if the items were ordered in some way? Would we be able to gain any efficiency
in our search technique?
Assume that the list of items was constructed so that the items were in ascending order,
from low to high. If the item we are looking for is present in the list, the chance of it
being in any one of the n positions is still the same as before. We will still have the
same number of comparisons to find the item. However, if the item is not present there
is a slight advantage. The diagram below shows this process as the algorithm looks for
the item 50. Notice that items are still compared in sequence until 54. At this point,
265
however, we know something extra. Not only is 54 not the item we are looking for, but
no other elements beyond 54 can work either since the list is sorted.
In this case, the algorithm does not have to continue looking through all of the items to
report that the item was not found. It can stop immediately. The code below shows this
variation of the sequential search function.
position = position + 1
return False
The table below summarizes these results. Note that in the best case we might discover
that the item is not in the list by looking at only one item. On average, we will know after
looking through only \frac {n}{2}2n items. However, this technique is still O(n)O(n). In
summary, a sequential search is improved by ordering the list only in the case where we
do not find the item.
266
Case Best Case Worst Case Average Case
Sorting arrays
Java
filter_none
edit
play_arrow
brightness_4
// A sample Java program to sort an array of integers
// using Arrays.sort(). It by default sorts in
// ascending order
import java.util.Arrays;
Arrays.sort(arr);
267
System.out.printf("Modified arr[] : %s",
Arrays.toString(arr));
}
}
Output:
Modified arr[] : [6, 7, 9, 13, 21, 45, 101, 102]
Java
filter_none
edit
play_arrow
brightness_4
// A sample Java program to sort a subarray
// using Arrays.sort().
import java.util.Arrays;
268
Java
filter_none
edit
play_arrow
brightness_4
// A sample Java program to sort a subarray
// in descending order using Arrays.sort().
import java.util.Arrays;
import java.util.Collections;
Java
filter_none
edit
play_arrow
brightness_4
// A sample Java program to sort an array of strings
// in ascending and descending orders using Arrays.sort().
import java.util.Arrays;
import java.util.Collections;
Modified arr[] :
[quiz.geeksforgeeks.org, practice.geeksforgeeks.org, code.geeksforgeeks.org]
Java
filter_none
edit
play_arrow
brightness_4
// Java program to demonstrate working of Comparator
// interface
import java.util.*;
import java.lang.*;
import java.io.*;
270
// A class to represent a student.
class Student
{
int rollno;
String name, address;
// Constructor
public Student(int rollno, String name,
String address)
{
this.rollno = rollno;
this.name = name;
this.address = address;
}
// Driver class
class Main
{
public static void main (String[] args)
{
Student [] arr = {new Student(111, "bbbb", "london"),
new Student(131, "aaaa", "nyc"),
new Student(121, "cccc", "jaipur")};
System.out.println("Unsorted");
for (int i=0; i<arr.length; i++)
System.out.println(arr[i]);
271
Arrays.sort(arr, new Sortbyroll());
System.out.println("\nSorted by rollno");
for (int i=0; i<arr.length; i++)
System.out.println(arr[i]);
}
}
Output:
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc
Strings
272
Actually, you do not place the null character at the end of a string constant. The C
compiler automatically places the '\0' at the end of the string when it initializes the
array. Let us try to print the above mentioned string −
Live Demo
#include <stdio.h>
int main () {
1 strcpy(s1, s2);
Copies string s2 into string s1.
2 strcat(s1, s2);
273
Concatenates string s2 onto the end of string s1.
3 strlen(s1);
Returns the length of string s1.
4 strcmp(s1, s2);
Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater than 0 if s1>s2.
5 strchr(s1, ch);
Returns a pointer to the first occurrence of character ch in string s1.
6 strstr(s1, s2);
Returns a pointer to the first occurrence of string s2 in string s1.
#include <stdio.h>
#include <string.h>
int main () {
return 0;
274
}
When the above code is compiled and executed, it produces the following result −
strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10
Text files
A text file is a computer file that only contains text and has no special formatting such
as bold text, italic text, images, etc. With Microsoft Windows computers text files are
identified with the .txt file extension, as shown in the example picture.
An example of a text file and ASCII art is shown in the Kirk text file. You can click this
link to open the .txt file in your browser or right-click the file to save the text file to your
computer.
A text file can be opened in any text editor or word processor. For example, in Microsoft
Windows, you can use the Notepad program to open, view, and edit text files.
In a C program, all lines that start with # are processed by preprocessor which is a special
program invoked by the compiler. In a very basic term, preprocessor takes a C program
and produces another C program without any #.
The following are some interesting facts about preprocessors in C.
1) When we use include directive, the contents of included header file (after
preprocessing) are copied to the current file.
Angular brackets < and > instruct the preprocessor to look in the standard folder where all
header files are held. Double quotes ― and ― instruct the preprocessor to look into the
current folder (current directory).
2) When we use define for a constant, the preprocessor produces a C program where the
defined constant is searched and matching tokens are replaced with the given
expression. For example in the following program max is defined as 100.
C
275
filter_none
edit
play_arrow
brightness_4
#include<stdio.h>
#define max 100
int main()
{
printf("max is %d", max);
return 0;
}
Output:
max is 100
3) The macros can take function like arguments, the arguments are not checked for data
type. For example, the following macro INCREMENT(x) can be used for x of any data
type.
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define INCREMENT(x) ++x
int main()
{
char *ptr = "GeeksQuiz";
int x = 10;
276
printf("%s ", INCREMENT(ptr));
printf("%d", INCREMENT(x));
return 0;
}
Output:
eeksQuiz 11
4) The macro arguments are not evaluated before macro expansion. For example,
consider the following program
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define MULTIPLY(a, b) a*b
int main()
{
// The macro is expanded as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MULTIPLY(2+3, 3+5));
return 0;
}
// Output: 16
Output:
16
277
The previous problem can be solved using following program
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
//here, instead of writing a*a we write (a)*(b)
#define MULTIPLY(a, b) (a)*(b)
int main()
{
// The macro is expanded as (2 + 3) * (3 + 5), as 5*8
printf("%d", MULTIPLY(2+3, 3+5));
return 0;
}
// This code is contributed by Santanu
Output:
40
5) The tokens passed to macros can be concatenated using operator ## called Token-
Pasting operator.
C
278
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define merge(a, b) a##b
int main()
{
printf("%d ", merge(12, 34));
}
Output:
1234
6) A token passed to macro can be converted to a string literal by using # before it.
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define get(a) #a
int main()
{
// GeeksQuiz is changed to "GeeksQuiz"
printf("%s", get(GeeksQuiz));
}
Output:
279
GeeksQuiz
7) The macros can be written in multiple lines using ‗\‘. The last line doesn‘t need to have
‗\‘.
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define PRINT(i, limit) while (i < limit) \
{\
printf("GeeksQuiz "); \
i++; \
}
int main()
{
int i = 0;
PRINT(i, 3);
return 0;
}
Output:
280
8) The macros with arguments should be avoided as they cause problems sometimes.
And Inline functions should be preferred as there is type checking parameter evaluation in
inline functions. From C99 onward, inline functions are supported by C language also.
For example consider the following program. From first look the output seems to be 1, but
it produces 36 as output.
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
Output:
36
281
If we use inline functions, we get the expected output. Also, the program given in point 4
above can be corrected using inline functions.
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
Output:
9) Preprocessors also support if-else directives which are typically used for conditional
compilation.
C
filter_none
edit
play_arrow
brightness_4
int main()
282
{
#if VERBOSE >= 2
printf("Trace Message");
#endif
}
Output:
No Output
10) A header file may be included more than one time directly or indirectly, this leads to
problems of redeclaration of same variables/functions. To avoid this problem, directives
like defined, ifdef and ifndef are used.
11) There are some standard macros which can be used to print program file (__FILE__),
Date of compilation (__DATE__), Time of compilation (__TIME__) and Line Number in C
code (__LINE__)
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
int main()
{
printf("Current File :%s\n", __FILE__ );
printf("Current Date :%s\n", __DATE__ );
printf("Current Time :%s\n", __TIME__ );
printf("Line Number :%d\n", __LINE__ );
return 0;
}
Output:
283
Current File
:/usr/share/IDE_PROGRAMS/C/other/081c548d50135ed88cfa0296159b05ca/081c548d
50135ed88cfa0296159b05ca.c
Current Date :Sep 4 2019
Current Time :10:17:43
Line Number :8
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define LIMIT 100
int main()
{
printf("%d",LIMIT);
//removing defined macro LIMIT
#undef LIMIT
//Next line causes error as LIMIT is not defined
printf("%d",LIMIT);
return 0;
}
//This code is contributed by Santanu
Following program is executed correctly as we have declared LIMIT as an integer
variable after removing previously defined macro LIMIT
284
C
filter_none
edit
play_arrow
brightness_4
#include <stdio.h>
#define LIMIT 1000
int main()
{
printf("%d",LIMIT);
//removing defined macro LIMIT
#undef LIMIT
//Declare LIMIT as integer again
int LIMIT=1001;
printf("\n%d",LIMIT);
return 0;
}
Output:
1000
1001
285
float div(float, float);
#define div(x, y) x/y
int main()
{
//use of macro div
//Note: %0.2f for taking two decimal value after point
printf("%0.2f",div(10.0,5.0));
//removing defined macro div
#undef div
//function div is called as macro definition is removed
printf("\n%0.2f",div(10.0,5.0));
return 0;
}
Output:
2.00
0.50
The last preprocessor directive we're going to look at is #ifdef. If you have the sequence
#ifdef name
program text
#else
286
more program text
#endif
in your program, the code that gets compiled depends on whether a preprocessor
macro by that name is defined or not. If it is (that is, if there has been a #define line for a
macro called name), then ``program text'' is compiled and ``more program text'' is
ignored. If the macro is not defined, ``more program text'' is compiled and ``program
text'' is ignored. This looks a lot like an if statement, but it behaves completely
differently: an if statement controls which statements of your program are executed at
run time, but #ifdef controls which parts of your program actually get compiled.
Just as for the if statement, the #else in an #ifdef is optional. There is a companion
directive #ifndef, which compiles code if the macro is not defined (although the
``#else clause'' of an #ifndef directive will then be compiled if the macro is defined).
There is also an #if directive which compiles code depending on whether a compile-time
expression is true or false. (The expressions which are allowed in an #if directive are
somewhat restricted, however, so we won't talk much about #if here.)
You are trying to write a portable program, but the way you do something is
different depending on what compiler, operating system, or computer you're
using. You place different versions of your code, one for each situation, between
suitable #ifdef directives, and when you compile the progam in a particular
environment, you arrange to have the macro names defined which select the
variants you need in that environment. (For this reason, compilers usually have
ways of letting you define macros from the invocation command line or in a
configuration file, and many also predefine certain macro names related to the
operating system, processor, or compiler in use. That way, you don't have to
change the code to change the #define lines each time you compile it in a
different environment.)
For example, in ANSI C, the function to delete a file is remove. On older Unix
systems, however, the function was called unlink. So if filename is a variable
containing the name of a file you want to delete, and if you want to be able to
compile the program under these older Unix systems, you might write
#ifdef unix
unlink(filename);
#else
remove(filename);
#endif
287
Then, you could place the line
#define unix
at the top of the file when compiling under an old Unix system. (Since all you're
using the macro unix for is to control the #ifdef, you don't need to give it any
replacement text at all. Any definition for a macro, even if the replacement text is
empty, causes an #ifdef to succeed.)
(In fact, in this example, you wouldn't even need to define the macro unix at all,
because C compilers on old Unix systems tend to predefine it for you, precisely
so you can make tests like these.)
You want to compile several different versions of your program, with different
features present in the different versions. You bracket the code for each feature
with #ifdef directives, and (as for the previous case) arrange to have the right
macros defined or not to build the version you want to build at any given time.
This way, you can build the several different versions from the same source
code. (One common example is whether you turn debugging statements on or
off. You can bracket each debugging printout with #ifdef DEBUG and #endif, and
then turn on debugging only when you need it.)
#ifdef DEBUG
printf("x is %d\n", x);
#endif
to print out the value of the variable x at some point in your program to see if it's
what you expect. To enable debugging printouts, you insert the line
#define DEBUG
at the top of the file, and to turn them off, you delete that line, but the debugging
printouts quietly remain in your code, temporarily deactivated, but ready to
reactivate if you find yourself needing them again later. (Also, instead of inserting
and deleting the #define line, you might use a compiler flag such as -DDEBUG to
define the macro DEBUG from the compiler invocatin line.)
Conditional compilation can be very handy, but it can also get out of hand. When large
chunks of the program are completely different depending on, say, what operating
system the program is being compiled for, it's often better to place the different versions
in separate source files, and then only use one of the files (corresponding to one of the
versions) to build the program on any given system. Also, if you are using an ANSI
Standard compiler and you are writing ANSI-compatible code, you usually won't need
288
so much conditional compilation, because the Standard specifies exactly how the
compiler must do certain things, and exactly which library functions it much provide, so
you don't have to work so hard to accommodate the old variations among compilers and
libraries.
There are different ways in which parameter data can be passed into and out of methods
and functions. Let us assume that a function B() is called from another function A(). In this
case A is called the ―caller function‖ and B is called the ―called function or callee
function‖. Also, the arguments which A sends to B are called actual arguments and the
parameters of B are called formal arguments.
Terminology
Formal Parameter : A variable and its type as they appear in the prototype of the
function or method.
Modes:
1. Pass By Value : This method uses in-mode semantics. Changes made to formal
parameter do not get transmitted back to the caller. Any modifications to the formal
parameter variable inside the called function or method affect only the separate
storage location and will not be reflected in the actual parameter in the calling
environment. This method is also called as call by value.
289
filter_none
edit
play_arrow
brightness_4
// C program to illustrate
// call by value
#include <stdio.h>
// Passing parameters
func(x, y);
290
printf("In main, x = %d y = %d\n", x, y);
return 0;
}
Output:
In func, a = 12 b = 7
In main, x = 5 y = 7
Languages like C, C++, Java support this type of parameter passing. Java in fact is
strictly call by value.
Shortcomings:
291
filter_none
edit
play_arrow
brightness_4
// C program to illustrate
// call by reference
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
// passing parameters
swapnum(&a, &b);
C and C++ both support call by value as well as call by reference whereas Java
does‘nt support call by reference.
Shortcomings:
These techniques are older and were used in earlier programming languages like Pascal,
Algol and Fortran. These techniques are not applicable in high level languages.
1. Pass by Result : This method uses out-mode semantics. Just before control is
transfered back to the caller, the value of the formal parameter is transmitted back
to the actual parameter.T his method is sometimes called call by result. In general,
pass by result technique is implemented by copy.
292
2. Pass by Value-Result : This method uses in/out-mode semantics. It is a
combination of Pass-by-Value and Pass-by-result. Just before the control is
transferred back to the caller, the value of the formal parameter is transmitted back
to the actual parameter. This method is sometimes called as call by value-result
3. Pass by name : This technique is used in programming language such as Algol.
In this technique, symbolic ―name‖ of a variable is passed, which allows it both to
be accessed and update.
Example:
To double the value of C[j], you can pass its name (not its value) into the following
procedure.
4. procedure double(x);
5. real x;
6. begin
7. x:=x*2
8. end;
In general, the effect of pass-by-name is to textually substitute the argument in a
procedure call for the corresponding parameter in the body of the procedure.
Implications of Pass-by-Name mechanism:
The argument expression is re-evaluated each time the formal parameter is
passed.
The procedure can change the values of variables used in the argument
expression and hence change the expression‘s value.
Input/Output
When we say Input, it means to feed some data into a program. An input can be given
in the form of a file or from the command line. C programming provides a set of built-in
functions to read the given input and feed it to the program as per requirement.
When we say Output, it means to display some data on screen, printer, or in any file.
C programming provides a set of built-in functions to output the data on the computer
screen as well as to save it in text or binary files.
C programming treats all the devices as files. So devices such as the display are
addressed in the same way as files and the following three files are automatically
opened when a program executes to provide access to the keyboard and screen.
293
Standard File File Pointer Device
The file pointers are the means to access the file for reading and writing purpose. This
section explains how to read values from the screen and how to print the result on the
screen.
The int getchar(void) function reads the next available character from the screen and
returns it as an integer. This function reads only single character at a time. You can
use this method in the loop in case you want to read more than one character from the
screen.
The int putchar(int c) function puts the passed character on the screen and returns
the same character. This function puts only single character at a time. You can use this
method in the loop in case you want to display more than one character on the screen.
Check the following example –
#include <stdio.h>
int main( ) {
int c;
return 0;
}
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then the program proceeds and reads only a
single character and displays it as follows −
294
$./a.out
Enter a value : this is test
You entered: t
The char *gets(char *s) function reads a line from stdin into the buffer pointed to
by s until either a terminating newline or EOF (End of File).
The int puts(const char *s) function writes the string 's' and 'a' trailing newline
to stdout.
NOTE: Though it has been deprecated to use gets() function, Instead of using gets,
you want to use fgets().
#include <stdio.h>
int main( ) {
char str[100];
return 0;
}
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then the program proceeds and reads the
complete line till end, and displays it as follows −
$./a.out
Enter a value : this is test
You entered: this is test
The int scanf(const char *format, ...) function reads the input from the standard input
stream stdin and scans that input according to the format provided.
The int printf(const char *format, ...) function writes the output to the standard output
stream stdout and produces the output according to the format provided.
295
The format can be a simple constant string, but you can specify %s, %d, %c, %f, etc.,
to print or read strings, integer, character or float respectively. There are many other
formatting options available which can be used based on requirements. Let us now
proceed with a simple example to understand the concepts better –
#include <stdio.h>
int main( ) {
char str[100];
int i;
return 0;
}
When the above code is compiled and executed, it waits for you to input some text.
When you enter a text and press enter, then program proceeds and reads the input
and displays it as follows −
$./a.out
Enter a value : seven 7
You entered: seven 7
Here, it should be noted that scanf() expects input in the same format as you provided
%s and %d, which means you have to provide valid inputs like "string integer". If you
provide "string string" or "integer integer", then it will be assumed as wrong input.
Secondly, while reading a string, scanf() stops reading as soon as it encounters a
space, so "this is test" are three strings for scanf().
The last chapter explained the standard input and output devices handled by C
programming language. This chapter cover how C programmers can create, open,
close text or binary files for their data storage.
A file represents a sequence of bytes, regardless of it being a text file or a binary file. C
programming language provides access on high level functions as well as low level
(OS level) calls to handle file on your storage devices. This chapter will take you
through the important calls for file management.
296
Opening Files
You can use the fopen( ) function to create a new file or to open an existing file. This
call will initialize an object of the type FILE, which contains all the information
necessary to control the stream. The prototype of this function call is as follows −
FILE *fopen( const char * filename, const char * mode );
Here, filename is a string literal, which you will use to name your file, and
access mode can have one of the following values –
1 r
Opens an existing text file for reading purpose.
2 w
Opens a text file for writing. If it does not exist, then a new file is created. Here
your program will start writing content from the beginning of the file.
3 a
Opens a text file for writing in appending mode. If it does not exist, then a new file
is created. Here your program will start appending content in the existing file
content.
4 r+
Opens a text file for both reading and writing.
5 w+
Opens a text file for both reading and writing. It first truncates the file to zero
length if it exists, otherwise creates a file if it does not exist.
6 a+
Opens a text file for both reading and writing. It creates the file if it does not exist.
The reading will start from the beginning but writing can only be appended.
297
If you are going to handle binary files, then you will use following access modes
instead of the above mentioned ones −
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
Closing a File
To close a file, use the fclose( ) function. The prototype of this function is −
int fclose( FILE *fp );
The fclose(-) function returns zero on success, or EOF if there is an error in closing the
file. This function actually flushes any data still pending in the buffer to the file, closes
the file, and releases any memory used for the file. The EOF is a constant defined in
the header file stdio.h.
There are various functions provided by C standard library to read and write a file,
character by character, or in the form of a fixed length string.
Writing a File
main() {
FILE *fp;
fp = fopen("/tmp/test.txt", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
fclose(fp);
}
298
When the above code is compiled and executed, it creates a new file test.txt in /tmp
directory and writes two lines using two different functions. Let us read this file in the
next section.
Reading a File
Given below is the simplest function to read a single character from a file −
int fgetc( FILE * fp );
The fgetc() function reads a character from the input file referenced by fp. The return
value is the character read, or in case of any error, it returns EOF. The following
function allows to read a string from a stream −
char *fgets( char *buf, int n, FILE *fp );
The functions fgets() reads up to n-1 characters from the input stream referenced by
fp. It copies the read string into the buffer buf, appending a null character to terminate
the string.
If this function encounters a newline character '\n' or the end of the file EOF before they
have read the maximum number of characters, then it returns only the characters read
up to that point including the new line character. You can also use int fscanf(FILE *fp,
const char *format, ...) function to read strings from a file, but it stops reading after
encountering the first space character.
#include <stdio.h>
main() {
FILE *fp;
char buff[255];
fp = fopen("/tmp/test.txt", "r");
fscanf(fp, "%s", buff);
printf("1 : %s\n", buff );
}
When the above code is compiled and executed, it reads the file created in the
previous section and produces the following result −
299
1 : This
2: is testing for fprintf...
There are two functions, that can be used for binary input and output −
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE
*a_file);
Fopen
The C library function FILE *fopen(const char *filename, const char *mode) opens
the filename pointed to, by filename using the given mode.
Declaration
Parameters
filename − This is the C string containing the name of the file to be opened.
mode − This is the C string containing a file access mode. It includes −
1 "r"
Opens a file for reading. The file must exist.
300
2 "w"
Creates an empty file for writing. If a file with the same name already exists, its
content is erased and the file is considered as a new empty file.
3 "a"
Appends to a file. Writing operations, append data at the end of the file. The file
is created if it does not exist.
4 "r+"
Opens a file to update both reading and writing. The file must exist.
5 "w+"
Creates an empty file for both reading and writing.
6 "a+"
Opens a file for reading and appending.
Return Value
This function returns a FILE pointer. Otherwise, NULL is returned and the global
variable errno is set to indicate the error.
Example
int main () {
FILE * fp;
fclose(fp);
return(0);
301
}
Let us compile and run the above program that will create a file file.txt with the
following content −
We are in 2012
Now let us see the content of the above file using the following program −
#include <stdio.h>
int main () {
FILE *fp;
int c;
fp = fopen("file.txt","r");
while(1) {
c = fgetc(fp);
if( feof(fp) ) {
break ;
}
printf("%c", c);
}
fclose(fp);
return(0);
}
Let us compile and run the above program to produce the following result −
We are in 2012
Fread
The C library function size_t fread(void *ptr, size_t size, size_t nmemb, FILE
*stream) reads data from the given stream into the array pointed to, by ptr.
Declaration
Parameters
302
nmemb − This is the number of elements, each one with a size of size bytes.
stream − This is the pointer to a FILE object that specifies an input stream.
Return Value
The total number of elements successfully read are returned as a size_t object, which
is an integral data type. If this number differs from the nmemb parameter, then either
an error had occurred or the End Of File was reached.
Example
int main () {
FILE *fp;
char c[] = "this is tutorialspoint";
char buffer[100];
return(0);
}
Let us compile and run the above program that will create a file file.txt and write a
content this is tutorialspoint. After that, we use fseek() function to reset writing pointer
to the beginning of the file and prepare the file content which is as follows −
this is tutorialspoint
303
string handling functions
String is an array of characters. In this guide, we learn how to declare strings, how to
work with strings in C programming and how to use the pre-defined string handling
functions.
We will see how to compare two strings, concatenate strings, copy one string to another
& perform various string manipulation operations. We can perform such operations
using the pre-defined functions of ―string.h‖ header file. In order to use these string
functions you must include string.h file in your C program.
String Declaration
Method 1:
char address[]="TEXAS";
In the above declaration NULL character (\0) will automatically be inserted at the end of
the string.
304
Read & write Strings in C using Printf() and Scanf() functions
#include <stdio.h>
#include <string.h>
int main()
{
/* String Declaration*/
char nickname[20];
/*Displaying String*/
printf("%s",nickname);
return 0;
}
Output:
#include <stdio.h>
305
#include <string.h>
int main()
{
/* String Declaration*/
char nickname[20];
puts(nickname);
return 0;
}
C – String functions
306
C String function – strlen
Syntax:
Example of strlen:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "BeginnersBook";
printf("Length of string str1: %d", strlen(str1));
return 0;
}
Output:
Syntax:
Example of strnlen:
#include <stdio.h>
#include <string.h>
307
int main()
{
char str1[20] = "BeginnersBook";
printf("Length of string str1 when maxlen is 30: %d", strnlen(str1, 30));
printf("Length of string str1 when maxlen is 10: %d", strnlen(str1, 10));
return 0;
}
Output:
Length of string str1 when maxlen is 30: 13
Length of string str1 when maxlen is 10: 10
Have you noticed the output of second printf statement, even though the string length
was 13 it returned only 10 because the maxlen was 10.
Example of strcmp:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[20] = "BeginnersBook";
char s2[20] = "BeginnersBook.COM";
if (strcmp(s1, s2) ==0)
{
printf("string 1 and string 2 are equal");
}else
{
printf("string 1 and 2 are different");
}
return 0;
}
Output:
308
string 1 and 2 are different
C String function – strncmp
Example of strncmp:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[20] = "BeginnersBook";
char s2[20] = "BeginnersBook.COM";
/* below it is comparing first 8 characters of s1 and s2*/
if (strncmp(s1, s2, 8) ==0)
{
printf("string 1 and string 2 are equal");
}else
{
printf("string 1 and 2 are different");
}
return 0;
}
Output:
Example of strcat:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[10] = "Hello";
char s2[10] = "World";
strcat(s1,s2);
printf("Output string after concatenation: %s", s1);
return 0;
309
}
Output:
Example of strncat:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[10] = "Hello";
char s2[10] = "World";
strncat(s1,s2, 3);
printf("Concatenation using strncat: %s", s1);
return 0;
}
Output:
Example of strcpy:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[30] = "string 1";
char s2[30] = "string 2 : I‘m gonna copied into s1";
/* this function has copied s2 into s1*/
strcpy(s1,s2);
printf("String s1 is: %s", s1);
return 0;
}
Output:
310
String s1 is: string 2: I‘m gonna copied into s1
C String function – strncpy
Example of strncpy:
#include <stdio.h>
#include <string.h>
int main()
{
char first[30] = "string 1";
char second[30] = "string 2: I‘m using strncpy now";
/* this function has copied first 10 chars of s2 into s1*/
strncpy(s1,s2, 12);
printf("String s1 is: %s", s1);
return 0;
}
Output:
Example of strchr:
#include <stdio.h>
#include <string.h>
int main()
{
char mystr[30] = "I‘m an example of function strchr";
printf ("%s", strchr(mystr, 'f'));
return 0;
}
Output:
311
f function strchr
C String function – Strrchr
#include <stdio.h>
#include <string.h>
int main()
{
char mystr[30] = "I‘m an example of function strchr";
printf ("%s", strrchr(mystr, 'f'));
return 0;
}
Output:
function strchr
Why output is different than strchr? It is because it started searching from the end of
the string and found the first ‗f‘ in function instead of ‗of‘.
Example of strstr:
#include <stdio.h>
#include <string.h>
int main()
{
char inputstr[70] = "String Function in C at BeginnersBook.COM";
printf ("Output string is: %s", strstr(inputstr, 'Begi'));
return 0;
}
Output:
312
Math functions :
sin( ), cos( ) and tan( ) functions in C are used to calculate sine, cosine
and tangent values.
sinh( ), cosh( ) and tanh( ) functions are used to calculate hyperbolic sine, cosine
and tangent values.
exp( ) function is used to calculate the exponential ―e‖ to the xth power. log( )
function is used to calculates natural logarithm and log10( ) function is used to
calculates base 10 logarithm.
1 #include <stdio.h>
3 #include <math.h>
5 int main()
7 {
8 float i = 0.314;
9 float j = 0.25;
10 float k = 6.25;
313
12 float cos_value = cos(i);
20
30 return 0;
31 }
OUTPUT:
The value of sin(0.314000) : 0.308866
The value of cos(0.314000) : 0.951106
The value of tan(0.314000) : 0.324744
314
The value of cosh(0.250000) : 1.031413
315
cosh ( ) This function is used to calculate hyperbolic cosine.
Standard C functions
In this tutorial, you will be introduced to functions (both user-defined and standard
library functions) in C programming. Also, you will learn why functions are used in
programming.
Suppose, you need to create a program to create a circle and color it. You can create
two functions to solve this problem:
316
Dividing a complex problem into smaller chunks makes our program easy to understand
and reuse.
Types of function
The printf() is a standard library function to send formatted output to the screen (display
output on the screen). This function is defined in the stdio.h header file.
Hence, to use the printf()function, we need to include the stdio.h header file
using #include <stdio.h>.
The sqrt() function calculates the square root of a number. The function is defined in
the math.h header file.
User-defined function
You can also create functions as per your need. Such functions created by the user are
known as user-defined functions.
#include <stdio.h>
void functionName()
... .. ...
... .. ...
int main()
317
... .. ...
... .. ...
functionName();
... .. ...
... .. ...
void functionName()
3. A large program can be divided into smaller modules. Hence, a large project can be
divided among many programmers.
318