As this complete example shows, we call the PDOStatement::fetch() method until
it returns a false value, at which point the loop quits—just like we did in previous
examples when discussing result sets traversal.
Of course, the replacement of question mark placeholders with actual values is not
the only thing that prepared statements can do. Their power lies in the possibility
of being executed as many times as needed. This means that we can call the
PDOStatement::execute() method as many times as we want, and every time we
can supply different values for the placeholders. For example, we can do this:
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
$stmt = $conn->prepare($sql);
// Fetch the 'new' cars:
$stmt->execute(array(2005, 2007));
$newCars = $stmt->fetchAll(PDO::FETCH_ASSOC);
// now, 'older' cars:
$stmt->execute(array(2000, 2004));
$olderCars = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Show them
echo 'We have ', count($newCars), ' cars dated 2005-2007';
print_r($newCars);
echo 'Also we have ', count($olderCars), ' cars dated 2000-2004';
print_r($olderCars);
Prepared statements tend to execute faster than calls to PDO::query() methods,
since the database drivers optimize them only once, in a call to PDO::prepare()
methods. Another advantage of using prepared statements is that you don't have to
quote the parameters passed in a call to PDOStatement::execute().
In our example we used an explicit cast of the request parameters into integer
variables, but we could also have done the following:
// Assume we also want to filter by make
$sql = 'SELECT * FROM cars WHERE make=?';
$stmt = $conn->prepare($sql);
$stmt->execute(array($_REQUEST['make']));
The prepared statement here will take care of the proper quoting made before
executing the query.
And just to fi nish the introduction of the prepared statements here, probably the best
feature about them is that PDO emulates them for every supported database. This
means you can use prepared statements with any databases; even if they don’t know
what they are.
Appropriate Understanding of PDO
Our introduction would not be complete if we didn't mention that. PDO is a database
connection abstraction library, and as such, cannot ensure that your code will work
for each and every database that it supports. This will only happen if your SQL code
is portable. For example, MySQL extends the SQL syntax with this form of insert:
INSERT INTO mytable SET x=1, y='two';
This kind of SQL code is not portable, as other databases do not understand this
way of doing inserts. To ensure that your inserts work across databases, you should
replace the above code with :
INSERT INTO mytable(x, y) VALUES(1, 'two');
This is just one example of incompatibilities that may arise when you use PDO.
It is only by making your database schema and SQL portable that can ensure you
that your code will be compatible with other databases. However, ensuring this
portability is beyond this text.
Summary
This introductory chapter showed you the basics of using PDO when developing
dynamic, database-driven applications with the PHP5 language. Also we looked
at how PDO can be effectively used to eliminate the differences between different
traditional database access APIs and to produce a clearer and more portable code.
In the subsequent chapters, we will be looking at each of the features discussed in this
chapter in a greater detail so that you fully master the PHP Data Objects extension.
Introduction PHP Data Objects-3
Error Handling
Of course, the above examples didn't provide for any error checking, so they are not
very useful for real-life applications.
When working with a database, we should check for errors when opening the
connection to the database, when selecting the database and after issuing every
query. Most web applications, however, just need to display an error message when
something goes wrong (without going into error detail, which could reveal some
sensitive information). However, when debugging an error, you (as the developer)
would need the most detailed error information possible so that you can debug the
error in the shortest possible time.
One simplistic scenario would be to abort the script and present the error message
(although this is something you probably would not want to do). Depending on the
database, our code might look like this:
// For SQLite:
$dbh = sqlite_open('/path/to/cars.ldb', 0666) or die
('Error opening SQLite database: ' .
sqlite_error_string(sqlite_last_error($dbh)));
$q = sqlite_query("SELECT DISTINCT make FROM cars ORDER BY make",
$dbh) or die('Could not execute query because: ' .
sqlite_error_string(sqlite_last_error($dbh)));
// and, finally, for PostgreSQL:
pg_connect("host=localhost dbname=cars user=boss
password=password") or die('Could not connect to
PostgreSQL: . pg_last_error());
$q = pg_query("SELECT DISTINCT make FROM cars ORDER BY make")
or die('Could not execute query because: ' . pg_last_error());
As you can see, error handling is starting to get a bit different for SQLite compared
to MySQL and PostgreSQL. (Note the call to sqlite_error_string
(sqlite_last_error($dbh)).)
Before we take a look at how to implement the same error handling strategy with
PDO, we should note that this will be only one of the three possible error handling
strategies in PDO. We will cover them in detail later in this book. Here we will just
use the simplest one:
// PDO error handling
// Assume the connection string is one of the following:
// $connStr = 'mysql:host=localhost;dbname=cars'
// $connStr = 'sqlite:/path/to/cars.ldb';
// $connStr = 'pgsql:host=localhost dbname=cars';
try
{
$conn = new PDO($connStr, 'boss', 'password');
}
catch(PDOException $pe)
{
die('Could not connect to the database because: ' .
$pe->getMessage();
}
$q = $conn->query("SELECT DISTINCT make FROM cars ORDER BY make");
if(!$q)
{
$ei = $conn->errorInfo();
die('Could not execute query because: ' . $ei[2]);
}
This example shows that PDO will force us to use a slightly different error handling
scheme from the traditional one. We wrapped the call to the PDO constructor in a
try … catch block. (Those who are new to PHP5's object-oriented features should
refer to Appendix A.) This is because while PDO can be instructed not to use
exceptions, (in fact, it is PDO's default behavior not to use exceptions), however,
you cannot avoid exceptions here. If the call to the constructor fails, an exception
will always be thrown.
It is a very good idea to catch that exception because, by default, PHP will abort the
script execution and will display an error message like this:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[28000]
[1045] Access denied for user 'bosss'@'localhost' (using password: YES)' in /var/
www/html/pdo.php5:3 Stack trace: #0 c:\www\hosts\localhost\pdo.php5(3):
PDO->__construct('mysql:host=loca...', 'bosss', 'password', Array) #1 {main}
thrown in /var/www/html/pdo.php5 on line 3
We made this exception by supplying the wrong username, bosss, in the call to the
PDO constructor. As you can see from this output, it contains some details that we
would not like others to see: Things like fi le names and script paths, the type of
database being used, and most importantly, usernames and passwords. Suppose
that this exception had happened when we had supplied the right username and
something had gone wrong with the database server. Then the screen output would
have contained the real username and password.
If we catch the exception properly, the error output might look like this:
SQLSTATE[28000] [1045] Access denied for user 'bosss'@'localhost' (using
password: YES)
This error message contains much less sensitive information. (In fact, this output
is very similar to the error output that would be produced by one of our non-PDO
examples.) But we will again warn you that the best policy is just show some neutral
error message like: "Sorry, the service is temporarily unavailable. Please try again
later." Of course, you should also log all errors so that you can fi nd out later whether
anything bad has happened.
Prepared Statements
This is a rather advanced topic, but you should become familiar with it. If you are a
user of PHP with MySQL or SQLite, then you probably didn't even hear of prepared
statements, since PHP's MySQL and SQLite extensions don't offer this functionality.
PostgreSQL users might have already used pg_prepare() and pg_execute()
in tandem. MySQLi (the improved MySQL extension) also offers the prepared
statements functionality, but in a somewhat awkward way (despite the possible
object-oriented style).
For those who are not familiar with prepared statements, we will now give a
short explanation.
When developing database-driven, interactive dynamic applications, you will sooner
or later need to take user input (which may originate from a form) and pass it as
a part of a query to a database. For example, given our cars' database, you might
design a feature that will output a list of cars made between any two years. If you
allow the user to enter these years in a form, the code will look something like this:
// Suppose the years come in the startYear and endYear
// request variables:
$sy = (int)$_REQUEST['startYear'];
$ey = (int)$_REQUEST['endYear'];
if($ey < $sy)
{
// ensure $sy is less than $ey
$tmp = $ey;
$ey = $sy;
$sy = $tmp;
}
$sql = "SELECT * FROM cars WHERE year >= $sy AND year <= $ey";
// send the query in $sql…
In this simple example the query depends on two variables, which are part of the
resulting SQL. A corresponding prepared statement in PDO would look something
like this:
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
As you can see, we replaced the $sy and $ey variables with placeholders in the
query body. We can now manipulate this query to create the prepared statement and
execute it:
// Assuming we have already connected and prepared
// the $sy and $ey variables
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
$stmt = $conn->prepare($sql);
$stmt->execute(array($sy, $ey));
These three lines of code tells us that the prepared statements are objects (with class
PDOStatement). They are created using calls to PDO::prepare() method that accepts
an SQL statement with placeholders as its parameters.
The prepared statements then have to be executed in order to obtain the query results
by calling the PDOStatement::execute() method. As the example shows, we call
this method with an array that holds the values for the placeholders. Note how the
order of the variables in that array matches the order of the placeholders in the $sql
variable. Obviously, the number of elements in the array must be the same as the
number of placeholders in the query.
You have probably noticed that we are not saving the result of the call to the
PDOStatement::execute() method in any variable. This is because the statement
object itself is used to access the query results, so that we can complete our example
to look like this:
// Suppose the years come in the startYear and endYear
// request variables:
$sy = (int)$_REQUEST['startYear'];
$ey = (int)$_REQUEST['endYear'];
if($ey < $sy)
{
// ensure $sy is less than $ey
$tmp = $ey;
$ey = $sy;
$sy = $tmp;
}
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
$stmt = $conn->prepare($sql);
$stmt->execute(array($sy, $ey));
// now iterate over the result as if we obtained
// the $stmt in a call to PDO::query()
while($r = $stmt->fetch(PDO::FETCH_ASSOC))
{
echo "$r[make] $r[model] $r[year]\n";
}
Of course, the above examples didn't provide for any error checking, so they are not
very useful for real-life applications.
When working with a database, we should check for errors when opening the
connection to the database, when selecting the database and after issuing every
query. Most web applications, however, just need to display an error message when
something goes wrong (without going into error detail, which could reveal some
sensitive information). However, when debugging an error, you (as the developer)
would need the most detailed error information possible so that you can debug the
error in the shortest possible time.
One simplistic scenario would be to abort the script and present the error message
(although this is something you probably would not want to do). Depending on the
database, our code might look like this:
// For SQLite:
$dbh = sqlite_open('/path/to/cars.ldb', 0666) or die
('Error opening SQLite database: ' .
sqlite_error_string(sqlite_last_error($dbh)));
$q = sqlite_query("SELECT DISTINCT make FROM cars ORDER BY make",
$dbh) or die('Could not execute query because: ' .
sqlite_error_string(sqlite_last_error($dbh)));
// and, finally, for PostgreSQL:
pg_connect("host=localhost dbname=cars user=boss
password=password") or die('Could not connect to
PostgreSQL: . pg_last_error());
$q = pg_query("SELECT DISTINCT make FROM cars ORDER BY make")
or die('Could not execute query because: ' . pg_last_error());
As you can see, error handling is starting to get a bit different for SQLite compared
to MySQL and PostgreSQL. (Note the call to sqlite_error_string
(sqlite_last_error($dbh)).)
Before we take a look at how to implement the same error handling strategy with
PDO, we should note that this will be only one of the three possible error handling
strategies in PDO. We will cover them in detail later in this book. Here we will just
use the simplest one:
// PDO error handling
// Assume the connection string is one of the following:
// $connStr = 'mysql:host=localhost;dbname=cars'
// $connStr = 'sqlite:/path/to/cars.ldb';
// $connStr = 'pgsql:host=localhost dbname=cars';
try
{
$conn = new PDO($connStr, 'boss', 'password');
}
catch(PDOException $pe)
{
die('Could not connect to the database because: ' .
$pe->getMessage();
}
$q = $conn->query("SELECT DISTINCT make FROM cars ORDER BY make");
if(!$q)
{
$ei = $conn->errorInfo();
die('Could not execute query because: ' . $ei[2]);
}
This example shows that PDO will force us to use a slightly different error handling
scheme from the traditional one. We wrapped the call to the PDO constructor in a
try … catch block. (Those who are new to PHP5's object-oriented features should
refer to Appendix A.) This is because while PDO can be instructed not to use
exceptions, (in fact, it is PDO's default behavior not to use exceptions), however,
you cannot avoid exceptions here. If the call to the constructor fails, an exception
will always be thrown.
It is a very good idea to catch that exception because, by default, PHP will abort the
script execution and will display an error message like this:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[28000]
[1045] Access denied for user 'bosss'@'localhost' (using password: YES)' in /var/
www/html/pdo.php5:3 Stack trace: #0 c:\www\hosts\localhost\pdo.php5(3):
PDO->__construct('mysql:host=loca...', 'bosss', 'password', Array) #1 {main}
thrown in /var/www/html/pdo.php5 on line 3
We made this exception by supplying the wrong username, bosss, in the call to the
PDO constructor. As you can see from this output, it contains some details that we
would not like others to see: Things like fi le names and script paths, the type of
database being used, and most importantly, usernames and passwords. Suppose
that this exception had happened when we had supplied the right username and
something had gone wrong with the database server. Then the screen output would
have contained the real username and password.
If we catch the exception properly, the error output might look like this:
SQLSTATE[28000] [1045] Access denied for user 'bosss'@'localhost' (using
password: YES)
This error message contains much less sensitive information. (In fact, this output
is very similar to the error output that would be produced by one of our non-PDO
examples.) But we will again warn you that the best policy is just show some neutral
error message like: "Sorry, the service is temporarily unavailable. Please try again
later." Of course, you should also log all errors so that you can fi nd out later whether
anything bad has happened.
Prepared Statements
This is a rather advanced topic, but you should become familiar with it. If you are a
user of PHP with MySQL or SQLite, then you probably didn't even hear of prepared
statements, since PHP's MySQL and SQLite extensions don't offer this functionality.
PostgreSQL users might have already used pg_prepare() and pg_execute()
in tandem. MySQLi (the improved MySQL extension) also offers the prepared
statements functionality, but in a somewhat awkward way (despite the possible
object-oriented style).
For those who are not familiar with prepared statements, we will now give a
short explanation.
When developing database-driven, interactive dynamic applications, you will sooner
or later need to take user input (which may originate from a form) and pass it as
a part of a query to a database. For example, given our cars' database, you might
design a feature that will output a list of cars made between any two years. If you
allow the user to enter these years in a form, the code will look something like this:
// Suppose the years come in the startYear and endYear
// request variables:
$sy = (int)$_REQUEST['startYear'];
$ey = (int)$_REQUEST['endYear'];
if($ey < $sy)
{
// ensure $sy is less than $ey
$tmp = $ey;
$ey = $sy;
$sy = $tmp;
}
$sql = "SELECT * FROM cars WHERE year >= $sy AND year <= $ey";
// send the query in $sql…
In this simple example the query depends on two variables, which are part of the
resulting SQL. A corresponding prepared statement in PDO would look something
like this:
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
As you can see, we replaced the $sy and $ey variables with placeholders in the
query body. We can now manipulate this query to create the prepared statement and
execute it:
// Assuming we have already connected and prepared
// the $sy and $ey variables
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
$stmt = $conn->prepare($sql);
$stmt->execute(array($sy, $ey));
These three lines of code tells us that the prepared statements are objects (with class
PDOStatement). They are created using calls to PDO::prepare() method that accepts
an SQL statement with placeholders as its parameters.
The prepared statements then have to be executed in order to obtain the query results
by calling the PDOStatement::execute() method. As the example shows, we call
this method with an array that holds the values for the placeholders. Note how the
order of the variables in that array matches the order of the placeholders in the $sql
variable. Obviously, the number of elements in the array must be the same as the
number of placeholders in the query.
You have probably noticed that we are not saving the result of the call to the
PDOStatement::execute() method in any variable. This is because the statement
object itself is used to access the query results, so that we can complete our example
to look like this:
// Suppose the years come in the startYear and endYear
// request variables:
$sy = (int)$_REQUEST['startYear'];
$ey = (int)$_REQUEST['endYear'];
if($ey < $sy)
{
// ensure $sy is less than $ey
$tmp = $ey;
$ey = $sy;
$sy = $tmp;
}
$sql = 'SELECT * FROM cars WHERE year >= ? AND year <= ?';
$stmt = $conn->prepare($sql);
$stmt->execute(array($sy, $ey));
// now iterate over the result as if we obtained
// the $stmt in a call to PDO::query()
while($r = $stmt->fetch(PDO::FETCH_ASSOC))
{
echo "$r[make] $r[model] $r[year]\n";
}
Introduction PHP Data Objects-2
Issuing SQL Queries, Quoting Parameters,
and Handling Result Sets
PDO would not be worth a whole book, if it didn't go beyond the single interface
for creating database connections. The PDO object introduced in the previous
example has all the methods needed to uniformly execute queries regardless of the
database used.
Let's consider a simple query that would select all the car make attributes from
an imaginary database employed at a used car lot. The query is as simple as the
following SQL command:
SELECT DISTINCT make FROM cars ORDER BY make;
Previously, we would have had to call different functions, depending on
the database:
// Let's keep our SQL in a single variable
$sql = 'SELECT DISTINCT make FROM cars ORDER BY make';
// Now, assuming MySQL:
mysql_connect('localhost', 'boss', 'password');
mysql_select_db('cars');
$q = mysql_query($sql);
// For SQLite we would do:
$dbh = sqlite_open('/path/to/cars.ldb', 0666);
$q = sqlite_query($sql, $dbh);
// And for PostgreSQL:
pg_connect("host=localhost dbname=cars user=boss
password=password");
$q = pg_query($sql);
Now that we are using PDO, we can do the following:
// assume the $connStr variable holds a valid connection string
// as discussed in previous point
$sql = 'SELECT DISTINCT make FROM cars ORDER BY make';
$conn = new PDO($connStr, 'boss', 'password');
$q = $conn->query($sql);
As you can see, doing things the PDO way is not too different from traditional
methods of issuing queries. Also, here it should be underlined, that a call to
$conn->query() is returning another object of class PDOStatement, unlike the calls
to mysql_query(), sqlite_query(), and pg_query(), which return PHP variables
of the resource type.
Now, let's make our simplistic SQL query a bit more complicated so that it selects the
total value of all Fords on sale in our imaginary car lot. The query would then look
something like this:
SELECT sum(price) FROM cars WHERE make='Ford'
To make our example even more interesting, let's assume that the name of the car
manufacturer is held in a variable ($make) so that we must quote it, before passing it
to the database. Our non-PDO queries would now look like this:
$make = 'Ford';
// MySQL:
$m = mysql_real_escape_string($make);
$q = mysql_query("SELECT sum(price) FROM cars WHERE make='$m'");
// SQLite:
$m = sqlite_escape_string($make);
$q = sqlite_query("SELECT sum(price) FROM cars WHERE make='$m'",
$dbh);
// and PostgreSQL:
$m = pg_escape_string($make);
$q = pg_query("SELECT sum(price) FROM cars WHERE make='$m'");
The PDO class defi nes a single method for quoting strings so that they can be used
safely in queries. We will discuss security issues such as SQL injection, in Chapter 3.
This method does a neat thing; it will automatically add quotes around the value
if necessary:
$m = $conn->quote($make);
$q = $conn->query("SELECT sum(price) FROM cars WHERE make=$m");
Again, you can see that PDO allows you to use the same pattern as you would have
used before, but the names of all the methods are unifi ed.
Now that we have issued our query, we will want to see its results. As the query in
the last example will always return just one row, we will want more rows. Again,
the three databases will require us to call different functions on the $q variable that
was returned from one of the three calls to mysql_query(), sqlite_query(), or
pg_query(). So our code for getting all the cars will look similar to this:
// assume the query is in the $sql variable
$sql = "SELECT DISTINCT make FROM cars ORDER BY make";
// For MySQL:
$q = mysql_query($sql);
while($r = mysql_fetch_assoc($q))
{
echo $r['make'], "\n";
}
// For SQLite:
$q = sqlite_query($dbh, $sql);
while($r = sqlite_fetch_array($q, SQLITE_ASSOC))
{
echo $r['make'], "\n";
}
// and, finally, PostgreSQL:
$q = pg_query($sql);
while($r = pg_fetch_assoc($q))
{
echo $r['make'], "\n";
}
As you can see, the idea is the same, but we have to use different function names.
Also, note that SQLite requires an extra parameter if we want to get the rows in the
same way as with MySQL and PostgreSQL (of course, this could be omitted, but
then the returned rows would contain both column name indexed and numerically
indexed elements.)
As you may already have guessed, things are pretty straightforward when it comes
to PDO: We don't care what the underlying database is, and the methods for fetching
rows are the same across all databases. So, the above code could be rewritten for
PDO in the following way:
$q = $conn->query("SELECT DISTINCT make FROM cars ORDER BY make");
while($r = $q->fetch(PDO::FETCH_ASSOC))
{
echo $r['make'], "\n";
}
Nothing is different from what happens before. One thing to note here is that we
explicitly specifi ed the PDO::FETCH_ASSOC fetch style constant here, since PDO's
default behavior is to fetch the result rows as arrays indexed both by column
name and number. (This behavior is similar to mysql_fetch_array(),
sqlite_fetch_array() without the second parameter, or pg_fetch_array().)
We will discuss the fetch styles that PDO has to offer in Chapter 2.
and Handling Result Sets
PDO would not be worth a whole book, if it didn't go beyond the single interface
for creating database connections. The PDO object introduced in the previous
example has all the methods needed to uniformly execute queries regardless of the
database used.
Let's consider a simple query that would select all the car make attributes from
an imaginary database employed at a used car lot. The query is as simple as the
following SQL command:
SELECT DISTINCT make FROM cars ORDER BY make;
Previously, we would have had to call different functions, depending on
the database:
// Let's keep our SQL in a single variable
$sql = 'SELECT DISTINCT make FROM cars ORDER BY make';
// Now, assuming MySQL:
mysql_connect('localhost', 'boss', 'password');
mysql_select_db('cars');
$q = mysql_query($sql);
// For SQLite we would do:
$dbh = sqlite_open('/path/to/cars.ldb', 0666);
$q = sqlite_query($sql, $dbh);
// And for PostgreSQL:
pg_connect("host=localhost dbname=cars user=boss
password=password");
$q = pg_query($sql);
Now that we are using PDO, we can do the following:
// assume the $connStr variable holds a valid connection string
// as discussed in previous point
$sql = 'SELECT DISTINCT make FROM cars ORDER BY make';
$conn = new PDO($connStr, 'boss', 'password');
$q = $conn->query($sql);
As you can see, doing things the PDO way is not too different from traditional
methods of issuing queries. Also, here it should be underlined, that a call to
$conn->query() is returning another object of class PDOStatement, unlike the calls
to mysql_query(), sqlite_query(), and pg_query(), which return PHP variables
of the resource type.
Now, let's make our simplistic SQL query a bit more complicated so that it selects the
total value of all Fords on sale in our imaginary car lot. The query would then look
something like this:
SELECT sum(price) FROM cars WHERE make='Ford'
To make our example even more interesting, let's assume that the name of the car
manufacturer is held in a variable ($make) so that we must quote it, before passing it
to the database. Our non-PDO queries would now look like this:
$make = 'Ford';
// MySQL:
$m = mysql_real_escape_string($make);
$q = mysql_query("SELECT sum(price) FROM cars WHERE make='$m'");
// SQLite:
$m = sqlite_escape_string($make);
$q = sqlite_query("SELECT sum(price) FROM cars WHERE make='$m'",
$dbh);
// and PostgreSQL:
$m = pg_escape_string($make);
$q = pg_query("SELECT sum(price) FROM cars WHERE make='$m'");
The PDO class defi nes a single method for quoting strings so that they can be used
safely in queries. We will discuss security issues such as SQL injection, in Chapter 3.
This method does a neat thing; it will automatically add quotes around the value
if necessary:
$m = $conn->quote($make);
$q = $conn->query("SELECT sum(price) FROM cars WHERE make=$m");
Again, you can see that PDO allows you to use the same pattern as you would have
used before, but the names of all the methods are unifi ed.
Now that we have issued our query, we will want to see its results. As the query in
the last example will always return just one row, we will want more rows. Again,
the three databases will require us to call different functions on the $q variable that
was returned from one of the three calls to mysql_query(), sqlite_query(), or
pg_query(). So our code for getting all the cars will look similar to this:
// assume the query is in the $sql variable
$sql = "SELECT DISTINCT make FROM cars ORDER BY make";
// For MySQL:
$q = mysql_query($sql);
while($r = mysql_fetch_assoc($q))
{
echo $r['make'], "\n";
}
// For SQLite:
$q = sqlite_query($dbh, $sql);
while($r = sqlite_fetch_array($q, SQLITE_ASSOC))
{
echo $r['make'], "\n";
}
// and, finally, PostgreSQL:
$q = pg_query($sql);
while($r = pg_fetch_assoc($q))
{
echo $r['make'], "\n";
}
As you can see, the idea is the same, but we have to use different function names.
Also, note that SQLite requires an extra parameter if we want to get the rows in the
same way as with MySQL and PostgreSQL (of course, this could be omitted, but
then the returned rows would contain both column name indexed and numerically
indexed elements.)
As you may already have guessed, things are pretty straightforward when it comes
to PDO: We don't care what the underlying database is, and the methods for fetching
rows are the same across all databases. So, the above code could be rewritten for
PDO in the following way:
$q = $conn->query("SELECT DISTINCT make FROM cars ORDER BY make");
while($r = $q->fetch(PDO::FETCH_ASSOC))
{
echo $r['make'], "\n";
}
Nothing is different from what happens before. One thing to note here is that we
explicitly specifi ed the PDO::FETCH_ASSOC fetch style constant here, since PDO's
default behavior is to fetch the result rows as arrays indexed both by column
name and number. (This behavior is similar to mysql_fetch_array(),
sqlite_fetch_array() without the second parameter, or pg_fetch_array().)
We will discuss the fetch styles that PDO has to offer in Chapter 2.
Introduction PHP Data Objects
PHP Data Objects, (PDO) is a PHP5 extension that defi nes a lightweight DBMS
connection abstraction library (sometimes called data access abstraction library).
The need for a tool like PDO was dictated by the great number of database systems
supported by PHP. Each of these database systems required a separate extension
that defi ned its own API for performing the same tasks, starting from establishing a
connection to advanced features such as preparing statements and error handling.
The fact that these APIs were not unifi ed made transition between underlying
databases painful, often resulting in the rewriting of many lines of code, which in
turn, led to new programming errors that required time to track, debug and correct.
On the other hand, the absence of a unifi ed library, like JDBC for Java, was putting
PHP behind the big players in the programming languages world. Now that such
library exists, PHP is regaining its position and is a platform of choice for millions
of programmers.
It should be noted, however, that there exist several libraries written in PHP, that
serve the same purpose as PDO. The most popular are the ADOdb library and the
PEAR DB package. The key difference between them and PDO is speed. PDO is a
PHP extension written in a compiled language (C/C++), while the PHP libraries
are written in an interpreted language. Also, once PDO is enabled, it does not
require you to include source fi les in your scripts and redistribute them with your
application. This makes installing your applications easier, as the end user does not
need to take care of third-party software.
PDO being a PECL extension, itself relies on database-specifi c drivers and on other
PECL extensions. These drivers must also be installed in order to use PDO (you only
need the drivers for the databases you are using). Since the description of installation
of PDO and database-specifi c drivers is beyond the scope of this book, you can refer
to PHP manual at www.php.net/pdo for technical information regarding installation
and upgrade issues.
Using PDO
As it has been noted in the previous section, PDO is a connection, or data access
abstraction library. This means that PDO defi nes a unifi ed interface for creating and
maintaining database connections, issuing queries, quoting parameters, traversing
result sets, dealing with prepared statements, and error handling.
We will give a quick overview of these topics here and look at them in greater detail
in the following chapters.
Connecting to the Database
Let's consider the well-known MySQL connection scenario:
mysql_connect($host, $user, $password);
mysql_select_db($db);
Here, we establish a connection and then select the default database for the
connection. (We ignore the issue of possible errors.)
In SQLite, for example, we would write something like the following:
$dbh = sqlite_open($db, 0666);
Here again we ignore errors (we will cover more on this later). For completeness,
let's see how we would connect to a PostgreSQL:
pg_connect("host=$host dbname=$db user=$user password=$password");
As you can see, all three databases require quite different ways of opening a
connection. While this is not a problem now, but if you always use the same database
management system in case you need to migrate, you will have to rewrite
your scripts.
Now, let's see what PDO has to offer. As PDO is fully object-oriented, we will be
dealing with connection objects, and further interaction with the database will
involve calling various methods of these objects. The examples above implied the
need for something analogous to these connection objects—calls to mysql_connect
or pg_connect return link identifi ers and PHP variables of a special type: resource.
However, we didn't use connection objects then since these two database APIs
don't require us to explicitly use them if we only have one connection in our scripts.
However, SQLite always requires a link identifi er.
With PDO, we will always have to explicitly use the connection object, since there
is no other way of calling its methods. (Those unfamiliar with object-oriented
programming should refer to Appendix A).
Each of the three above connections could be established in the following manner:
// For MySQL:
$conn = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
// For SQLite:
$conn = new PDO("sqlite:$db");
// And for PostgreSQL:
$conn = new PDO("pgsql:host=$host dbname=$db", $user, $pass);
As you can see, the only part that is changing here is the fi rst argument passed to the
PDO constructor. For SQLite, which does not utilize username and password, the
second and third arguments can be skipped.
Connection Strings
As you have seen in previous example, PDO uses the so-called connection strings
(or Data Source Names, abbreviated to DSN) that allow the PDO constructor to select
proper driver and pass subsequent method calls to it. These connection strings or
DSNs are different for every database management system and are the only things
that you will have to change.
If you are designing a big application that will be able to work with different
databases, then this connection string (together with a connection username and
a password) can be defi ned in a confi guration fi le and later used in the following
manner (assuming your confi guration fi le is similar to php.ini)
$config = parse_ini_file($pathToConfigFile);
$conn = new PDO($config['db.conn'], $config['db.user'],
$config['db.pass']);
Your confi guration fi le might then look like this:
db.conn="mysql:host=localhost;dbname=test"
db.user="johns"
db.pass="mypassphrase"
We will cover connection strings in more detail in Chapter 2; here we gave a quick
example so that you can see how easy it is to connect to different database systems
with PDO.
connection abstraction library (sometimes called data access abstraction library).
The need for a tool like PDO was dictated by the great number of database systems
supported by PHP. Each of these database systems required a separate extension
that defi ned its own API for performing the same tasks, starting from establishing a
connection to advanced features such as preparing statements and error handling.
The fact that these APIs were not unifi ed made transition between underlying
databases painful, often resulting in the rewriting of many lines of code, which in
turn, led to new programming errors that required time to track, debug and correct.
On the other hand, the absence of a unifi ed library, like JDBC for Java, was putting
PHP behind the big players in the programming languages world. Now that such
library exists, PHP is regaining its position and is a platform of choice for millions
of programmers.
It should be noted, however, that there exist several libraries written in PHP, that
serve the same purpose as PDO. The most popular are the ADOdb library and the
PEAR DB package. The key difference between them and PDO is speed. PDO is a
PHP extension written in a compiled language (C/C++), while the PHP libraries
are written in an interpreted language. Also, once PDO is enabled, it does not
require you to include source fi les in your scripts and redistribute them with your
application. This makes installing your applications easier, as the end user does not
need to take care of third-party software.
PDO being a PECL extension, itself relies on database-specifi c drivers and on other
PECL extensions. These drivers must also be installed in order to use PDO (you only
need the drivers for the databases you are using). Since the description of installation
of PDO and database-specifi c drivers is beyond the scope of this book, you can refer
to PHP manual at www.php.net/pdo for technical information regarding installation
and upgrade issues.
Using PDO
As it has been noted in the previous section, PDO is a connection, or data access
abstraction library. This means that PDO defi nes a unifi ed interface for creating and
maintaining database connections, issuing queries, quoting parameters, traversing
result sets, dealing with prepared statements, and error handling.
We will give a quick overview of these topics here and look at them in greater detail
in the following chapters.
Connecting to the Database
Let's consider the well-known MySQL connection scenario:
mysql_connect($host, $user, $password);
mysql_select_db($db);
Here, we establish a connection and then select the default database for the
connection. (We ignore the issue of possible errors.)
In SQLite, for example, we would write something like the following:
$dbh = sqlite_open($db, 0666);
Here again we ignore errors (we will cover more on this later). For completeness,
let's see how we would connect to a PostgreSQL:
pg_connect("host=$host dbname=$db user=$user password=$password");
As you can see, all three databases require quite different ways of opening a
connection. While this is not a problem now, but if you always use the same database
management system in case you need to migrate, you will have to rewrite
your scripts.
Now, let's see what PDO has to offer. As PDO is fully object-oriented, we will be
dealing with connection objects, and further interaction with the database will
involve calling various methods of these objects. The examples above implied the
need for something analogous to these connection objects—calls to mysql_connect
or pg_connect return link identifi ers and PHP variables of a special type: resource.
However, we didn't use connection objects then since these two database APIs
don't require us to explicitly use them if we only have one connection in our scripts.
However, SQLite always requires a link identifi er.
With PDO, we will always have to explicitly use the connection object, since there
is no other way of calling its methods. (Those unfamiliar with object-oriented
programming should refer to Appendix A).
Each of the three above connections could be established in the following manner:
// For MySQL:
$conn = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
// For SQLite:
$conn = new PDO("sqlite:$db");
// And for PostgreSQL:
$conn = new PDO("pgsql:host=$host dbname=$db", $user, $pass);
As you can see, the only part that is changing here is the fi rst argument passed to the
PDO constructor. For SQLite, which does not utilize username and password, the
second and third arguments can be skipped.
Connection Strings
As you have seen in previous example, PDO uses the so-called connection strings
(or Data Source Names, abbreviated to DSN) that allow the PDO constructor to select
proper driver and pass subsequent method calls to it. These connection strings or
DSNs are different for every database management system and are the only things
that you will have to change.
If you are designing a big application that will be able to work with different
databases, then this connection string (together with a connection username and
a password) can be defi ned in a confi guration fi le and later used in the following
manner (assuming your confi guration fi le is similar to php.ini)
$config = parse_ini_file($pathToConfigFile);
$conn = new PDO($config['db.conn'], $config['db.user'],
$config['db.pass']);
Your confi guration fi le might then look like this:
db.conn="mysql:host=localhost;dbname=test"
db.user="johns"
db.pass="mypassphrase"
We will cover connection strings in more detail in Chapter 2; here we gave a quick
example so that you can see how easy it is to connect to different database systems
with PDO.
The Decision Control Structure in C language-6
The ! Operator
So far we have used only the logical operators && and ||. The third logical operator is the NOT operator, written as !. This operator reverses the result of the expression it operates on. For example, if the expression evaluates to a non-zero value, then applying ! operator to it results into a 0. Vice versa, if the expression evaluates to zero then on applying ! operator to it makes it 1, a non-zero value. The final result (after applying !) 0 or 1 is considered to be false or true respectively. Here is an example of the NOT operator applied to a relational expression.
! ( y < 10 )
This means “not y less than 10”. In other words, if y is less than 10, the expression will be false, since ( y < 10 ) is true. We can express the same condition as ( y >= 10 ).
The NOT operator is often used to reverse the logical value of a single variable, as in the expression
if ( ! flag )
This is another way of saying
if ( flag == 0 )
Does the NOT operator sound confusing? Avoid it if you want, as the same thing can be achieved without using the NOT operator.
Hierarchy of Operators Revisited
Since we have now added the logical operators to the list of operators we know, it is time to review these operators and their priorities. Figure 2.7 summarizes the operators we have seen so far. The higher the position of an operator is in the table, higher is its priority. (A full-fledged precedence table of operators is given in Appendix A.)
Operators
Type
!
Logical NOT
* / %
Arithmetic and modulus
+ -
Arithmetic
< > <= >=
Relational
== !=
Relational
&&
Logical AND
||
Logical OR
=
Assignment
Figure 2.7
A Word of Caution
What will be the output of the following program:
main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;
if ( i = 5 )
printf ( "You entered 5" ) ;
else
printf ( "You entered something other than 5" ) ;
}
And here is the output of two runs of this program...
Enter value of i 200
You entered 5
Enter value of i 9999
You entered 5
Surprising? You have entered 200 and 9999, and still you find in either case the output is ‘You entered 5’. This is because we have written the condition wrongly. We have used the assignment operator = instead of the relational operator ==. As a result, the condition gets reduced to if ( 5 ), irrespective of what you supply as the value of i. And remember that in C ‘truth’ is always non-zero, whereas ‘falsity’ is always zero. Therefore, if ( 5 ) always evaluates to true and hence the result.
Another common mistake while using the if statement is to write a semicolon (;) after the condition, as shown below:
main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;
if ( i == 5 ) ;
printf ( "You entered 5" ) ;
}
The ; makes the compiler to interpret the statement as if you have written it in following manner:
if ( i == 5 )
;
printf ( "You entered 5" ) ;
Here, if the condition evaluates to true the ; (null statement, which does nothing on execution) gets executed, following which the printf( ) gets executed. If the condition fails then straightaway the printf( ) gets executed. Thus, irrespective of whether the condition evaluates to true or false the printf( ) is bound to get executed. Remember that the compiler would not point out this as an error, since as far as the syntax is concerned nothing has gone wrong, but the logic has certainly gone awry. Moral is, beware of such pitfalls.
The following figure summarizes the working of all the three logical operators.
Operands
So far we have used only the logical operators && and ||. The third logical operator is the NOT operator, written as !. This operator reverses the result of the expression it operates on. For example, if the expression evaluates to a non-zero value, then applying ! operator to it results into a 0. Vice versa, if the expression evaluates to zero then on applying ! operator to it makes it 1, a non-zero value. The final result (after applying !) 0 or 1 is considered to be false or true respectively. Here is an example of the NOT operator applied to a relational expression.
! ( y < 10 )
This means “not y less than 10”. In other words, if y is less than 10, the expression will be false, since ( y < 10 ) is true. We can express the same condition as ( y >= 10 ).
The NOT operator is often used to reverse the logical value of a single variable, as in the expression
if ( ! flag )
This is another way of saying
if ( flag == 0 )
Does the NOT operator sound confusing? Avoid it if you want, as the same thing can be achieved without using the NOT operator.
Hierarchy of Operators Revisited
Since we have now added the logical operators to the list of operators we know, it is time to review these operators and their priorities. Figure 2.7 summarizes the operators we have seen so far. The higher the position of an operator is in the table, higher is its priority. (A full-fledged precedence table of operators is given in Appendix A.)
Operators
Type
!
Logical NOT
* / %
Arithmetic and modulus
+ -
Arithmetic
< > <= >=
Relational
== !=
Relational
&&
Logical AND
||
Logical OR
=
Assignment
Figure 2.7
A Word of Caution
What will be the output of the following program:
main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;
if ( i = 5 )
printf ( "You entered 5" ) ;
else
printf ( "You entered something other than 5" ) ;
}
And here is the output of two runs of this program...
Enter value of i 200
You entered 5
Enter value of i 9999
You entered 5
Surprising? You have entered 200 and 9999, and still you find in either case the output is ‘You entered 5’. This is because we have written the condition wrongly. We have used the assignment operator = instead of the relational operator ==. As a result, the condition gets reduced to if ( 5 ), irrespective of what you supply as the value of i. And remember that in C ‘truth’ is always non-zero, whereas ‘falsity’ is always zero. Therefore, if ( 5 ) always evaluates to true and hence the result.
Another common mistake while using the if statement is to write a semicolon (;) after the condition, as shown below:
main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;
if ( i == 5 ) ;
printf ( "You entered 5" ) ;
}
The ; makes the compiler to interpret the statement as if you have written it in following manner:
if ( i == 5 )
;
printf ( "You entered 5" ) ;
Here, if the condition evaluates to true the ; (null statement, which does nothing on execution) gets executed, following which the printf( ) gets executed. If the condition fails then straightaway the printf( ) gets executed. Thus, irrespective of whether the condition evaluates to true or false the printf( ) is bound to get executed. Remember that the compiler would not point out this as an error, since as far as the syntax is concerned nothing has gone wrong, but the logic has certainly gone awry. Moral is, beware of such pitfalls.
The following figure summarizes the working of all the three logical operators.
Operands
The Decision Control Structure in C language-5
The else if Clause
There is one more way in which we can write program for Example 2.4. This involves usage of else if blocks as shown below:
/* else if ladder demo */
main( )
{
int m1, m2, m3, m4, m5, per ;
per = ( m1+ m2 + m3 + m4+ m5 ) / per ;
if ( per >= 60 )
printf ( "First division" ) ;
else if ( per >= 50 )
printf ( "Second division" ) ;
else if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "fail" ) ;
}
You can note that this program reduces the indentation of the statements. In this case every else is associated with its previous if. The last else goes to work only if all the conditions fail. Even in else if ladder the last else is optional.
Note that the else if clause is nothing different. It is just a way of rearranging the else with the if that follows it. This would be evident if you look at the following code:
if ( i == 2 ) if ( i == 2 )
printf ( "With you…" ) ; printf ( "With you…" ) ;
else elseif(j==2)
{ printf("…Allthetime");
if ( j == 2 )
printf ( "…All the time" ) ;
}
Another place where logical operators are useful is when we want to write programs for complicated logics that ultimately boil down
to only two answers. For example, consider the following example:
Example 2.5: A company insures its drivers in the following cases:
− If the driver is married.
− If the driver is unmarried, male & above 30 years of age.
− If the driver is unmarried, female & above 25 years of age.
In all other cases the driver is not insured. If the marital status, sex and age of the driver are the inputs, write a program to determine whether the driver is to be insured or not.
Here after checking a complicated set of instructions the final output of the program would be one of the two—Either the driver should be ensured or the driver should not be ensured. As mentioned above, since these are the only two outcomes this problem can be solved using logical operators. But before we do that let us write a program that does not make use of logical operators.
/* Insurance of driver - without using logical operators */
main( )
{
char sex, ms ;
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c", &age, &sex, &ms ) ;
if ( ms == 'M' )
printf ( "Driver is insured" ) ;
else
{
if ( sex == 'M' )
{
if ( age > 30 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
else
{
if ( age > 25 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
}
}
From the program it is evident that we are required to match several ifs and elses and several pairs of braces. In a more real-life situation there would be more conditions to check leading to the program creeping to the right. Let us now see how to avoid these problems by using logical operators.
As mentioned above, in this example we expect the answer to be either ‘Driver is insured’ or ‘Driver is not insured’. If we list down all those cases in which the driver is insured, then they would be:
(a)
(b)
(c)
Driver is married.
Driver is an unmarried male above 30 years of age.
Driver is an unmarried female above 25 years of age.
Since all these cases lead to the driver being insured, they can be combined together using && and || as shown in the program below:
/* Insurance of driver - using logical operators */
main( )
{
char sex, ms ;
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c" &age, &sex, &ms ) ;
if ( ( ms == 'M') || ( ms == 'U' && sex == 'M' && age > 30 ) ||
( ms == 'U' && sex == 'F' && age > 25 ) )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
In this program it is important to note that:
− The driver will be insured only if one of the conditions enclosed in parentheses evaluates to true.
− For the second pair of parentheses to evaluate to true, each condition in the parentheses separated by && must evaluate to true.
− Even if one of the conditions in the second parentheses evaluates to false, then the whole of the second parentheses evaluates to false.
− The last two of the above arguments apply to third pair of parentheses as well.
Thus we can conclude that the && and || are useful in the following programming situations:
(a)
(b)
When it is to be tested whether a value falls within a particular range or not.
When after testing several conditions the outcome is only one of the two answers (This problem is often called yes/no problem).
There can be one more situation other than checking ranges or yes/no problem where you might find logical operators useful. The following program demonstrates it.
Example 2.6: Write a program to calculate the salary as per the following table:
Gender
Years of Service
Qualifications
Salary
Male
>= 10
Post-Graduate
15000
>= 10
Graduate
10000
< 10
Post-Graduate
10000
< 10
Graduate
7000
Female
>= 10
Post-Graduate
12000
>= 10
Graduate
9000
< 10
Post-Graduate
10000
< 10
Graduate
6000
Figure 2.6
main( )
{
char g ;
int yos, qual, sal ;
printf ( "Enter Gender, Years of Service and
Qualifications ( 0 = G, 1 = PG ):" ) ;
scanf ( "%c%d%d", &g, &yos, &qual ) ;
if ( g == 'm' && yos >= 10 && qual == 1 )
sal = 15000 ;
else if ( ( g == 'm' && yos >= 10 && qual == 0 ) ||
( g == 'm' && yos < 10 && qual == 1 ) )
sal = 10000 ;
else if ( g == 'm' && yos < 10 && qual == 0 )
sal = 7000 ;
else if ( g == 'f' && yos >= 10 && qual == 1 )
sal = 12000 ;
else if ( g == 'f' && yos >= 10 && qual == 0 )
sal = 9000 ;
else if ( g == 'f' && yos < 10 && qual == 1 )
sal = 10000 ;
else if ( g == 'f' && yos < 10 && qual == 0 )
sal = 6000 ;
printf ( "\nSalary of Employee = %d", sal ) ;
}
There is one more way in which we can write program for Example 2.4. This involves usage of else if blocks as shown below:
/* else if ladder demo */
main( )
{
int m1, m2, m3, m4, m5, per ;
per = ( m1+ m2 + m3 + m4+ m5 ) / per ;
if ( per >= 60 )
printf ( "First division" ) ;
else if ( per >= 50 )
printf ( "Second division" ) ;
else if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "fail" ) ;
}
You can note that this program reduces the indentation of the statements. In this case every else is associated with its previous if. The last else goes to work only if all the conditions fail. Even in else if ladder the last else is optional.
Note that the else if clause is nothing different. It is just a way of rearranging the else with the if that follows it. This would be evident if you look at the following code:
if ( i == 2 ) if ( i == 2 )
printf ( "With you…" ) ; printf ( "With you…" ) ;
else elseif(j==2)
{ printf("…Allthetime");
if ( j == 2 )
printf ( "…All the time" ) ;
}
Another place where logical operators are useful is when we want to write programs for complicated logics that ultimately boil down
to only two answers. For example, consider the following example:
Example 2.5: A company insures its drivers in the following cases:
− If the driver is married.
− If the driver is unmarried, male & above 30 years of age.
− If the driver is unmarried, female & above 25 years of age.
In all other cases the driver is not insured. If the marital status, sex and age of the driver are the inputs, write a program to determine whether the driver is to be insured or not.
Here after checking a complicated set of instructions the final output of the program would be one of the two—Either the driver should be ensured or the driver should not be ensured. As mentioned above, since these are the only two outcomes this problem can be solved using logical operators. But before we do that let us write a program that does not make use of logical operators.
/* Insurance of driver - without using logical operators */
main( )
{
char sex, ms ;
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c", &age, &sex, &ms ) ;
if ( ms == 'M' )
printf ( "Driver is insured" ) ;
else
{
if ( sex == 'M' )
{
if ( age > 30 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
else
{
if ( age > 25 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
}
}
From the program it is evident that we are required to match several ifs and elses and several pairs of braces. In a more real-life situation there would be more conditions to check leading to the program creeping to the right. Let us now see how to avoid these problems by using logical operators.
As mentioned above, in this example we expect the answer to be either ‘Driver is insured’ or ‘Driver is not insured’. If we list down all those cases in which the driver is insured, then they would be:
(a)
(b)
(c)
Driver is married.
Driver is an unmarried male above 30 years of age.
Driver is an unmarried female above 25 years of age.
Since all these cases lead to the driver being insured, they can be combined together using && and || as shown in the program below:
/* Insurance of driver - using logical operators */
main( )
{
char sex, ms ;
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c" &age, &sex, &ms ) ;
if ( ( ms == 'M') || ( ms == 'U' && sex == 'M' && age > 30 ) ||
( ms == 'U' && sex == 'F' && age > 25 ) )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
In this program it is important to note that:
− The driver will be insured only if one of the conditions enclosed in parentheses evaluates to true.
− For the second pair of parentheses to evaluate to true, each condition in the parentheses separated by && must evaluate to true.
− Even if one of the conditions in the second parentheses evaluates to false, then the whole of the second parentheses evaluates to false.
− The last two of the above arguments apply to third pair of parentheses as well.
Thus we can conclude that the && and || are useful in the following programming situations:
(a)
(b)
When it is to be tested whether a value falls within a particular range or not.
When after testing several conditions the outcome is only one of the two answers (This problem is often called yes/no problem).
There can be one more situation other than checking ranges or yes/no problem where you might find logical operators useful. The following program demonstrates it.
Example 2.6: Write a program to calculate the salary as per the following table:
Gender
Years of Service
Qualifications
Salary
Male
>= 10
Post-Graduate
15000
>= 10
Graduate
10000
< 10
Post-Graduate
10000
< 10
Graduate
7000
Female
>= 10
Post-Graduate
12000
>= 10
Graduate
9000
< 10
Post-Graduate
10000
< 10
Graduate
6000
Figure 2.6
main( )
{
char g ;
int yos, qual, sal ;
printf ( "Enter Gender, Years of Service and
Qualifications ( 0 = G, 1 = PG ):" ) ;
scanf ( "%c%d%d", &g, &yos, &qual ) ;
if ( g == 'm' && yos >= 10 && qual == 1 )
sal = 15000 ;
else if ( ( g == 'm' && yos >= 10 && qual == 0 ) ||
( g == 'm' && yos < 10 && qual == 1 ) )
sal = 10000 ;
else if ( g == 'm' && yos < 10 && qual == 0 )
sal = 7000 ;
else if ( g == 'f' && yos >= 10 && qual == 1 )
sal = 12000 ;
else if ( g == 'f' && yos >= 10 && qual == 0 )
sal = 9000 ;
else if ( g == 'f' && yos < 10 && qual == 1 )
sal = 10000 ;
else if ( g == 'f' && yos < 10 && qual == 0 )
sal = 6000 ;
printf ( "\nSalary of Employee = %d", sal ) ;
}
The Decision Control Structure in C language-4
Use of Logical Operators
C allows usage of three logical operators, namely, &&, || and !. These are to be read as ‘AND’ ‘OR’ and ‘NOT’ respectively.
There are several things to note about these logical operators. Most obviously, two of them are composed of double symbols: || and &&. Don’t use the single symbol | and &. These single symbols also have a meaning. They are bitwise operators, which we would examine in Chapter 14.
The first two operators, && and ||, allow two or more conditions to be combined in an if statement. Let us see how they are used in a program. Consider the following example.
Example 2.4: The marks obtained by a student in 5 different subjects are input through the keyboard. The student gets a division as per the following rules:
Percentage above or equal to 60 - First division
Percentage between 50 and 59 - Second division
Percentage between 40 and 49 - Third division
Percentage less than 40 - Fail
Write a program to calculate the division obtained by the student.
There are two ways in which we can write a program for this example. These methods are given below.
/* Method – I */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;
if ( per >= 60 )
printf ( "First division ") ;
else
{
if ( per >= 50 )
printf ( "Second division" ) ;
else
{
if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "Fail" ) ;
}
}
}
This is a straight forward program. Observe that the program uses nested if-elses. This leads to three disadvantages:
(a)
(b)
(c)
As the number of conditions go on increasing the level of indentation also goes on increasing. As a result the whole program creeps to the right.
Care needs to be exercised to match the corresponding ifs and elses.
Care needs to be exercised to match the corresponding pair of braces.
All these three problems can be eliminated by usage of ‘Logical operators’. The following program illustrates this.
/* Method – II */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;
if ( per >= 60 )
printf ( "First division" ) ;
if ( ( per >= 50 ) && ( per < 60 ) )
printf ( "Second division" ) ;
if ( ( per >= 40 ) && ( per < 50 ) )
printf ( "Third division" ) ;
if ( per < 40 )
printf ( "Fail" ) ;
}
As can be seen from the second if statement, the && operator is used to combine two conditions. ‘Second division’ gets printed if both the conditions evaluate to true. If one of the conditions evaluate to false then the whole thing is treated as false.
Two distinct advantages can be cited in favour of this program:
(a)
(b)
The matching (or do I say mismatching) of the ifs with their corresponding elses gets avoided, since there are no elses in this program.
In spite of using several conditions, the program doesn't creep to the right. In the previous program the statements went on creeping to the right. This effect becomes more pronounced as the number of conditions go on increasing. This would make the task of matching the ifs with their corresponding elses and matching of opening and closing braces that much more difficult.
C allows usage of three logical operators, namely, &&, || and !. These are to be read as ‘AND’ ‘OR’ and ‘NOT’ respectively.
There are several things to note about these logical operators. Most obviously, two of them are composed of double symbols: || and &&. Don’t use the single symbol | and &. These single symbols also have a meaning. They are bitwise operators, which we would examine in Chapter 14.
The first two operators, && and ||, allow two or more conditions to be combined in an if statement. Let us see how they are used in a program. Consider the following example.
Example 2.4: The marks obtained by a student in 5 different subjects are input through the keyboard. The student gets a division as per the following rules:
Percentage above or equal to 60 - First division
Percentage between 50 and 59 - Second division
Percentage between 40 and 49 - Third division
Percentage less than 40 - Fail
Write a program to calculate the division obtained by the student.
There are two ways in which we can write a program for this example. These methods are given below.
/* Method – I */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;
if ( per >= 60 )
printf ( "First division ") ;
else
{
if ( per >= 50 )
printf ( "Second division" ) ;
else
{
if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "Fail" ) ;
}
}
}
This is a straight forward program. Observe that the program uses nested if-elses. This leads to three disadvantages:
(a)
(b)
(c)
As the number of conditions go on increasing the level of indentation also goes on increasing. As a result the whole program creeps to the right.
Care needs to be exercised to match the corresponding ifs and elses.
Care needs to be exercised to match the corresponding pair of braces.
All these three problems can be eliminated by usage of ‘Logical operators’. The following program illustrates this.
/* Method – II */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;
if ( per >= 60 )
printf ( "First division" ) ;
if ( ( per >= 50 ) && ( per < 60 ) )
printf ( "Second division" ) ;
if ( ( per >= 40 ) && ( per < 50 ) )
printf ( "Third division" ) ;
if ( per < 40 )
printf ( "Fail" ) ;
}
As can be seen from the second if statement, the && operator is used to combine two conditions. ‘Second division’ gets printed if both the conditions evaluate to true. If one of the conditions evaluate to false then the whole thing is treated as false.
Two distinct advantages can be cited in favour of this program:
(a)
(b)
The matching (or do I say mismatching) of the ifs with their corresponding elses gets avoided, since there are no elses in this program.
In spite of using several conditions, the program doesn't creep to the right. In the previous program the statements went on creeping to the right. This effect becomes more pronounced as the number of conditions go on increasing. This would make the task of matching the ifs with their corresponding elses and matching of opening and closing braces that much more difficult.
The Decision Control Structure in C language-3
Nested if-elses
It is perfectly all right if we write an entire if-else construct within either the body of the if statement or the body of an else statement. This is called ‘nesting’of ifs. This is shown in the following program.
/* A quick demo of nested if-else */
main( )
{
int i ;
printf ( "Enter either 1 or 2 " ) ;
scanf ( "%d", &i ) ;
if ( i == 1 )
printf ( "You would go to heaven !" ) ;
else
{
if ( i == 2 )
printf ( "Hell was created with you in mind" ) ;
else
printf ( "How about mother earth !" ) ;
}
}
Note that the second if-else construct is nested in the first else statement. If the condition in the first if statement is false, then the condition in the second if statement is checked. If it is false as well, then the final else statement is executed.
You can see in the program how each time a if-else construct is nested within another if-else construct, it is also indented to add clarity to the program. Inculcate this habit of indentation, otherwise you would end up writing programs which nobody (you included) can understand easily at a later date.
In the above program an if-else occurs within the else block of the first if statement. Similarly, in some other program an if-else may occur in the if block as well. There is no limit on how deeply the ifs and the elses can be nested.
Forms of if
The if statement can take any of the following forms:
(a) if ( condition )
do this ;
(b) if ( condition )
{
do this ;
and this ;
}
(c) if ( condition )
do this ;
else
do this ;
(d) if ( condition )
{
do this ;
and this ;
}
else
{
do this ;
and this ;
}
(e) if ( condition )
do this ;
else
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
(f) if ( condition )
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
else
do this ;
It is perfectly all right if we write an entire if-else construct within either the body of the if statement or the body of an else statement. This is called ‘nesting’of ifs. This is shown in the following program.
/* A quick demo of nested if-else */
main( )
{
int i ;
printf ( "Enter either 1 or 2 " ) ;
scanf ( "%d", &i ) ;
if ( i == 1 )
printf ( "You would go to heaven !" ) ;
else
{
if ( i == 2 )
printf ( "Hell was created with you in mind" ) ;
else
printf ( "How about mother earth !" ) ;
}
}
Note that the second if-else construct is nested in the first else statement. If the condition in the first if statement is false, then the condition in the second if statement is checked. If it is false as well, then the final else statement is executed.
You can see in the program how each time a if-else construct is nested within another if-else construct, it is also indented to add clarity to the program. Inculcate this habit of indentation, otherwise you would end up writing programs which nobody (you included) can understand easily at a later date.
In the above program an if-else occurs within the else block of the first if statement. Similarly, in some other program an if-else may occur in the if block as well. There is no limit on how deeply the ifs and the elses can be nested.
Forms of if
The if statement can take any of the following forms:
(a) if ( condition )
do this ;
(b) if ( condition )
{
do this ;
and this ;
}
(c) if ( condition )
do this ;
else
do this ;
(d) if ( condition )
{
do this ;
and this ;
}
else
{
do this ;
and this ;
}
(e) if ( condition )
do this ;
else
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
(f) if ( condition )
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
else
do this ;
The Decision Control Structure in C language-2
Multiple Statements within if
It may so happen that in a program we want more than one statement to be executed if the expression following if is satisfied. If such multiple statements are to be executed then they must be placed within a pair of braces as illustrated in the following example.
Example 2.2: The current year and the year in which the employee joined the organization are entered through the keyboard. If the number of years for which the employee has served the organization is greater than 3 then a bonus of Rs. 2500/- is given to the employee. If the years of service are not greater than 3, then the program should do nothing.
/* Calculation of bonus */
main( )
{
int bonus, cy, yoj, yr_of_ser ;
printf ( "Enter current year and year of joining " ) ;
scanf ( "%d %d", &cy, &yoj ) ;
yr_of_ser = cy - yoj ;
if ( yr_of_ser > 3 )
{
bonus = 2500 ;
printf ( "Bonus = Rs. %d", bonus ) ;
}
}
Observe that here the two statements to be executed on satisfaction of the condition have been enclosed within a pair of braces. If a pair of braces is not used then the C compiler assumes that the programmer wants only the immediately next statement after the if to be executed on satisfaction of the condition. In other words we can say that the default scope of the if statement is the immediately next statement after it.
The if-else Statement
The if statement by itself will execute a single statement, or a group of statements, when the expression following if evaluates to true. It does nothing when the expression evaluates to false. Can we execute one group of statements if the expression evaluates to true and another group of statements if the expression evaluates to false? Of course! This is what is the purpose of the else statement that is demonstrated in the following example:
Example 2.3: In a company an employee is paid as under:
If his basic salary is less than Rs. 1500, then HRA = 10% of basic salary and DA = 90% of basic salary. If his salary is either equal to or above Rs. 1500, then HRA = Rs. 500 and DA = 98% of basic salary. If the employee's salary is input through the keyboard write a program to find his gross salary.
/* Calculation of gross salary */
main( )
{
float bs, gs, da, hra ;
printf ( "Enter basic salary " ) ;
scanf ( "%f", &bs ) ;
if ( bs < 1500 )
{
hra = bs * 10 / 100 ;
da = bs * 90 / 100 ;
}
else
{
hra = 500 ;
da = bs * 98 / 100 ;
}
gs = bs + hra + da ;
printf ( "gross salary = Rs. %f", gs ) ;
}
A few points worth noting...
The group of statements after the if upto and not including the else is called an ‘if block’. Similarly, the statements after the else form the ‘else block’.
Notice that the else is written exactly below the if. The statements in the if block and those in the else block have been indented to the right. This formatting convention isfollowed throughout the book to enable you to understand the working of the program better.
Had there been only one statement to be executed in the if block and only one statement in the else block we could have dropped the pair of braces.
As with the if statement, the default scope of else is also the statement immediately after the else. To override this default scope a pair of braces as shown in the above example must be used.
It may so happen that in a program we want more than one statement to be executed if the expression following if is satisfied. If such multiple statements are to be executed then they must be placed within a pair of braces as illustrated in the following example.
Example 2.2: The current year and the year in which the employee joined the organization are entered through the keyboard. If the number of years for which the employee has served the organization is greater than 3 then a bonus of Rs. 2500/- is given to the employee. If the years of service are not greater than 3, then the program should do nothing.
/* Calculation of bonus */
main( )
{
int bonus, cy, yoj, yr_of_ser ;
printf ( "Enter current year and year of joining " ) ;
scanf ( "%d %d", &cy, &yoj ) ;
yr_of_ser = cy - yoj ;
if ( yr_of_ser > 3 )
{
bonus = 2500 ;
printf ( "Bonus = Rs. %d", bonus ) ;
}
}
Observe that here the two statements to be executed on satisfaction of the condition have been enclosed within a pair of braces. If a pair of braces is not used then the C compiler assumes that the programmer wants only the immediately next statement after the if to be executed on satisfaction of the condition. In other words we can say that the default scope of the if statement is the immediately next statement after it.
The if-else Statement
The if statement by itself will execute a single statement, or a group of statements, when the expression following if evaluates to true. It does nothing when the expression evaluates to false. Can we execute one group of statements if the expression evaluates to true and another group of statements if the expression evaluates to false? Of course! This is what is the purpose of the else statement that is demonstrated in the following example:
Example 2.3: In a company an employee is paid as under:
If his basic salary is less than Rs. 1500, then HRA = 10% of basic salary and DA = 90% of basic salary. If his salary is either equal to or above Rs. 1500, then HRA = Rs. 500 and DA = 98% of basic salary. If the employee's salary is input through the keyboard write a program to find his gross salary.
/* Calculation of gross salary */
main( )
{
float bs, gs, da, hra ;
printf ( "Enter basic salary " ) ;
scanf ( "%f", &bs ) ;
if ( bs < 1500 )
{
hra = bs * 10 / 100 ;
da = bs * 90 / 100 ;
}
else
{
hra = 500 ;
da = bs * 98 / 100 ;
}
gs = bs + hra + da ;
printf ( "gross salary = Rs. %f", gs ) ;
}
A few points worth noting...
The group of statements after the if upto and not including the else is called an ‘if block’. Similarly, the statements after the else form the ‘else block’.
Notice that the else is written exactly below the if. The statements in the if block and those in the else block have been indented to the right. This formatting convention isfollowed throughout the book to enable you to understand the working of the program better.
Had there been only one statement to be executed in the if block and only one statement in the else block we could have dropped the pair of braces.
As with the if statement, the default scope of else is also the statement immediately after the else. To override this default scope a pair of braces as shown in the above example must be used.
The Decision Control Structure in C language-1
The if Statement
Like most languages, C uses the keyword if to implement the decision control instruction. The general form of if statement looks like this:
if ( this condition is true )
execute this statement ;
The keyword if tells the compiler that what follows is a decision control instruction. The condition following the keyword if is always enclosed within a pair of parentheses. If the condition, whatever it is, is true, then the statement is executed. If the condition is not true then the statement is not executed; instead the program skips past it. But how do we express the condition itself in C? And how do we evaluate its truth or falsity? As a general rule, we express a condition using C’s ‘relational’ operators. The relational operators allow us to compare two values to see whether they are equal to each other, unequal, or whether one is greater than the other. Here’s how they look and how they are evaluated in C.
this expression
is true if
x == y x is equal to y
x != y x is not equal to y
x < y x is less than y
x > y x is greater than y
x <= y x is less than or equal to y
x >= y x is greater than or equal to y
The relational operators should be familiar to you except for the equality operator == and the inequality operator !=. Note that = is used for assignment, whereas, == is used for comparison of two quantities. Here is a simple program, which demonstrates the use of if and the relational operators.
/* Demonstration of if statement */
main( )
{
int num ;
printf ( "Enter a number less than 10 " ) ;
scanf ( "%d", &num ) ;
if ( num <= 10 )
printf ( "What an obedient servant you are !" ) ;
}
On execution of this program, if you type a number less than or equal to 10, you get a message on the screen through printf( ). If you type some other number the program doesn’t do anything. The following flowchart would help you understand the flow of control in the program.
Figure 2.2
To make you comfortable with the decision control instruction one more example has been given below. Study it carefully before reading further. To help you understand it easily, the program is accompanied by an appropriate flowchart.
Example 2.1: While purchasing certain items, a discount of 10% is offered if the quantity purchased is more than 1000. If quantity and price per item are input through the keyboard, write a program to calculate the total expenses.
/* Calculation of total expenses */
main( )
{
int qty, dis = 0 ;
float rate, tot ;
printf ( "Enter quantity and rate " ) ;
scanf ( "%d %f", &qty, &rate) ;
if ( qty > 1000 )
dis = 10 ;
tot = ( qty * rate ) - ( qty * rate * dis / 100 ) ;
printf ( "Total expenses = Rs. %f", tot ) ;
}
Here is some sample interaction with the program.
Enter quantity and rate 1200 15.50
Total expenses = Rs. 16740.000000
Enter quantity and rate 200 15.50
Total expenses = Rs. 3100.000000
In the first run of the program, the condition evaluates to true, as 1200 (value of qty) is greater than 1000. Therefore, the variable dis, which was earlier set to 0, now gets a new value 10. Using this new value total expenses are calculated and printed.
In the second run the condition evaluates to false, as 200 (the value of qty) isn’t greater than 1000. Thus, dis, which is earlier set to 0, remains 0, and hence the expression after the minus sign evaluates to zero, thereby offering no discount.
Is the statement dis = 0 necessary? The answer is yes, since in C, a variable if not specifically initialized contains some unpredictable value (garbage value).
The Real Thing
We mentioned earlier that the general form of the if statement is as follows
if ( condition )
statement ;
Truly speaking the general form is as follows:
if ( expression )
statement ;
Here the expression can be any valid expression including a relational expression. We can even use arithmetic expressions in the if statement. For example all the following if statements are valid
if ( 3 + 2 % 5 )
printf ( "This works" ) ;
if ( a = 10 )
printf ( "Even this works" ) ;
if ( -5 )
printf ( "Surprisingly even this works" ) ;
Note that in C a non-zero value is considered to be true, whereas a 0 is considered to be false. In the first if, the expression evaluates to 5 and since 5 is non-zero it is considered to be true. Hence the printf( ) gets executed.
In the second if, 10 gets assigned to a so the if is now reduced to if ( a ) or if ( 10 ). Since 10 is non-zero, it is true hence again printf( ) goes to work.
In the third if, -5 is a non-zero number, hence true. So again printf( ) goes to work. In place of -5 even if a float like 3.14 were used it would be considered to be true. So the issue is not whether the number is integer or float, or whether it is positive or negative. Issue is whether it is zero or non-zero.
Like most languages, C uses the keyword if to implement the decision control instruction. The general form of if statement looks like this:
if ( this condition is true )
execute this statement ;
The keyword if tells the compiler that what follows is a decision control instruction. The condition following the keyword if is always enclosed within a pair of parentheses. If the condition, whatever it is, is true, then the statement is executed. If the condition is not true then the statement is not executed; instead the program skips past it. But how do we express the condition itself in C? And how do we evaluate its truth or falsity? As a general rule, we express a condition using C’s ‘relational’ operators. The relational operators allow us to compare two values to see whether they are equal to each other, unequal, or whether one is greater than the other. Here’s how they look and how they are evaluated in C.
this expression
is true if
x == y x is equal to y
x != y x is not equal to y
x < y x is less than y
x > y x is greater than y
x <= y x is less than or equal to y
x >= y x is greater than or equal to y
The relational operators should be familiar to you except for the equality operator == and the inequality operator !=. Note that = is used for assignment, whereas, == is used for comparison of two quantities. Here is a simple program, which demonstrates the use of if and the relational operators.
/* Demonstration of if statement */
main( )
{
int num ;
printf ( "Enter a number less than 10 " ) ;
scanf ( "%d", &num ) ;
if ( num <= 10 )
printf ( "What an obedient servant you are !" ) ;
}
On execution of this program, if you type a number less than or equal to 10, you get a message on the screen through printf( ). If you type some other number the program doesn’t do anything. The following flowchart would help you understand the flow of control in the program.
Figure 2.2
To make you comfortable with the decision control instruction one more example has been given below. Study it carefully before reading further. To help you understand it easily, the program is accompanied by an appropriate flowchart.
Example 2.1: While purchasing certain items, a discount of 10% is offered if the quantity purchased is more than 1000. If quantity and price per item are input through the keyboard, write a program to calculate the total expenses.
/* Calculation of total expenses */
main( )
{
int qty, dis = 0 ;
float rate, tot ;
printf ( "Enter quantity and rate " ) ;
scanf ( "%d %f", &qty, &rate) ;
if ( qty > 1000 )
dis = 10 ;
tot = ( qty * rate ) - ( qty * rate * dis / 100 ) ;
printf ( "Total expenses = Rs. %f", tot ) ;
}
Here is some sample interaction with the program.
Enter quantity and rate 1200 15.50
Total expenses = Rs. 16740.000000
Enter quantity and rate 200 15.50
Total expenses = Rs. 3100.000000
In the first run of the program, the condition evaluates to true, as 1200 (value of qty) is greater than 1000. Therefore, the variable dis, which was earlier set to 0, now gets a new value 10. Using this new value total expenses are calculated and printed.
In the second run the condition evaluates to false, as 200 (the value of qty) isn’t greater than 1000. Thus, dis, which is earlier set to 0, remains 0, and hence the expression after the minus sign evaluates to zero, thereby offering no discount.
Is the statement dis = 0 necessary? The answer is yes, since in C, a variable if not specifically initialized contains some unpredictable value (garbage value).
The Real Thing
We mentioned earlier that the general form of the if statement is as follows
if ( condition )
statement ;
Truly speaking the general form is as follows:
if ( expression )
statement ;
Here the expression can be any valid expression including a relational expression. We can even use arithmetic expressions in the if statement. For example all the following if statements are valid
if ( 3 + 2 % 5 )
printf ( "This works" ) ;
if ( a = 10 )
printf ( "Even this works" ) ;
if ( -5 )
printf ( "Surprisingly even this works" ) ;
Note that in C a non-zero value is considered to be true, whereas a 0 is considered to be false. In the first if, the expression evaluates to 5 and since 5 is non-zero it is considered to be true. Hence the printf( ) gets executed.
In the second if, 10 gets assigned to a so the if is now reduced to if ( a ) or if ( 10 ). Since 10 is non-zero, it is true hence again printf( ) goes to work.
In the third if, -5 is a non-zero number, hence true. So again printf( ) goes to work. In place of -5 even if a float like 3.14 were used it would be considered to be true. So the issue is not whether the number is integer or float, or whether it is positive or negative. Issue is whether it is zero or non-zero.
Subscribe to:
Posts (Atom)