1.5 Structure of a ‘C’ Program
1.6 printf() and scanf() Functions
1.8 Escape Sequence (Backslash Character Constants)
In 1971 Dennis Ritchi, a system programmer from Bell laboratories, developed a very powerful language called C for writing UNIX, a large and complex operating system. Even the compiler of ‘C’ was written in C. In fact, it is a high level language that not only supports the necessary data types and data structures needed by a normal programmer but it can also access the computer hardware through specially designed declarations and functions and, therefore, it is often called as a “middle-level” language.
It is popular because of the following characteristics:
Besides the above characteristics, the C programs are small and efficient. A ‘C’ program can be compiled on variety of computers.
The set of characters allowed in ‘C’ consists of alphabets, digits, and special characters as listed below:
A, B, C, …. X, Y, and Z
a, b, c, …. x, y, and z
0, 1, 2, …. 7, 8, 9
! * + “ <<
#(= ! {
%) ; “ /
^_ [ :, ?
&_ ]’ . blank
Every program specifies a set of operations to be done on some data in a particular sequence. However, the data can be of many types such as a numbers, characters, floating points, etc. ‘C’ supports the following simple data types: Integer data type, character data type, floating point data type.
An integer is an integral whole number without a decimal point. These numbers are used for counting. Examples of integers are:
923
47
5
15924
−56
2245
‘C’ allows four types of representation of integers, i.e., integer, long integer, short integer, and unsigned integer.
The unsigned int is stored in one word of the memory whereas the unsigned short is stored in 16 bits and does not depend upon the word size of the memory.
Examples of invalid integers are:
(i) 9, 24, 173 | illegal-comma used |
(ii) 5.29 | illegal-decimal point used |
(iii) 79 248 | blank used |
It is a non-numeric data type consisting of single alphanumeric character enclosed between a pair of apostrophes, i.e., single quotation marks.
Examples of valid character type are:
‘A’
‘N’
‘*’
‘7’
It may be noted that the character ‘7’ is different from the numeric value 7. In fact, former is of type char and later of type int. Each character has a numeric code, i.e., the ASCII code. For instance, the ASCII code for the character ‘A’ is 65 and that of ‘*’ is 42. A table of ASCII codes is given in Appendix A.
A character data type is referred to as char. It is stored in one byte of memory. However, the representation varies from computer to computer. For instance, some computers support signed as well as unsigned characters. The signed characters can store integer values from –128 to +127 whereas the unsigned characters store ASCII codes from 0 to 255.
A floating point number is a real number which can be represented in two forms: decimal and exponent forms. Floating point numbers are generally used for measuring quantities.
Examples of valid “decimal form” numbers are:
973.24
849.
73.0
–82349.24
9.0004
<integer>. <fraction> e <exponent>
Examples of valid floating point numbers are:
3.45 e 7
0.249 e –6
It may be noted that exponent form is a scientific notation wherein the number is broken into two parts: mantissa and exponent. The mantissa is a floating point number of decimal form. The exponent part starts with a letter ‘e’ followed by an integer (signed or unsigned).
For example, the number 324.5 can be written as 3.245 times 102. In exponential form, the number is represented as 3.245 e2. In fact, the base 10 has been replaced by the character e (or E).
The utility of exponential form is that very small numbers can be easily represented by this notation of floating points.
For example, the number 0.00001297 can be written as 0.1297 e–4 or as 12.97 e–6 or as 129.7 e–7.
‘C’ allows the following two data types for floating prints:
A summary of ‘C’ basic data types is given the Table 1.1. From this table, it may be observed that character and integer type data can also be declared as unsigned. Such data types are called unsigned data types. In this representation, the data is always a positive number with range starting from 0 to a maximum value. Thus, a number twice as big as a signed number can be represented through unsigned data types.
Table 1.1 Basic data types in ‘C’
A token is a group of characters that logically belong together. In fact, a programmer can write a program by using tokens. ‘C’ supports the following types of tokens:
Symbolic names can be used in ‘C’ for various data items. For example, if a programmer desires to store a value 27, then he can choose any symbolic name (say, ROLL) and use it as given below:
ROLL = 27;
Where ROLL is a memory location and the symbol ‘=’ is an assignment operator.
The significance of the above statement is that ‘ROLL’ is a symbolic name for a memory location where the value 27 is being stored. A symbolic name is generally known as an identifier.
The identifier is a sequence of characters taken from ‘C’ character set. The number of characters in an identifier is not fixed though most of the C compilers allow 31 characters. The rules for the formation of an identifier are:
Examples of acceptable identifiers are:
TOTAL
Sum
Net_sal
P123
a_b_c
total
_sysreg
Examples of unacceptable identifiers are:
Bas ic (blank not allowed)
H, rent (special character ‘, ‘ included)
It may be noted here that TOTAL and total are two different identifier names.
A keyword is a reserved word of C. This cannot be used as an identifier by the user in his program. The set of C keywords is given in Table 1.2.
Table 1.2 Standard keywords in ‘C’
A variable is the most fundamental aspect of any computer language. It is a location in the computer memory which can store data and is given a symbolic name for easy reference. The variables can be used to hold different values at different times during a program run. To understand this concept, let us have a look at the following set of statements:
Total = 500.25; …(i)
Net = Total − 100.00; …(ii)
In statement (i), value 500.25 has been stored in a memory location called Total. The variable Total is being used in statement (ii) for the calculation of another variable Net. The point worth noting is that ‘the variable Total is used in statement (ii) by its name not by its value’.
Before a variable is used in a program, it has to be defined. This activity enables the compiler to make available the appropriate amount of space and location in the memory. The definition of a variable consists of its type followed by the name of the variable. For example, a variable called Total of type float can be declared as shown below:
float Total;
Similarly, the variable net of type int can also be defined as shown below:
int Net;
Examples of valid variable declarations are:
Let us now look at a variable declaration from a different perspective. Whenever a variable (say, int val) is declared, a memory location called val is made available by the compiler as shown in Figure 1.1.
Fig. 1.1 Memory allocated to variable val
Thus, val is the name associated by the compiler to a location in the memory of the computer. Let us assume that, at the time of execution, the physical address of this memory location (called val) is 4715 as shown in Figure 1.2.
Fig. 1.2 The physical address of val
Now, a point worth noting is that this memory location is viewed by the programmer as a variable called val and by the computer system as an address 4715. The programmer can store a value in this location with the help of an assignment operator, i.e., ‘=’. For example, if the programmer desires to store a value 100 into the variable val, he can do so by the following statement:
val = 100;
Once the above statement is executed, the memory location called val gets the value 100 as shown in Figure 1.3.
Fig. 1.3 The contents of a variable (rvalue)
‘C’ allows the initialization of variables even at the time of declaration as shown below:
int val = 100;
From Figure 1.3, we can see that besides its type a variable has three entities associated with it, i.e., the name of variable (val), its physical address (4715), and its contents (100). The content of a variable is also called its rvalue whereas the physical address of the variable is called its lvalue. Thus, lvalue and rvalue of variable val are 4715 and 100, respectively. The lvalue is of more importance because it is an expression that should appear on the left hand side of assignment operator because it refers to the variable or object.
A constant is a memory location which can store data in such a manner that its value during execution of a program does not change. Any attempt to change the value of a constant will result in an error message. A constant in ‘C’ can be of any of the basic data types, i.e., integer constant, floating point constant, and character constant. const qualifier is used to declare a constant as shown below:
const <type> <name> = <val>;
where
const: | is a reserved word of ‘C’ |
<type>: | is any of the basic data types |
<name>: | is the identifier name |
<val>: | is the value to be assigned to the constant. |
const int rate = 50;
The above declaration means that rate is a constant of type integer having a fixed value 50. Consider the following declaration:
const int rate;
rate = 50;
The above initialization of constant rate is illegal. This is because of the reason that a constant cannot be initialized for a value at a place other than where it is declared. It may be further noted that if a program does not change or mutatesa constant or constant object then the program is called as const correct.
const float Pi = 3.1415;
The above declaration means that Pi is a constant of type float having a fixed value 3.1415. It may be noted here that by default a floating point constant is of type double.
const char Akshar = ’Q’;
The above declaration means that Akshar is a constant of type char having a fixed value ‘Q’.
A sequence of characters enclosed within quotes is known as a string literal. For example, the character sequence “computer” is a string literal. When a string literal is assigned to an identifier declared as a constant, then it is known as a string constant. In fact, a string is an array of characters. Arrays are discussed later in the chapter.
A simple program in ‘C’ can be written as a module. More complex programs can be broken into sub-modules. In ‘C’, all modules or subprograms are referred to as functions.
The structure of a typical ‘C’ program is given below:
main ()
{
....;
....;
....;
}
Note:
Let us break the myth that ‘C’ is a difficult language to start with. Without going into the details, the beginner can quickly start writing the program such as given below:
#include <stdio.h>
main()
{
puts (“This is my first program”);
}
The above program displays the following text on the screen:
This is my first program.
‘C’ uses printf() and scanf() functions to write and read from I/O devices, respectively. These functions have been declared in the header file called stdio.h.
Let us use printf() function to rewrite our first program. The modified program is given below:
#include <stdio.h>
main()
{
printf (“This is my first program”);
}
This program displays the following message on the screen:
This is my first program.
In fact, any text written within the pair of quotes (“ ”) is displayed as such by printf() function on the screen. However, this function is much more powerful than puts() in the sense that it can display all types of data on the screen as explained below.
An integer, stored in a variable, can be displayed on the screen by including a format specifier (%d) within a pair of quotes as shown below:
#include <stdio.h>
main()
{
int age = 25;
printf (“%d”, age);
}
The above program does the following:
It may noted that printf() has two arguments separated by a comma, i.e., format specifier written within quotes and the variable age. It may be further noted that both messages and format specifiers can be included within the pair of quotes as shown below:
printf (“ The age of student = %d”, age);
The above statement would display the following data on the screen:
The age of student = 25
Thus, the text between the quotes has been displayed as such but for %d, the data stored in the variable age has been displayed.
A float can be displayed on the screen by including a format specifier (%f) within the pair of quotes as shown below:
float rate = 9.5;
printf (“The rate of provident fund = %f”, rate);
The above statements would produce the following display:
The rate of provident fund = 9.5
A char can be displayed by including a format specifier (%c) within the pair of quotes as shown below:
char ch = ’A’
printf (“The first alphabet is: %c”, ch);
Obviously, the output of the above set of statements would be:
The first alphabet is: A.
The other specifiers which can be used in printf() function are given in Appendix B.
Similar to printf() function, scanf() function also uses the %d, %f, %c, and other format specifiers to specify the kind of data to be read from the keyboard.
However, it expects the programmer to prefix the address operator ‘&’ to every variable written in the argument list as shown below:
int roll;
scanf (“%d”, & roll);
The above set of statements declares the variable roll of type int, and reads the value for roll from the keyboard. It may be noted that ‘&’, the address operator, is prefixed to the variable roll. The reason for specifying ‘&’ would be discussed later in the book.
Similarly, other format specifiers can be used to input data from the keyboard.
Example 1: Write an interactive program that reads the marks secured by a student for four subjects Sub1, Sub2, Sub3, and Sub4, the maximum marks of a subject being 100. The program shall compute the percentage of marks obtained by the student.
Solution: The scanf() and prinf() functions would be used to do the required task. The required program is as follows:
#include <stdio.h>
main()
{
int sub1, sub2, sub3, sub4;
float percent;
printf (“Enter the marks for four subjects:”);
scanf (“%d %d %d %d”,&sub1, &sub2, &sub3, &sub4);
percent = (sub1 + sub2 + sub3 + sub4)/ 400.00*100;
printf (“The percentage = %f”, percent);
}
For input data 45 56 76 90, the above program computes the percentage and displays the following output:
The percentage = 66.750000
Though the output is correct, but it has displayed unnecessary four trailing zeros. This can be controlled by using field width specifiers discussed later in the chapter.
A comment can be added to the program by enclosing the text between the pair / * ... * /, i.e., the pair ‘/*’ indicates the beginning of the comment whereas the pair ‘*/’ marks the end of it. It is also known as multiple line comment. For example, the following line is a comment:
/* This is my first program */
Everything written within ‘/*’ and ‘*/’ is ignored by the compiler. A comment written in this fashion can overflow to multiple lines as shown below:
/* This is an illustration of multiple line comment. The C compiler ignores these lines. A programmer can use comment lines for documentation of his programs*/
In fact, a comment is a non-executable statement in the program.
‘C’ has some special character constants called backslash character constants. These are unprintable ASCII characters which can perform special functions in the output statements. A backslash character constant is nothing but a back slash (’’) character followed by another character.
For example, “ ” can be used in a printf() statement to send the next output to the beginning of the next line.
Consider the following program:
#include <stdio.h >
main()
{
printf(“A backslash character constant”);
printf(“prints the output on the next line.”);
}
The output of this program would be:
A backslash character constant prints the output on the next line.
It may be noted that though two separate printf() statements were written in the above program, the output has been displayed on the same line.
In order to display the text in two lines, the “ ” character constant should be placed either at the end of the text in the first printf() statement or at the beginning of the text in the second printf() statement.
Consider the following modified program:
#include <stdio.h>
main()
{
printf(“A backslash character constant”);
printf(“
prints the output on the next line.”);
}
The character constant “ ” has been placed at the beginning of the text of the second printf() statement and, therefore, the output of the program would be:
A back slash character constant
prints the output on the next line.
Some other important backslash constants are listed below:
Backslash character constant | Meaning |
---|---|
tab | |
backspace | |
a | bell (alert) |
newline character |
Note:
The backslash characters are also known as escape sequences; such characters can be used within apostrophes or within double quotes.
#include <stdio.h>
main()
{
printf(“
hello Comp-Boy”);
}
The output of the above statement would be on the new line with spacing as shown below:
hello Comp-Boy
#include <stdio.h>
main()
{
printf(“
ASHOKA-”);
}
The output of the above statement would be:
ASHOK-
We can see that the trailing letter ‘A’ has been overwritten by the character ‘-’ at the end of the string constant <ASHOKA> the reason being that ‘’ moved the curser one column backward, i.e., at ‘A’ and printf() printed the character ‘-’ on that column position.
#include <stdio.h>
main()
{
printf(“
Error in data a”);
}
The output of the above statement would be the following message on the screen and a sounding of a bell on the system speaker.
Error in data
#include <stdio.h>
main()
{
printf(“
This is
a test.”);
}
The output of this statement would be:
This is
a test.
An operator is a symbol or letter used to specify a certain operation on variables in a program. For example, the symbol ‘+’ is an add operator that adds two data items called operands.
Expressions: An expression is a combination of operands (i.e., constants, variables, numbers) connected by operators and parenthesis. For example, in the expression given below A and B are operands and ‘+’ is an operator.
A + B
‘C’ supports many types of operators such as arithmetic, relational, logical, etc. An expression that involves arithmetic operators is known as an arithmetic expression. The computed result of an arithmetic expression is always a numerical value. The expression which involves relational and/or logical operators is called as a boolean expression or logical expression. The computed result of such an expression is a logical value, i.e., either 1 (True) or 0 (False).
The rules of formation of an expression are:
The valid arithmetic operators supported by ‘C’ are given in Table 1.3.
Table 1.3 Arithmetic operator
Symbol | Stands for | Example |
---|---|---|
+ | addition | x + y |
– | subtraction | x – y |
* | multiplication | x *y |
/ | division | x/y |
% | modulus or remainde | x%y |
–– | decrement | ––x |
x–– | ||
++ | increment | x++ |
A unary operator requires only one operand or data item. The unary arithmetic operators supported by ‘C’ are unary minus (‘-’), increment (‘++’), and decrement (‘--’). As compared to binary operators, the unary operators are right associative in the sense that they evaluate from right to left.
The unary minus operator is written before a numerical value, variable or an expression. Examples of usage of unary minus operator are:
It may be noted here that the result of application of unary minus on an operand is the negation of its operand.
The operators ‘++’ and ‘--’ are unique to C. These are called increment and decrement operators, respectively. The increment operator ‘++’ adds 1 to its operand. Therefore, we can say that the following expressions are equivalent.
i = i + 1 ++i;
For example, if the initial value of i is 10 then the expression ++i will increment the contents of i to 11. Similarly, the decrement operator ‘--’ subtracts 1 from its operand. Therefore, we can say that the following expressions are equivalent:
j = j - 1 --j;
For example, if the initial value of j is 5 then the expression --j will decrement the contents of j to 4.
The increment and decrement operators can be used both as a prefix and as a postfix to a variable as shown below:
++ x or x++
--y or y--
As long as the increment or decrement operator is not used as part of an expression, the prefix and postfix forms of these operators do not make any difference. For example, ++x and x++ would produce the same result. However, if such an operator is part of an expression then the prefix and postfix forms would produce entirely different results.
In the prefix form, the operand is incremented or decremented before the operand is used in the program. Whereas in the postfix form, the operand is used first and then incremented or decremented.
A relational operator is used to compare two values and the result of such an operation is always logical, i.e., either true or false. The valid relational operators supported by C are given in Table 1.4.
Table 1.4 Relational operators supported by C
Symbol | Stands for | Example |
---|---|---|
> | greater than | x > y |
> = | greater than equal to | x > = y |
< | less than | x < y |
< = | less than equal to | x < = y |
= = | equal to | x = = y |
! = | not equal to | x ! = y |
Example 2: Take two variables x and y with initial values 10 and 15, respectively. Demonstrate the usage of relational operators by using x and y as operands.
Solution: The usage of relational operators is illustrated below with the help of a table:
x = 10, y = 15
Expression | Result |
---|---|
x > y | False |
x + 5 > = y | True |
x < y | True |
x < = y | True |
x = = y | False |
x + 5= = y | True |
x! = y | True |
A logical operator is used to connect two relational expressions or logical expressions. The result of such an operation is always logical, i.e., either true or false. The valid logical operators supported by C are given in Table 1.5.
Table 1.5 Logical operators supported by C
Symbol | Stands for | Example |
---|---|---|
&& | Logical AND | x&&y |
|| | Logical OR | x||y |
! | Logical NOT | !x |
Rules of logical operators:
For initial value of x = 5 and y = 7, consider the following expression:
(x < 6) && (y > 6)
The operand x < 6 is true and the operand y > 6 is also true. Thus, the result of above given logical expression is also true. However, the result of following expression is false because one of the operands is false:
(x < 6) && (y > 7)
Similarly, consider the following expression:
(x < 6) || (y > 7)
The operand x < 6 is true whereas the operand y > 7 is false. Since these operands are connected by logical OR, the result of this expression is true (Rule 2). However, the result of the following expression becomes false because both the operands are false.
!(x < 6) || (y > 7)
Note: The expression on the right hand side of logical operators && and || does not get evaluated in case the left hand side determines the outcome.
Consider the expression given below:
x && y
If x evaluates to false (zero), then the outcome of the above expression is bound to be false irrespective of y evaluating to any logical value. Therefore, there is no need to evaluate the term y in the above expression.
Similarly, in the following expression, if x evaluates to true (non zero) then the outcome is bound to be true. Thus, y will not be evaluated.
x || y
‘C’ provides a conditional operator (? :) which can help the programmers in performing simple conditional operations. It is represented by the symbols ‘?’ and ’:’. For example, if one desires to assign the bigger of the two variables x and y to a third variable z the conditional operator is an excellent tool.
The general form of this operation is:
E1?E2:E3
where E1, E2, and E3 are expressions.
In the conditional operation, the expression E1 is tested, if E1 is true then E2 is evaluated otherwise the expression E3 is evaluated as shown in Figure 1.4.
Fig. 1.4 conditional operator
Consider the following conditional expression:
z = (x > y)? x : y;
The expression x > y is evaluated. If x is greater than y, then z is assigned x otherwise z gets y. Examples of valid conditional expressions are:
It may be noted here that the conditional operator (? :) is also known as a ternary operator because it operates on three values.
A number of logical and relational expressions can be linked together with the help of logical operators as shown below:
(x < y) || (x > 20) && !(z) || ((x < y) && (z > 5))
For a complex expression such as given above, it becomes difficult to make out as to in what order the evaluation of sub-expressions would take place.
In ‘C’, the order of evaluation of an expression is carried out according to the operator precedence given in Table 1.6.
Table 1.6 Operator precedence
It may be noted here that in C, false is represented as zero and true as any non-zero value. Thus, expressions that use relational and logical operators return either 0 (false) or 1 (true).
There are many other operators in C. In this section, the two frequently used operators—sizeof and comma operators—have been discussed.
a = sizeof (“sum”);
b = sizeof (char);
c = sizeof (123L);
would return the sizes occupied by variables sum, data type char and constant ‘123L’ on your machine. It may be noted that
For example, the following statement
a = (x = 5, x + 2)
executes in the following order
The following points may be noted regarding comma operator:
Statements are the smallest executable units of a C program and each statement is terminated with a semicolon. An assignment statement assigns the value of the expression on the right hand side to a variable on the left hand side of the assignment operator (=). Its general form is given below:
<variable name> = <expression>
The expression on the right hand side could be a constant, a variable or an arithmetic, relational, or logical expression. Some examples of assignment statements are given below:
a = 10;
a = b;
a = b*c;
count = count +1;
a = b = c = 30;
These multiple assignment statements work from right to left and at the end, all variables have the same value. The above statement assigns the value (i.e., 30) to all variables c, b, and a. However, the variables must be of same type.
‘C’ supports special bitwise shift operators: shift left (<<) and shift right (>>). We know that data at machine level is represented in the binary form and it can be shifted to left or right by these special operators. However, the number of bits to be shifted is specified by an integer written next to the operatoras shown below:
x << 3;
The above statement means that the value contained in x is shifted to left by 3 bits. Thus, the leftmost 3 bits of x will be lost and the resultant vacant 3 rightmost bits will be filled by zeros as shown in Figure 1.5.
Fig. 1.5 The contents of x before and after left shift
Similarly, the following expression would shift the contents of y to right by two bits:
y >> 2
In this case, the rightmost two bits would be lost and the resultant 2 vacant leftmost bits would be filled by zeros as shown in Figure 1.6.
Fig. 1.6 The contents of y before and after right shift
A statement is the smallest executable unit of a C program. It is terminated with a semicolon. It is an instruction given to the computer to perform a particular task like reading input, displaying output or evaluating an expression, etc.
A single statement is also called a simple statement. Some examples of simple statement are given below:
A statement can also be an empty or null statement as shown below:
;
The high level languages are designed for computers based on Von-Neumann architecture. Since this architecture supports only sequential processing, the normal flow of execution of statements in a high level language program is also sequential, i.e., each statement is executed in the order of its appearance in the program. For example in the following C program segment, the order of execution is sequential from top to bottom.
The first statement to be executed is ‘x = 10’, and the second statement to be executed is ‘y = 20’. The execution of statement ‘z = x + y’ will take place only after the execution of the statement ‘y = 20’. Thus, the processing is strictly sequential. Moreover, every statement is executed once and only once.
Depending upon the requirements of a problem, it is often required to alter the normal sequence of execution in the program. This means that we may desire to selectively and/or repetitively execute a program segment. A number of ‘C’ control structures are available for controlling the flow of processing. These structures are discussed in the following sections.
A compound statement is a group of statements separated from each other by a semicolon. The group of statements, also called a block of code, is enclosed between a pair of curly braces, i.e., ‘{’ and ‘}’. The significance of a block is that the sequence of statements enclosed in it is treated as a single unit. For example, the following group of statements is a block.
/* a block of code*/
{
scanf (“%d %d”, & a, & b);
c = a + b;
printf (“
%d”, c);
}
One compound statement can be embedded in another as shown below:
{
:
{
:
}
:
}
In fact, the function of curly braces ‘{’ and ‘}’ in a ‘C’ program to create a block, is same as the function of begin and end, the reserved words in Pascal. ‘C’ calls these braces as delimiters.
In some cases, it is desired that a selected segment of a program be executed on the basis of a test, i.e., depending upon the state of a particular condition being true or false. In ‘C’, ‘if statement’ is used for selective execution of a program segment.
if (expression)
{
statement sequence
}
Examples of acceptable ‘if statements’ are:
total = total + val;
count = count + 1;
}
:
}
if (expression)
{
statement sequence1
}
else
{
statement sequence2
}
where | if: | is a reserved word. |
expression: | is a boolean expression, written within parentheses. | |
statement sequence1: | can be a simple or a compound statement. | |
else: | is a reserved word. | |
statement sequence2: | can be a simple or a compound statement. |
Examples of if-else statements are:
else C = B;
printf (“
Equal to 100”);
else
printf (“
Not Equal to 100”);
It may be noted here that both the ‘if’ and ‘else’ parts are terminated by semicolons.
if (exp1)
if (exp2)
{
:
}
else
if (exp3)
{
:
}
else
{
:
}
It may be noted here that sometimes the nesting may become complex in the sense that it becomes difficult to decide “which if does the else match”. This is called “dangling else problem”. The ‘C’ compiler follows the following rule in this regard:
Rule: Each else matches to its nearest unmatched preceding if.
Consider the following nested if:
if (x < 50) if (y > 5) Net = x + y; else Net = x – y;
In the above statement, the else part matches the second if (i.e., if (y . 5)) because it is the nearest preceding if. It is suggested that the nested if(s) should be written with proper indentation. The else(s) should be lined up with their matching if(s). Nested if(s) written in this fashion are also called if-else-if ladder. For example, the nested if given above should be written as:
if (x < 50)
if (y > 5)
Net = x + y;
else
Net = x – y;
However, if one desires to match the else with the first if, then the braces should be used as shown below:
if (x < 50) {
if (y > 5)
Net = x + y;
}
else
Net = x – y;
The evaluation of if-else-if ladder is carried out from top to bottom. Each conditional expression is tested and if found true, only then its corresponding statement is executed. The remaining ladder is, therefore, by passed. In a situation where none of the nested conditions is found true, the final else part is executed.
switch (expression)
{
case constant 1:
statement;
break;
case constant 2:
statement;
break;
:
default:
statement;
}
where switch: | is a reserved word. |
expression: | it must evaluate to an integer or character value. |
case: | is a reserved word. |
constant: | it must be an int or char compatible value. |
statement: | a simple or compound statement. |
default: | is a reserved word and is an optional entry. |
break: | is a reserved word that stops the execution within the switch and control comes out of the switch construct. |
The switch statement works according to the following rules:
Examples of acceptable switch statements are:
switch (BP)
{
case 1 : total + = 100;
break;
case 2 : total + = 150;
break;
case 3 : total + = 250;
}
switch (code)
{
case 101 : Rate = 50; break;
case 102 : Rate = 70; break;
case 103 : Rate = 100; break;
default : Rate = 95;
}
In the statement (ii), it can be observed that depending on the value of the code one out of the four instructions is selected and obeyed. For example, if the code evaluates to 103, the third instruction (i.e., Rate =100) is selected. Similarly if the code evaluates to 101, then the first instruction (i.e., Rate = 50) is selected.
Some problems require a set of statements to be executed a number of times, each time changing the values of one or more variables so that every new execution is different from the previous one. This kind of repetitive execution of a set of statements in a program is known as a loop.
We can categorize loop structures into two categories: non-deterministic loops and deterministic loops. When the number of times the loop is to be executed is not known, then the loop is called non-deterministic loop otherwise it is called a deterministic loop.
‘C’ supports while, do while, and for loop constructs to help repetitive execution of a compound statement in a program. The ‘while’ and ‘do while’ loops are non-deterministic loops and the ‘for’ loop is a deterministic loop.
while <cond> statement;
where while: | is a reserved word of C. |
<cond>: | is a boolean expression. |
statement: | can be a simple or compound statement. |
The sequence of operation in a while loop is as follows:
It may be noted here that the variables used in the <cond> or boolean expression must be initialized somewhere before the while statement is encountered. It is a pre-test loop in the sense that the condition is tested before the body of the loop is executed.
do
{
statement;
}
while <cond>;
where | do: | is a reserved word. |
statement: | can be a simple or a compound statement. | |
while: | is a reserved word. | |
<cond>: | is a boolean expression. |
The sequence of operations in a do-while loop is as follows:
Thus, it performs a post-test in the sense that the condition is not tested until the body of the loop is executed at least once.
3. The for loop: It is a count controlled loop in the sense that the program knows in advance as to how many times the loop is to be executed. The general form of this construct is given below: for (initialization; expression; increment)
{
statement
}
where | for: | is a reserved word. |
initialization: | is usually an assignment expression wherein a loop control variable is initialized. | |
expression: | is a conditional expression required to determine whether the loop should continue or be terminated | |
increment: | it modifies the value of the loop control variable by a certain amount. | |
statement: | can be a simple or a compound statement. |
The loop is executed with the loop control variable at initial value, final value and the values in between.
We can increase the power of for-loop with the help of the comma operator. This operator allows the inclusion of more than one expression in place of a single expression in the ‘for’ statement as shown below:
for (exp1a, exp1b; exp2; exp3a, exp3b;) statement;
Consider the following program segment:
:
for (i = 1, j = 10; i < = 10; i++, j--)
{
:
}
The variable i and j have been initialized to values 1 and 10, respectively. Please note that these initialization expressions are separated by a ‘comma’. However, the required semicolon remains as such. During the execution of the loop, i increases from 1 to 10 whereas j decreases from 10 to 1 simultaneously. Similarly, the increment and decrement operations have been separated by a ‘comma’ in the ‘for statement’.
Though the power of the loop can be increased by including more than one initialization and increment expression separated with the comma operator but there can be only one test expression which can be simple or complex.
The break statement can be used in any ‘C’ loop to terminate execution of the loop. We have already seen that it is used to exit from a switch statement. In fact, whenever the break statement is encountered in a loop the control is transferred out of the loop. This is used in a situation where some error is found in the program inside the loop or it becomes unnecessary to continue with the rest of the execution of the loop.
Consider the following program segment:
:
while (val != 0)
{
:
printf (“
%d”, val);
if (val < 0) {
printf (“
Error in input”);
break;
}
:
}
Whenever the value contained, in variable val becomes negative, the message ‘Error in input’ would be displayed and because of the break statement the loop will be terminated.
The continue statement can also be used in any ‘C’ loop to bypass the rest of the code segment of the current iteration of the loop. The loop, however, is not terminated. Thus, the execution of the loop resumes with the next iteration. For example, the following loop computes the sum of positive numbers in a list of 50 numbers:
:
sum = 0;
for (i = 0; i < 50; i ++)
{
printf (“
%d”, val);
if (val <= 0) continue;
sum = sum + val;
}
:
It may be noted here that continue statement has no relevance as far as the switch statement is concerned. Therefore, it cannot be used in a switch statement.
In the event of encountering a fatal error, the programmer may desire to terminate the program itself. For such a situation, ‘C’ supports a function called exit() which can be invoked by the programmer to exit from the program. This function can be called from anywhere inside the body of the program. For normal termination, the programmer can include an argument ‘0’ while invoking this library function as shown below:
#include <stdio.h>
#include <process.h>
void main()
{
:
if (error) exit (0);
:
}
It may be noted here that the file process.h has to be included as header file because it contains the function prototype of the library function exit().
It is possible to nest one loop construct inside the body of another. The inner and outer loops need not be of the same construct as shown below.
while <cond>
{
do
{
} while <cond>;
for (init; exp; inc)
{
:
}
:
}
The rules for the formation of nested loops are:
The unconditional transfer of control means that the sequence of execution will be broken without performing any test and the control will be transferred to some statement other than the immediate next one. ‘C’ supports the following statement for this purpose.
goto <statement label>
where | goto: | is a reserved word. |
<statement label>: | is an identifier used to label the target statement. |
The goto statement causes control to be transferred to the statement whose label is specified in the goto statement. Consider the following program segment:
-
-
goto rpara;
-
-
rpara: -
-
-
The goto statement will cause the control to be transferred to a statement whose label is rpara. The normal flow of execution will continue from this statement (i.e., having label rpara) onwards. Consider the following program segment:
:
k = 50;
back: I++
:
sum = sum + k*I ;
k--;
goto back;
:
It is clear from the above segment that as and when the control reaches the goto statement, it transferred to the statement with label back.
Statement label A statement label is an identifier which can be placed before any C statement followed by a colon (i.e., :) as shown below:
again: C = A + B;
Thus, again is a label attached to the statement C = A + B and the control of execution can be transferred to this statement by the following goto statement.
goto again;
It may be noted here that the transfer of control out of a control structure is allowed. However, a goto branch into a control structure is not allowed.
Some example programs using control structures are given below.
Example 3: Write a program that reads three numbers and prints the largest of them.
Solution: The if-else ladder would be used. The required program is given below:
/* This program displays the largest of three numbers */
#include <stdio.h>
main()
{
int A, B, C;
printf (“
Enter the Numbers A, B, C:”);
scanf (“%d %d %d”, &A, &B, &C);
/* if-else ladder */
if (A > B)
if ( A > C)
printf (“
A is largest”);
else
printf (“
C is largest”);
else
if (B > C)
printf (“
B is largest”);
else
printf (“
C is largest”);
/* end of ladder */
}
Example 4: Write a program that prints all perfect numbers between 2 and 9999, inclusive. A perfect number is a positive integer such that the number is equal to the sum of its proper divisors. A proper divisor is any divisor whose value is less than the number.
Solution: The remainder operator ‘%’ would be used to find whether a number is divisor of another or not. The maximum value of perfect divisor cannot be more than the half the value of the number.
The required program is given below:
/* This program finds out all the perfect numbers between 2 and 9999 both
inclusive */
#include <stdio.h>
main()
{
int num, divisor;
int sum;
char ch;
for (num = 2; num , = 9999; num++)
{
sum = 1; /* 1 is proper divisor of all positive integers */
for (divisor = 2; divisor < = num/2; divisor++)
{
if (num % divisor == 0)
sum = sum + divisor;
}
if ( sum == num )
printf (“
%d is a perfect number”, num);
}
}
Most of the programs read and write data through input/output devices such as screen, keyboard, printer, and disk devices, etc. Obviously, the programmer has to learn how to perform correct I/O operations so that efficient programs can be written. We have already used two C functions printf() and scanf() in the previous examples. In the following sections, we will discuss some of the following input output functions:
In order to use the above functions, the programmer must include the ‘stdio.h’ header file at the beginning of his program. The ‘C’ or ‘C environment’ assumes keyboard as the standard input device and VDU as standard output device. A consol comprises both keyboard and VDU.
By default, all stream I/Os are buffered. At this point, it is better that we understand the term buffered I/O before we proceed to discuss the stream I/O functions.
Whenever we read from the keyboard or from a file stored on a device, a block of data is stored in a buffer called input buffer. The input stream, therefore, reads from the buffer with the help of a pointer until the input buffer is empty (see Figure 1.7). As soon as the buffer becomes empty, the next block of data is transferred into the buffer from the I/O device.
Fig. 1.7 Buffered I/O
Similarly, data written by an output stream pointer is not directly written onto the device but into an output buffer. As soon as the output buffer becomes full, a block of data is written on to the I/O device making output buffer empty.
When the header file stdio.h is included in a program, the following standard stream pointers are automatically opened:
Name | Meaning |
stdin | standard input |
stdout | standard output |
stderr | standard error |
stdaux | auxiliary storage |
stdprn | printer |
In the computer, ‘stdin’ and ‘stdout’ refer to the user’s console, i.e., input device as keyboard and output device as VDU (screen). The stream pointers ‘stdprn’ and ‘stdaux’ refer to the printer and auxiliary storage, respectively. The error messages generated by the stream are sent to standard error (stderr).
In order to clear the buffers, a function called ‘fflush()’ can be used. For example, input buffer of standard input device can be cleared by invoking the function: ‘fflush(stdin)’.
‘C’ supports many input and output functions based on character. These functions read or write one character at a time. ‘C’ supports both stream and consol I/O character-based functions. We will discuss them in the following sections.
:
char ch;
ch = getchar();
:
Since the function getchar() is a stream I/O function, it is buffered in the sense that the character typed by the user is not passed to the variable ch until the user hits the enter or return key, i.e., ↵. The enter key is itself a character and it also gets stored in the buffer along with the character typed by the user. The entry of ‘enter key’ character into the buffer creates problems in the normal functioning of getchar() function. Therefore, it is suggested that after an input operation from the standard input device (i.e., keyboard) the input buffer should be cleared. This operation is required to avoid interference with subsequent input operations. The function call for this activity is: fflush (stdin). The usage is shown below:
:
char ch;
ch = getchar();
fflush (stdin);
:
The function putchar() is used to send a single character to the standard output device. The character to be displayed on the VDU screen is included as an argument to the putchar() function as shown below:
:
ch = ’A’;
putchar (ch);
:
Once the above program segment is executed, the character ‘A’ will be displayed on the screen.
The putchar() function is also buffered. The function call for clearing the output buffer is fflush (stdout). The output buffer is cleared on its own only when a new line character ‘ ’ is used.
For example, the function getc(stdin) is equivalent to the function getchar(). Both will get a character from the standard input device (keyboard). The function getchar() by default reads from keyboard whereas the argument stdin of function getc(stdin) makes it read from a file represented by the standard input device which is nothing but the keyboard.
Similarly, the function putc(ch, stdout) is equivalent to the function putchar(ch). Both the functions send the character ch to the standard output device, i.e., VDU screen.
Examples of usage of these functions are:
Examples of usage of this function are:
Note: These functions cannot read special keys from the keyboard such as function keys.
String-based functions read or write a string of characters at a time. ‘C’ supports both stream and console I/O string-based functions.
:
name = gets() ;
fflush (stdin);
:
Similarly, the function puts() is used to send a string to the standard output device. The string to be displayed on the VDU screen is included as an argument to the puts function as shown below:
:
city = "New Delhi”;
puts (city);
:
Once this program segment is executed, the following message will be displayed on the screen:
New Delhi
A detailed discussion on arrays as data structure is given in Chapter 3.
Arrays are very useful for list and table processing. However, the elements of an array must be of the same data type. In certain situations, we require a construct that can store data items of mixed data types. C supports structures for this purpose. The basic concept of a structure comes from day-to-day life. We observe that certain items are made up of components or sub-items of different types. For example, a date is composed of three parts: day, month, and year as shown in Figure 1.8.
Fig. 1.8 Composition of ‘date’
Similarly, the information about a student is composed of many components such as name, age, roll number., and class; each belonging to different types (see Figure 1.9).
Fig. 1.9 Student
The collective information about the student as shown above is called a structure. It is similar to a record construct supported by other programming languages. Similarly, the date is also a structure. The term structure can be precisely defined as ‘a group of related data items of arbitrary types’. Each member of a structure is, in fact, a variable that can be referred to through the name of the structure.
A structure can be defined in C by the keyword struct followed by its name and a body enclosed in curly braces. The body of the structure contains the definition of its members and each member must have a name. The declaration ends by a semicolon. The general format of structure declaration in C is given below:
struct <name> {
member 1
member 2
:
member n
};
where | struct: | is the keyword. |
<name>: | is the name of the structure. | |
member 1, 2 ... n: | are the individual member declarations. |
Let us now define the following ‘C’ structure to describe the information about the student given in Figure 1.9.
struct student
{
char Name [20];
int age;
int roll;
char class[5];
};
The above declaration means that the student is a structure consisting of data members: Name, age, roll, and class. A variable of this type can be declared as given below:
struct student x;
Once the above declaration is obeyed, we get a variable x of type student in the computer memory which can be visualized as shown in Figure 1.10.
Fig. 1.10 Memory space allocated to variable x of type student
The programmer is also allowed to declare one or more structure variables along with the structure declaration as shown below:
struct student { char name [20]; int age; int roll; char class [5]; } stud1, stud2;
In the above declaration, the structure declaration and the variable declaration of the structure type have been clubbed, i.e., the structure declaration is followed by two variable names stud1 and stud2 and the semicolon.
The structure variable x has four members: name, age, roll, and class. These members can be designated as: x.name, x.age, x.roll, and x.class, respectively. In this notation, an individual member of the structure is designated or qualified by the structure variable name followed by a period and the member name. The period is called a structure member operator or simply a dot operator.
However, the information of a student (Figure 1.10) can be stored in structure variable x in either of the following ways:
strcpy (x.name, “SACHIN KUMAR”);
x.age = 18;
x.roll = 10196;
strcpy (x.class, “CE41”);
gets(x.name);
ffush(stdin);
scanf(“% d %d”, & x age., & x.roll);
gets(x.class);
An array of structures can be declared just like an ordinary array. However, the structure has to be defined before an array of its type is declared. For example, a 50-element array of type student called stud_list can be defined as shown below:
struct student {
char name [20];
int roll;
int sub1, sub2, sub3, sub4;
int total;
};
struct student stud_list [50]; /* declaration of an array of structures*/
When a structure variable is declared, its data members are not initialized and, therefore, contain undefined values. Similar to arrays, the structure variables can also be initialized. For instance, the structure shown in Figure 1.10 can be declared and initialized as shown below:
struct student
{
char name[20];
int age;
int roll;
char class[5];
};
/* Initialize variable of type student*/
struct student stud1 = {"SACHIN KUMAR”, 18, 10196," CE41"};
Please notice that the values are enclosed within curly braces. The values are assigned to the members of the structure in the order of their appearance, i.e., first value is assigned to the first member, second to second, and so on.
It has been appreciated that the individual fields of a structure can be treated as simple variables. The main benefit of a structure, however, is that it can be treated as a single entity. For example, if two structure variables stud1 and stud2 have been declared as shown below
student stud1, stud2;
then the following assignment statement is perfectly valid.
stud1 = stud2;
This statement will perform the necessary internal assignments. The concept of structure assignment can be better understood by the following example program. In this program, a structure variable stud1 is initialized with certain values and it is assigned to another structure variable stud2. The contents of the variable stud2 are displayed.
/* This program illustrates copying of complete structures */
#include <stdio.h>
main()
{
struct student {
char name[20];
int roll;
int age;
char class[6];
};
/* initialize a variable of type student */
struct student stud1 = {"Sachin Kumar”, 101, 16, "CE_IV"};
struct student stud2;
/* assign stud1 to stud2 */
stud2 = stud1;
/* Display contents of stud2 */
printf (“
The copied contents are....”);
printf (“
Name: %s”, stud2.name);
printf (“
Roll: %d”, stud2.roll);
printf (“
Age : %d" , stud2.age);
printf (“
class: %s”, stud2.class);
}
Nested structures are structures as member of another structure. For instance, the date of birth (DOB) is a structure within the structure of a student as shown in figure below. These types of structures are known as nested structures.
The nested structure shown in Figure 16.4 can be declared in a program as shown below:
/* Nested structures /*
struct date
{
int dd;
int mm;
int yy;
};
struct student
{
char name[20];
int roll;
struct date dob;
int marks;
};
It may be noted here that the member of a nested structure is referenced from the outermost to inner most with the help of dot operators. Let us declare a variable stud of type student:
struct student stud;
The following statement illustrates the assignment of value 10 to the member mm of this nested structure stud:
stud.dob.mm = 10;
The above statement means: store value 10 in mm member of a structure dob which itself is a member of structure variable called stud.
In addition to the simple data types such as integer, float, char, etc., ‘C’ allows the users to declare new data types called user-defined data types. These data types can be declared with the help of a keyword called typedef whose general form is given below:
typedef <type> <new_type>
where | <typedef>: | is a reserved word |
<type>: | is an existing data type. | |
<new_type>: | is the desired user-defined data type. |
For example, consider the following declaration:
typedef float xyz;
In this declaration, an existing data type (float) has been redefined as xyz. Now, the user can use xyz as a synonym for the type float as a new type as shown below.
xyz x1, x2;
In fact, the above declaration is equivalent to the following declaration:
float x1, x2;
Apparently, it looks as if we have not achieved anything great because the user will have to remember xyz as a new type whereas its equivalent float type is already available. Nevertheless, the utility of typedef lies in a situation where the name of a particular type is very long. The user can also self document his code as shown in the following declaration:
typedef float salary; :
salary wages-of-month;
In the above declaration, the variable wages-of-month has been declared of type salary, where salary itself is of float type. Thus, we can see that readability of a program can be enhanced by self documenting the variables and their data types with the help of typedef.
For example, the declaration:
typedef int age;
can be used to increase the clarity of code as shown below :
age boy, girl, child;
The above statement clearly suggests as to what data the variables boy, girl, and child are going to store.
Similarly, typedef can also be used to define arrays.
typedef float lists [20];
lists BP, SAL, GSAL;
These statements are equivalent to the following:
float BP [20], SAL [20], GSAL [20]
typedef is also extremely useful for shortening the long and inconvenient declarations of structures.
For instance, the structure struct can be declared as a typedef as shown below:
typedef struct {
char name [20];
int age;
int roll;
char class[6];
} student;
Now the structure student has become the type and a variable of this type can be defined as:
student stud1, stud2;
The above declaration means that stud1 and stud2 are variables of type student.
A user can define a set of integer type identifiers in the form of new data types called enumerated data types. For instance, the user can create a new data type called color with the help of enum definition as shown below:
enum color {
Blue,
Yellow,
White,
Black
};
where enum is the keyword that defines an enumerated data type.
The enum declaration given above means that a new type, color, has been defined. This type contains the constant values: Blue, Yellow, White, and Black. Each of these symbols stands for an integer value. By default, the value of the first symbol (i.e., Blue) is 0, the value of the second symbol is 1, and so on. Once the type color has been defined, then variables of that type can be defined in the following manner:
enum color A, B;
Now, the variable A of type color can use the enumerations (blue, yellow, etc.) in a program.
Thus, the following operations on variable A are valid:
A = red;
:
if (A == red)
x = x + 10;
else
x = x – 5;
Enumerated data type can be precisely defined as the ordered set of distinct constant values defined as a data type in a program.
Examples of some valid enumerated data types are:
{
chair,
table,
stool,
desk
};
{
Maruti,
Santro,
Micra,
Indigo
}
It may be noted here that the ordering of elements in enumerated data type is specified by their position in the enum declaration. Thus for furniture type, the following relations hold good:
Expression | Value |
---|---|
Chair<Table | True |
Stool>Desk | True |
Table==Desk | False |
Chair<Desk | True |
The enumerated types can also be used in a switch construct. Consider the following program segment.
:
/* Enumerated type declaration */
enum furniture
{
chair,
table,
stool,
desk
};
main()
{
/* Enumerated variable declaration */
enum furniture item;
float cost;
:
switch item
{
case chair : cost = 250; break;
case table : cost = 700; break;
case stool : cost = 120; break;
case desk : cost = 1500; break;
}
:
Similarly, enumerated data types can also be used as a control variable in a for loop as shown below:
:
for (item = chair; item <= desk; item++)
{
:
:
}
The enumerations are also called symbolic constants because an enumeration has a name and an integer value assigned to it which cannot be changed in the program. Therefore, enumerated data types cannot be plainly used in I/O statements. As a result, the statements scanf, printf, gets, puts, etc. cannot be directly applied to these data types because the results will not be as desired.
Suppose in a fete, every visitor is assured to win any one of the items listed below:
Obviously, a visitor to the fete must carry a bag large enough to carry the largest item so that any one of the items won by him can be held in that bag. With the same philosophy in mind, the designers of ‘C’ introduced a special variable called union which may hold objects of different sizes and types but one at a time. Though a union is a variable and can hold only one item at a time, it looks like a structure. The general format of a union is given below:
union <name> {
member 1
member 2
:
member
};
where | union: | is a keyword. |
<name>: | is the name of the union. | |
member 1, 2, ... n: | are the individual member declarations. |
A function is a subprogram that can be defined by the user in his program. It is a complete program in itself in the sense that its structure is similar to main() function except that the name main is replaced by the name of the function. The general form of a function is given below:
<type> <name> (arguments)
Where | <type>: | is the type of value to be returned by the function. If no value is returned, then keyword void should be used. |
<name>: | is a user-defined name of the function. The function can be called from another function by this name. | |
arguments: | is a list of parameters (parameter is the data that the function may receive when called from another function). This list can be omitted by leaving the parameters empty. |
The program segment enclosed within the opening brace and closing brace is known as the function body. For example, the main function in C is written as shown below:
main()
{
}
Let us write a function tri_area() which calculates the area of a triangle. Two variables base and height will be used to read the values from the keyboard. The function is given below:
float tri_area()
{
float base, height, area;
printf (“
Enter Base and Height”);
scanf (“%f %f”, &base, &height);
area = (0.5)*base*height;
return (area);
}
It may be noted here that the function tri_area() has defined its own variables. These are known as local variables. The advantage of their usage is that once the execution of the function is over these variables are disposed off by the system, freeing the memory for other things.
Let us write another function clear () which clears the screen of the VDU
/* This function clears the screen by writing blank lines on the screen */
void clear()
{
int i;
for (i = 0; i< = 30; i++)
printf (“
”);
}
Similarly, let us write a function add which receives two parameters x and y of type integer from the calling function and returns the sum of x and y.
int add (int x, int y) { int temp; temp = x + y; return temp; }
In the above function, we have used a local variable temp to obtain the sum of x and y. The value contained in temp is returned through return statement. In fact, variable temp has been used to enhance the readability of the function only, otherwise it is unnecessary. The function can be optimized as shown below:
ind add (int x, int y)
{
return (x + y);
}
Thus, a function has following four elements:
The name of the function has to be unique so that the compiler can identify it. The body of the function contains the C statements which define the task performed by the function. The return type is the type of value that the function is able to return to the calling function. The argument or parameter list contains the list of values of variables from outside required by the function to perform the given task. For example, the function given above has a name add. It has a body enclosed between the curly braces. It can return a value of type int. The argument list is x and y.
Similar to variables, all functions must be declared before they are used in a program. ‘C’ allows the declaration of a function in the calling program with the help of a function prototype. The general form of a function prototype in the calling program is given below:
<type> <name> (arguments);
where | <type>: | is the type of value to be returned by the function |
<name>: | is a user-defined name of the function. | |
arguments: | is a list of parameters. | |
;: | the semicolon is necessary. |
For example, the prototype declarations for the functions tri_area(), clear(), and add() can be written as shown below:
void tri_area();
void clear();
int add(int x, int y);
It may be noted that a function prototype ends with a semicolon. In fact, the function prototype is required for those functions which are intended to be called before they are defined. In absence of a prototype, the compiler will stop at the function call because it cannot do the type checking of the arguments being sent to the function. Therefore, the main purpose of function prototype is to help the compiler in static type checking of the data requirement of the function.
A function can be called or invoked from another function by using its name. The function name must be followed by a set of actual parameters, enclosed in parentheses and separated by commas. A function call to function tri_area from the main program can be written as:
tri_area();
This statement will transfer the control to function tri_area. Since this function does not require any parameter, the argument list is empty. Similarly, in order to call the function ‘clear’, the following statement will be sufficient:
clear();
A complete C program involving the two functions tri_area and clear is given below:
#include <stdio.h>
/* Function ptototypes */
float tri_area();
void clear();
main()
{
char ch;
int flag;
float Area;
clear(); /* Clear the screen */
flag = 0;
while (flag == 0)
{
Area = tri_area(); /* call tri_area to compute area */
printf (“
Area of Triangle = %5.2f”, Area);
printf (“
Want to calculate again: Enter Y/N”);
fflush(stdin);
ch = getchar();
if (ch == ’N’ || ch == ’n’)
flag = 1;
clear();
}
}
float tri_area()
{
float base, height, area;
printf (“
Enter Base and Height”);
scanf (“%f %f”, &base, &height);
area = (0.5)*base*height;
return (area);
}
/* This function clears the screen by writing blank lines on the screen */
void clear()
{
int i;
for (i = 0; i< = 30; i++)
printf(“
”);
}
It may be noted here that when this program is executed, the first statement to be executed is the first executable statement of the function main() of the program (i.e., clear() in this case). A function will be executed only after it is called from some other function or itself.
The variables base, height, and area are local to function tri_area and they are not available in the main() function. Similarly, the variable flag declared in function main() is also not available to functions tri_area() and clear().
However, the variables declared outside any function can be accessed by all the functions. Such variables are called global variables.
Let us consider the following program which declares the variables flag and area outside the main function instead of declaring them inside the functions main() and tri_area (), respectively.
#include <stdio.h>
/* Function prototypes */
void tri_area();
void clear();
/* Global Variables */
int flag;
float area;
main()
{
char ch; /* Local Variable */
clear(); /* Clear the screen */
flag = 0;
while (flag == 0)
{
tri_area(); /* call tri_area to compute area */
printf (“
Area of Triangle = %5.2f”, area);
printf (“
Want to calculate again: Enter Y/N”);
fflush(stdin);
ch = getchar();
if (ch == ’N’ || ch == ’n’)
flag = 1;
clear();
}
}
/* Function Definitions */
void tri_area()
{
float base, height;
printf (“
Enter Base and Height”);
scanf (“%f %f”, &base, &height);
area = (0.5)*base*height;
}
/* This function clears the screen by writing blank lines on the screen */
void clear()
{
int i;
for (i = 0; i< = 30; i++)
printf (“
”);
}
It may be noted in the above program that the variable area is available to both the functions tri_area() and main(). On the other hand, the local variables base and height are available to function tri_area only. They are neither available to main() function nor to the function clear(). Similarly, variable i is also local to function clear().
In our previous programs, we have used our own function clear() to clear the screen. C also provides a function called clrscr() that clears the screen. From now onwards, we will use this function. However, in order to use clrscr() in a program we will have to include conio.h, a header file at the beginning of the program.
Note: We should not use global variables in our programs as they make the program or function insecure and error prone.
We have seen that two-way communication between functions can be achieved through global variables. This technique has its own limitations and drawbacks. Let us now see how this communication between the calling function and the called function can be improved and made fruitful.
The two-way communication between the various functions can be achieved through parameters and return statement as done in previous section. The set of parameters defined in a function are called formal or dummy parameters whereas the set of corresponding parameters sent by the calling function are called actual parameters. For instance, the variables x and y in the argument list of function add() are formal parameters. The parameters included in the function call, i.e., val1 and val2 of main() are actual parameters.
The function that receives parameters can be called in one of the following two ways:
/* This function compares two variables and returns the bigger of the two */ int big (int x, int y) { if (x > y) return x; else return y; }
The function big() can be called from the function main() by including the variables a and b as the actual arguments of the function call as shown below.
main()
{
int a = 30;
int b = 45;
int c;
c = big (a, b);
printf (“
The bigger = %d ”, c);
}
The output of the above program would be:
The bigger = 45
Let us now write a program which reads the values of two variables a and b. The values of a and b are sent as parameters to a function exchange(). The function exchanges the contents of the parameters with the help of a variable temp. The changed values of a and b are printed.
#include <stdio.h>
#include <conio.h>
void exchange( int x, int y);
main()
{
int a, b;
clrscr(); /* clear screen */
printf (“
Enter two values”);
scanf (“%d %d”, &a, &b);
exchange(a,b);
/* print the exchanged contents */
printf (“
The exchanged contents are: %d and %d”, a, b);
}
void exchange (int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
The above program seems to be wonderful but it fails down badly because variables a and b do not get any values back from the function exchange(). The reason is that although all values of actual parameters (i.e., a and b) have been passed on to formal parameters (i.e., x and y) correctly, the changes done to the values in the formal parameters are not reflected back into the calling function.
Once the above program is executed for input value (say 30 and 45), the following output is produced:
The exchanged contents are: 30 and 45
The reason for this behaviour is that at the time of function call, the values of actual parameters a and b get copied into the memory locations of the formal parameters x and y of the function exchange().
It may be noted that the variables x and y have entirely different memory locations from variables a and b. Therefore any, changes done to the contents of x and y are not reflected back to the variables a and b. Thus, the original data remains unaltered. In fact, this type of behaviour is desirable from a pure function.
Since in this type of parameter passing, only the values are passed from the calling function to the called function, the technique is called call by value.
For instance, in order to receive the addresses of actual parameters of int type the exchange () function can be rewritten as shown below:
void exchange (int *val1, int *val2)
{
int temp;
temp = *val1;
*val1 = *val2;
*val2 = temp;
}
It may be noted that the above function has used two pointers called val1 and val2 to receive the addresses of two int type actual parameters. However, initially, these are dangling pointers as shown below:
The exchange() function would be called from the main() function by sending the addresses of the actual arguments as shown below:
exchange (& a, & b);
Note: Kindly refer to Chapter 5 before reading the text of this section.
After the exchange() function is called by the above statement, the addresses of the actual parameters a and b would be assigned to pointers val1 and val2, respectively as shown below:
Since the function exchanges the contents of variables being pointed by the pointers val1 and val2, the contents of variables a and b get exchanged which is the goal of this exercise.
The complete program is given below:
#include <stdio.h>
#include <conio.h>
void exchange( int *val1, int *val2);
main()
{
int a, b;
clrscr(); /* clear screen */
printf (“
Enter two values”);
scanf (“%d %d”, &a, &b);
exchange(&a,&b);
/* print the exchanged contents */
printf (“
The exchanged contents are: %d and %d”, a, b);
}
void exchange (int *val1, int *val2)
{
int temp;
temp = *val1;
*val1 = *val2;
*val2 = temp;
}
After the above program is executed for input values (say 30 and 45), the following output is produced:
The exchanged values are: 45 30
Now, we can see that the program has worked correctly in the sense that changes made inside the function exchange() have been available to corresponding actual parameters a and b in the function main(). Thus, the address operator ‘&’ has done the required task.
The main advantage of call by reference method is that more than one value can be received back from the called function.
Note:
void calc (int a, float *b, float *c);
some (xyz);
The formal parameters can be declared in the called function in three ways. The different ways are illustrated with the help of a function some() that receives an array xyz of size 100 of integer type.
Method I:
In this method, the array is declared without subscript, i.e., of an known size as shown below:
void some (int xyz [ ])
{
}
The C compiler automatically computes the size of the array.
Method II:
In this method, an array of same size and type is declared as shown below:
void some (int xyz [100])
{
}
Method III:
In this method, the operator * is applied on the name of the array indicating that it is a pointer.
void some (int *xyz)
{
}
All the three methods are equivalent and the function some() can be called by the following statement:
some (xyz);
Note:
Earlier in this chapter, we have used functions which either return no value or integer values. The functions that return no value are declared as void. We have been prefixing int to functions which return integer values. This is valid but unnecessary because the default return value of a function in C is of type int. Thus, the following two declarations are equivalent in the sense that we need not prefix int to a function which returns an integer value.
int add (int a, int b);
add (int a, int b);
On the other hand, whenever a function returns non-integer values, the function must be prefixed with the appropriate type. For example, a function xyz that returns a value of type float can be declared as shown below:
float xyz (.....)
{ float a;
:
return a
}
Similarly, a function ABC that returns a value of type char can be declared as shown below:
char ABC ( ..... )
{ char ch;
:
return ch;
}
Similar to variables, the structures can also be passed to other functions as arguments both by value and by reference.
The following program uses a structure variable called stud of type student and passes the structure variable by value to a function print_data(). The function print_data() displays the contents of the various members of the structure variables.
/* This program illustrates the passing of the structures by value to a
function */
#include <<stdio.h>>
struct student
{
char name [20];
int age;
int roll;
char class [5];
};
/* Prototype of the function */
void print_data (struct student Sob);
main()
{
struct student stud;
printf (“
Enter the student data”);
printf (“
Name:”); fflush(stdin);
gets (stud.name);
printf (“
Age:”); scanf(“%d”, &stud.age);
printf (“
Roll:”); scanf(“%d”, &stud.roll);
printf (“
Class:”); fflush(stdin);
gets (stud.class);
print_data(stud); /*The structure is being passed by value*/
}
void print_data (struct student Sob)
{
printf (“
The student data..”);
printf (“
Name:”); fflush(stdout);
puts (Sob.name);
printf (“Age: %d”,Sob.age);
printf (“
Roll: %d”,Sob.roll);
printf („
Class:”); fflush(stdout);
puts (Sob.class);
}
This program reads the data of a student in the function main() and passes the structure by reference to the function called print_data().
/* This program illustrates the passing of the structures by reference to
a function */
#include <stdio.h>
struct student
{
char name [20];
int age;
int roll;
char class [5];
};
/* Prototype of the function */
void print_data (struct student &Sob);
main()
{
struct student stud;
printf (“
Enter the student data”);
printf (“
Name:”); fflush(stdin);
gets (stud.name);
printf (“
Age:”); scanf(“%d”,&stud.age);
printf (“
Roll:”); scanf(“%d”,&stud.roll);
printf (“
Class:”); fflush(stdin);
gets (stud.class);
print_data(&stud); /*The structure is being passed by reference*/
}
void print_data (struct student &Sob)
{
struct student *ptr;
ptr = sob;
printf (“
The student data..”);
printf (“
Name:”); fflush(stdout);
puts (ptr−>name);
printf (“Age: %d”,ptr->age);
printf (“
Roll: %d”,ptr->roll);
printf (“
Class:”); fflush(stdout);
puts (ptr->class);
}
It may be noted here that structures are usually passed by reference in order to prevent the overheads associated with the technique of passing structures by value. The overheads are extra memory space and CPU time used to pass bigger structures.
Example 5: Write a program that reads the data of a students whose structure is given in the figure shown below. The structure is then passed by value to a function called change-data() where the name of the student is capitalized. The changed contents of the student data are returned by the function to the function main().
Solution: We will use the function toupper() in this program to capitalize the name of the student inside the function change-data(). The required program is given below:
/* This program illustrates the process of returning a structure from a
function */
#include <stdio.h>
#include <ctype.h>
struct student
{
char name [20];
int age;
int roll;
char class [5];
};
/* Prototype of the function */
void print_data (struct student *ptr);
struct student change_data (struct student Sob);
main()
{
struct student stud, newstud;
printf (“
Enter the student data”);
printf (“
Name:”); fflush(stdin);
gets (stud.name);
printf (“
Age:”);scanf(“%d”,&stud.age);
printf (“
Roll:”);scanf(“%d”,&stud.roll);
printf (“
Class:”); fflush(stdin);
gets (stud.class);
/* call function to change data */
newstud = change_data(stud);
printf (“
The changed data ..”);
print_data(&newstud); /*The structure is being passed by value*/
}
/* This function changes the data of a student */
struct student change_data (struct student Sob)
{
int i = 0;
while (Sob.name[i] != ’ ’)
{ /* Capitalize the letters */
Sob.name[i] = toupper (Sob.name[i]);
i++;
}
return (Sob);
}
void print_data (struct student *ptr)
{
printf (“
The student data..”);
puts (ptr->name);
printf (“Age: %d”, ptr->age);
printf (“
Roll: %d”, ptr->roll);
printf (“
Class:”); fflush(stdout);
puts (ptr->class);
}
#include <stdio.h>
main()
{
printf(“Compu”);
printf (“ter”);
}
Ans. The output would be: Computer
#include <stdio.h>
main()
{
printf(“Compuuter”);
}
Ans. The output would be: Computer
void main()
{
int k = 30;
/*
printf (“k = %d”, k);
*/
printf (“value of k = %d”, k);
}
Ans. The output would be: value of k = 30
Ans. The required statements are:
Ans Since in ‘C’ 1 represents true and 0 represents false, the following statements can be used instead of above:
Ans. The required statement is: num = num + (++Val);
printf (“%c”, ch);
printf (“%d”, a < 10);
Ans. The output would be: (i) K, (ii) 1
#include <stdio.h>
main()
{
int k = 10;
k = ++k == 11;
printf (“
%d”, k);
}
Ans. The output would be: 1
#include <stdio.h>
main()
{
int i =8 > 5?100:150;
printf(“
%d”,i);
}
Ans. The output would be: 100
enum furniture { Chair,
Table,
Bed
Almirah
};
#include <stdio.h>
main()
{
printf (“
%d %d %d %d”, Chair, Table, Bed, Almirah);
}
Ans. The output would be: 0 1 2 3
#include <stdio.h>
int first (int, int);
int second (int);
void main()
{
int x = 10, y = 5, z;
z = first (x,y);
printf (“
z = %d”, z);
}
int first (int x, int y)
{
return (x + second (y));
}
int second (int y)
{
return ++y;
}
Ans. The output would be: 16
#include <stdio.h>
{
int k;
printf (“k = %d”, k );
}
A
B B
C C C
D D D D
E E E E E
Menu | |
Option1 | ‘a’ |
Option2 | ‘b’ |
Option3 | ‘c’ |
Option4 | ‘d’ |
Enter your choice:
In response to user’s selection, it prints the following messages:
Option | Message |
---|---|
1 | ‘One is alone’ |
2 | ‘Two is a company’ |
3 | ‘Three is a crowd’ |
4 | ‘Quitting’ |
3.16.51.157