ITP Week 2
ITP Week 2
Reading Objective
In this reading, you will learn to write a C program. You will gain insights into the essential elements of a C program. You
will then learn how to compile the program using a compiler on Coursera Labs and execute it on the processor.
First, we must understand the various elements essential to writing a C program. Then we need to define each step the
program will take before we write the actual code.
Let’s get started with our first C program. We will write a program to find out the sum of two numbers.
1. START
2. Input the numbers num1, num2
3. Initialize sum = 0
4. Set sum = num1 + num2
5. Print sum
6. END
Fig. 1 shows an example program to determine the sum of two numbers. Let us understand the individual elements of the
program.
a. Preprocessor directive
In Fig. 1, we see the second line #include<stdio.h> that instructs the preprocessor to insert the contents of the file stdio.h
at the beginning of the program. We must know that a file with a .h extension is a header file that informs the C compiler
about standard pre-written C functions that other users can use in their program. Now, stdio.h is a header file that
contains information about functions in the C programming language to perform input and output operations, where
stdio means Standard Input Output. This file is stored in a standard directory where the compiler stores all the header
files.
b. Comments
In Fig. 1, we can see a lot of texts written in green color. These are comments. Comments are statements written in
natural language, usually English, to enhance the readability of our code for the programmer and others. Programmers
use these comments to explain the logic they implement in a particular line or function. Comments can be employed to
convey related information to the human reader of the program to help them understand the code better. There are two
ways we can create comments in C. First, we can write a // to make a single-line comment extending until the end of the
current line. And second, we can write any text between /* and */, which is considered a multi-line comment.
/* This is a multi-line
comment.*/
c. Functions
There are some tasks that we want to perform repeatedly in a program. For this purpose, we can use lines 7 and 8 in Fig.
1, which are called the printf( ) and the scanf( ) functions, respectively. We can easily observe the parenthesis indicating
printf and scanf names of functions in C.
We can also look at the compilation, another commonly used terminology in computer programming. The compilation
converts high-level code written in a particular programming language into low-level machine code understandable by
the computer.
d. Handling errors
We can encounter some problems called errors during the compilation or execution of a computer program. Errors can
also occur after successful compilation and execution, but with incorrect output. There are three types of errors: compile-
time errors, run-time errors, and semantic errors.
• Compile-time errors occur when some statements in our code do not follow the rules of the programming
language in which they are written. These errors are raised by the compiler while trying to compile our code.
For example, in Fig. 1, we can see that all the statements between lines 6 to 11 in the C program end in a semicolon. If we
forget to put a semicolon, it raises a compile-time error. int a, b, sum;
• Run-time errors occur during the execution of our program but are not detected during compilation.
For example, a statement a = b / c; can cause an error if the value of c is zero.
• Semantic errors occur when the code compiles and executes successfully but does not perform the intended
task.
For example, if we use == instead of using =, the meaning of the expression will change completely. However, the program
will still compile and execute properly. a = b means the value of b is assigned to a, whereas a == b is a Boolean expression
whose value is True if values of a and b are the same, and False otherwise.
Let us now look at compiling and running a C program. Fig. 2 shows the steps involved in running a C program. It shows
how the operating system loads the program into RAM and then executes it line by line on the CPU.
Steps to run a C program
• Firstly, we write a C program in any file with the extension .c and store it on disk. The .c extension denotes files
written in the C programming language.
• Then, we compile our program and generate an executable file using the gcc <filename>.c command. For
example, gccmyFirst.c
• The above compilation generates an executable file named a.out and stores it on disk.
• Now, we can execute our program by running the ./a.out command.
• When we run the above command, the OS loads the executable file onto the RAM and instructs the CPU to
execute it line by line.
Reading Summary:
In this reading, you will be introduced to variables, constants, and datatypes in C. You will understand how memory
space is allocated to variables in RAM. You will also understand how characters are internally represented as integers and
how implicit and explicit type conversions are performed in C.
We write computer programs to solve real-world problems. For this, programs must be very efficient in handling real-
world data. Programming languages have come up with different data types that support different kinds of data to
address the need to represent real-world data in computer programs.
Data in a program can be stored as a constant or a variable. A constant is a data item whose value remains fixed
throughout the entire program. A variable is a data item whose value can be changed during the program’s execution.
Variables are allocated a fixed memory location in the RAM from where we can read and modify the variable. For example,
if we need to store the value of π in a program, we will use a constant. To iterate over a list of 20,000 items, we will use a
variable to indicate the current position that we are reading and keep incrementing the value of that variable to iterate
through the entire list.
We can declare a variable by specifying the data type of the variable followed by the variable name. For example, int age,
or float avg.
A constant is a data item whose value remains fixed throughout the entire program. C specifies a default datatype with
every constant. For example, 25, 6.25, and ‘$’ are all constants.
• The default data type of an integer in C is int. If the constant does not fit into an integer, a larger size data type is
used to store the constant.
• The default data type for a floating point number is double.
• We can use suffixes to assign data types to constants other than their default datatypes. For integer constants,
the suffix U or you can be used to make them unsigned integers, suffix L or l can be used to make them as long
integers. When a double constant is suffixed by f or F, it demotes the constant to a float datatype, and the suffix L
or l promotes it to a long double datatype.
• There are two ways of defining constants in C.
o Using a const qualifier In a variable declaration, we can add const qualifier in front of the declaration
to tell the compiler that this variable declaration is a constant declaration, not a variable declaration. For
example, const float pi = 3.14f; // here pi is a read-only value. Also, note that we have used ‘f’ as a suffix to
indicate that the constant value 3.14 is to be interpreted as a float value, not a double value.
o Using symbolic constants #define We can use preprocessor directives to define constants in our code.
For example, #define PI 3.14f // no semicolon used Before compiling the code, the compiler will replace
all the occurrences of PI in our program with 3.14f. Note: It is good practice to use all capital letters when
defining #define constants and to start all variables with a small letter.
o The difference between the two types of constants above is that in the first type, we have declared a
constant that takes actual memory on RAM. Still, because we have specified the const qualifier in the
declaration, the compiler won’t allow the value of this variable to be changed during the execution of the
program. Whereas when we use #define, no variable is declared. The compiler is just replacing PI with
3.14f in our program before it starts compilation
Consider the C program shown in Figure 1 above. Its main function has three variables declared: num1, num2, and num3.
Where do these three variables get stored in the main memory?
Figure 2: Steps of program execution.
We have noted that the compilation of a C program creates an executable stored on the hard disk. When this executable
file is executed, the operating system (OS) loads our C program into the RAM and executes it line by line on the CPU. Let
us look closely at the memory allocated to the program in the main memory.
When the OS loads the program into RAM, it allocates some memory to the program. As shown in Figure 3, the variables
named in the program are stored in this space.
Variables in a C program occupy a fixed amount of RAM space on the RAM depending on their datatype. For example, an
int variable will occupy 2 or 4 bytes depending on the compiler used to compile the program. Main memory is logically
represented as a massive table of rows, where each row can store 8 bits. A bit stores a binary value of 0 or 1, sometimes
called True or False. A set of 8 contiguous bits is known as a byte. Figure 4 shows a snapshot of how the RAM looks when
an int variable is declared and initialized:
int num = 4;
Four bytes are allocated, as shown in addresses from 1004 through 1007, and the value of 4 is in these four bytes.
Figure 5 shows different integer types supported by the C programming language and what the range of values that these
datatypes can represent. Since any variable in C takes a finite amount of memory, it can be easily understood that there
will be a certain limit on the number of values that it can represent. The precise size of all the datatypes is not explicitly
defined in the C language definition. It is left up to the compiler to decide how much memory to allocate to those
datatypes. However, we can still observe that allocated memory follows the order below: short, unsigned short <= int,
unsigned int <= long, unsigned long <= long long, unsigned long long.
It is also very easy to determine the number of bytes allotted to a particular variable. The sizeof() operator returns the
number of bytes allotted to a variable. Its return type is unsigned long int. Figure 6 shows an example of a C program that
computes the amount of memory allocated for variables of different datatypes and its output on execution. Please go to
Coursera Labs and try to execute this code. You learn better when you execute the code yourself.
Figure 4: Visualization of some memory locations in RAM when a variable is declared and initialized.
Figure 7 shows the different types of floating-point datatypes supported by C, the number of bytes used by them, and
their range in the form of mantissa and exponent. Please note that a double has a higher precision than a float in terms of
the number of digits.
Character Types in C:
We have heard about representing integers in binary format, but what about characters? How do computers represent
characters in binary format? Computers use ASCII (American Standard Code for Information Interchange) character-
encoding scheme. ASCII defines an encoding to represent English characters (a-z, A-z) along with the other symbols (!, @,
#, $), punctuation marks (:, “, ‘, ?, /), numeric characters (0-9) and some non-printable characters as numbers, with each
letter assigned to a number from 0 to 127. 8-bit ASCII is used in C so the char datatype is one byte wide.
Fig 8 shows an ASCII chart that shows how different characters are represented in ASCII character-encoding scheme.
Character variables are stored in the memory as integers only, and therefore, we can perform computations using them.
For instance, in the example given below, %c format specifier tells printf() to interpret ch1 or ch2 as a character, and %d
tells printf() to interpret ch1 or ch2 as an integer while printing.
char ch1 = ‘A’, ch2; printf(“%c\t%d\n”, ch1, ch1); // prints A 65 on the screen ch2 = ch1 + 1; // char
variables can be used for computation just like integers printf(“%c\t%d\n”, ch2, ch2); // prints B 66 on the screen
Nonprintable characters
There are certain characters in ASCII like \n (newline), \t(tab), which cannot be printed on the screen. These are called
non-printable characters. Refer to Figure 8 to find out more non-printable characters.
To print some special characters like ‘ or “ or \ , we should use a preceding \. See the example below.
A string is a sequence of characters. In C, a string is implemented as an array of characters. (You will learn more about
arrays and strings later!) A character literal in C is enclosed within single quotes, whereas a string literal in C is enclosed
within double quotes. For example, “Welcome” is a string, ‘A’ is a character, “A” is a string containing only one character,
and ‘Welcome’ will throw an error.
Type Conversions:
Type conversion in C allows us to tell the compiler to interpret the datatype of a variable differently in a particular
statement. Note that type conversion does not change the datatype of a variable; it just instructs the compiler
to interpret a variable as a different datatype while executing a particular instruction. There are two types of
type conversions, implicit and explicit.
Reading Summary:
● How variables in a program get space allocated in the RAM based on their types
In this reading, you will be introduced to various kinds of operators implemented in C and how to use them to create
expressions. You will also learn about the precedence and associativity rules to evaluate expressions.
We have already got introduced to variables and constants. Now, we will define operators and operands and see how
these two are combined to form expressions. C programs employ different operators on one or more variables to get
useful results. Operators are mathematical symbols used in C programs to perform arithmetic, logical, and relational
manipulations on variables and constants. Operands are the values that operators operate upon to get some result.
When we combine operands with various operators, we get an expression. In C programs, operands can be constants,
variables, or even other expressions. For example, in the expression x + 2, the variable x and constant 2 are operands, and
+ is an addition operator. Other examples of expressions are 2 + 3, 2 *4, 8 - 3, 15 / 4, a + b / 7, -5, etc. Constants like 25
and -5 are also expressions.
Types of Operators
There are two types of operators: unary and binary operators. Unary operators operate on a single operand, whereas
binary operators operate on a pair of operands. For example, in the expression -5, the - sign is acting as a unary operator,
and in the expression 25 - x, the - sign is acting as a binary operator.
There is another way in which operators can be classified into four categories - arithmetic operators, relational operators,
logical operators, and assignment operators. Let us understand them one by one.
1. Arithmetic operators
• These operators are used for performing arithmetic operations on numeric types of data.
• Binary arithmetic operators take two operands as input. For example, C has the following binary arithmetic
operators:
o Addition (+): It computes the sum of two numbers.
o Subtraction (-): It computes the difference between two numbers.
o Multiplication (*): It computes the product of two numbers.
o Division (/): It computes the quotient upon the division of two numbers. For integer operands, the
division operator performs truncation to report the result. Truncation means that the result is reported
after dropping the decimal part of the number. For example, while rounding of 2.7 yields 3, truncation of
2.7 yields 2, rounding of -2.7 yields -3, whereas truncation of -2.7 yields -2.
o Modulo (%): It computes the remainder upon the division of two numbers. It is applicable only to integer
variables or constants. For example, 5%2 = 1. The modulo operator cannot be used on floating point
operands.
• The following example shows the result obtained by applying the given operands over two cases:
o Case 1: int a = 42, b = 5
o Case 2: float a = 42.0, b = 5.0
• This operator is used to assign a value to a variable. For example, y = 5; assigns the value of 5 to the variable y,
and x = y; assigns the value of y to the memory location corresponding to variable x.
• The variable occurring to the left of the assignment operator is called L-value. The L-value persists beyond that
single expression, i.e., the memory location of the L-value continues to hold the newly assigned value even after
that particular assignment statement until it is further modified.
• The temporary value that sits at the right of the assignment operator does not persist beyond the single
expression that uses it and is called R-value.
• There is another variety of assignment operators in C known as shorthand operators. These are of the form
“op=”. x op= y is the same as x = x op y; this is the reason why these operators are called shorthand operators
because they give a shorthand way to represent x = x op y; for example, +=, -=, *=, /=, %= are shorthand operators.
• Below given are two examples:
o The expression int x = 62, y = 7; x %= y; assigns the value (62 % 7), i.e., 6 to the variable x, whereas the
value of y stays the same.
o The expression, int dividend = 30, divisor = 4; dividend /= divisor; gives the dividend as 7 after the
operation, and the value of the divisor stays unchanged.
• These operators take only one operator as input and can be used either as a prefix or as a postfix to the operand.
For example, ++ and -- are two unary arithmetic operators. ++ operator increments the value of the operand by 1,
and -- decrements the value of the operand by 1. These operators can only be applied to L-values.
• Prefix unary arithmetic operators:
o This type of unary operator changes the value and then uses the updated value in the expression. This
means that in the case of prefix unary arithmetic operators, the compiler first changes the value of the
operand and then uses that changed value in the expression.
o Syntax: ++ <variable_name> / -- <variable_name>
o For example, int a = 1; printf(“%d”, ++a); In the printf() statement, ++a first increases the value of a, and
then this new value is passed to the printf() function. Thus 2 gets printed.
o The prefix operator is lower in precedence than the postfix operator.
• Postfix unary arithmetic operators:
o This type of unary operator uses the existing value in the expression and then changes it. This means that
in the case of prefix unary arithmetic operators, the compiler first uses the current value of the operand
and then changes its value in the expression.
o Syntax: <variable_name>++ / <variable_name>
o For example, int a = 1; printf(“%d”, a--); In the above printf() statement, a-- first sends the current value
of a to printf(), and then decrements the value of a to 0. Thus number 1 gets printed. Subsequently, if you
try printing the value of a, it will print 0.
o The postfix operator is higher in precedence than the prefix operator.
4. Relational operators
• Relational operators are used to define relations between variables and constants. They compare numeric values
to determine if one is greater than, less than, equal to, or not equal to another. The result of the comparison is
either 1 (True) or 0 (False). The following are the different relational operators:
o a == b -> checks whether a is equal to b
o a != b -> checks whether a is not equal to b
o a < b -> checks whether a is less than b
o a > b -> checks whether a is greater than b
o a <= b -> checks whether a is less than or equal to b
o a >= b -> checks whether a is greater than or equal to b
• All of the relational operators have the same precedence and are left-to-right associative.
• We have to keep in mind that for a C compiler, the value 0 is considered False, whereas any non-zero value is
considered True, although relational operators result in value of 1 in case the expression is True.
• For example, consider the code given below. In the 7th relational expression, note that 2 >= -1 results in a value of
1, and eventually, -1 < 2 results in a False, which results in a value of 0.
5. Logical operators
• Logical operators are used for defining logical relationships between Boolean expressions in C. The word Boolean
means it can take only two values, either a 1(True) or a 0 (False). The following are the different logical operators:
o Logical AND denoted by && expr1 && expr2: This returns True when both the Boolean expressions
evaluate to True.
o Logical OR denoted by | expr1 || expr2: This returns True when at least one of the Boolean expressions
evaluates to True.
o Logical NOT denoted by ! !(expr): This returns True if expr is zero or False and returns False if expr is non-
zero or True.
• Logical operators always result in 1(True) or 0 (False).
• All logical operators have the same precedence and are left-to-right associative.
When there are multiple operators with different precedence, then we use operator precedence to determine which
operation is to be performed first. On the other hand, when two operators of the same precedence appear in an
expression, then we use operator associativity. This associativity can be either Left to Right or Right to Left. Let us discuss
both of them in detail.
• In a C expression that contains more than one operator, the order of evaluation of the operators is decided by the
operator precedence rules in C. This helps the compiler to disambiguate the order of evaluation of operators. For
example, 2 + 3 * 6 can be interpreted as (2 + 3) * 6 = 5 * 6 = 30 or 2 + (3 * 6) = 2 + 18 = 20. The precedence rules in C
define that * should be evaluated prior to +, and thus the first interpretation is wrong, whereas the second one is
correct. Figure 1 shows the rules for operator precedence and associativity in C. The operators placed higher in
the table are given higher precedence as compared to operators placed on the lower side of the table. For
example, x = 2 + 3; + is higher than = in the table, and thus + is evaluated first, followed by =, and the result is that
x contains the value 5 after executing this statement.
Fig 1: Operator Precedence and Associativity rules in C (Source: lookuptables.com)
• In an expression, operators with the same precedence level are evaluated in the order specified by associativity
rules. For example, in the expression 2 * 3 / 6, * and / have the same precedence. Their associativity is from left to
right, i.e., the leftmost occurring operator in the given expression will be evaluated first, then the second left, and
so on, and the rightmost operator will be evaluated at last. In 2 * 3 / 6, * is evaluated first, which gives 6 / 6, and
then / is evaluated to give 1.
• Another example: 2 > 3 >= 2. Both > and >= have the same precedence. Thus, they are evaluated by the order of
their associativity (left to right). Firstly 2 > 3 evaluates to a 0 (False). Now the compiler will consider the value 0 for
the next relational operation. So, 0 >= 2 will compute to a 0 (False).
• C does not define the order in which the operands of an operator will be evaluated. This means that if there is an
expression of the form (exp1) op (exp2), then there is no pre-defined order of evaluation of the expressions exp1
and exp2, i.e., either of the two expressions can be evaluated first. For example, consider the code below:
Here, for the operator / whether the left operand (a+3) would be evaluated first or the right operand (c*2) would be
evaluated first is not defined.
Example Program to Convert a Given Temperature from Fahrenheit Scale to Celsius Scale
Let f represents the temperature in Fahrenheit scale, and c represents the temperature in Celsius scale. Both are related
to each other by the relationship given by c = (f - 32)/1.8
Now, if we consider giving input as Fahrenheit = 100, then after applying the operator precedence and associativity rules
to the expression, Celsius = (Fahrenheit – 32)/1.8, we will get the output of Celsius temperature as 37.777779.
Fig 2: C Program to convert temperature from Fahrenheit scale to Celsius scale
Reading Summary:
• Operators and operands and how they are combined to form an expression
• The five types of operators in C, i.e., arithmetic operators, assignment operators, logical operators, relational
operators, and unary operators
• Precedence and associativity rules to evaluate expressions in C in an unambiguous manner
4 A Taste of C
WHAT TO LEARN
The three-phase compilation process that transforms a C source program to machine code.
Use of sequence, decision making and repetition in programs.
Handling simple errors generated by the compiler.
Role of functions in making programs modular.
Working knowledge of the printf and scanf functions.
Macro view of the features of the C language.
Commonly used styles that make programs readable and maintainable.
Standardization efforts that have made C stable and acceptable.
Institute (ANSI) stepped in to standardize the language. The ANSI standard removed the system
calls from UNIX C and retained a subset of the original language. This subset is now common to
all systems, and in this book, we’ll stick to this subset, which will be variously referred to as ANSI C,
C89 or C99, the nomenclature used by ANSI.
C is a simple but powerful third-generation language. Its rich library of functions enables the
development of modular applications. Its support of a variety of constructs for decision making
(if and switch) and repetition (while, for and do-while) also makes it suitable for structured
programming. But the language derives its power from the vast arsenal of operators that permit
low-level operations like (i) direct access to memory, and (ii) manipulation of every bit in memory.
In this respect, C is somewhat akin to a second-generation language like assembly language.
Today, C is widely adopted for developing a diverse range of both application and system software.
Compilers for many languages (including C) are written in C. Since C programs are compact and
efficient, it is the preferred language for software running on small devices like mobile phones and
tablets. C has replaced BASIC and Pascal for introducing students to the programming world.
It has also influenced the development of object-oriented languages like C++, C# and Java.
It pays to know C because the language is not going to go away in a hurry.
Note: C can be considered to be both a high- and low-level language. While it is sufficiently low-level
to enable access to specific memory locations, it is also a high-level language with all the standard
constructs and operators found in any 3GL language.
Source code
foo.c (text file)
Preprocessor
Preprocessed code
foo.1 (text file)
Compiler
Assembly code
foo.s (text file)
Assembler
Object code
foo.o or foo.obj
(machine language)
Libraries
Linker
Executable code
Other object a.out or aout.exe or
files foo.exe
(machine language)
Loader
Program image
in memory
Does the compiler directly translate the source code to machine code? Some compilers (like the
Linux GCC compiler) find it more convenient to perform translation to assembly language first.
A separate program (the assembler) then converts the assembly language code to machine code.
The intermediate file is removed once the final machine code is created. However, GCC also
supports an option that retains the assembly code for use by assembly language programmers.
Note: The term compiler is used in two ways in C. It could mean the program that does the job
specified in the second phase, or represent a collective term that performs all of the three tasks.
The true meaning should be evident from the context, but when it is not, we’ll use the term compiling
software to refer to the collective meaning.
Takeaway: A program can have syntax errors (on account of wrong use of its grammar) or
semantic errors (because of faulty program logic). The former is detected during compilation
and the latter during program execution.
The standard library containing the object code of all functions that are part of ANSI C
(like printf).
An editor to edit programs and header files.
A debugger to locate semantic (runtime) errors in programs.
Compiling software is available in both CUI and GUI flavors. Command-line or CUI systems offer
separate programs for editing, processing and debugging. These programs are invoked by name
and they support several options or switches that change their default behavior. We won’t need to
use these options in this book though (except in Chapter 17).
GUI-based systems offer an Integrated Development Environment (IDE) where all actions are
invoked by the point-and-click mechanism of the mouse. IDEs are menu-based which dispenses
with the need to invoke commands by name. Behind the hood, however, these mouse clicks
internally invoke standalone programs. Generally, IDE systems also offer a CUI mode for those
(this author included) who prefer to invoke commands by name.
executable. Unlike other Windows compilers that generate aout.exe as the default executable,
Visual Studio names the executable after the source filename. The source file first_prog.c is
compiled to first_prog.exe.
Note: Windows executables have the .exe extension. Depending on the compiler used, the program
foo.c is converted to the executable aout.exe or foo.exe. Also note that Windows filenames are
not case-sensitive, so foo.c and FOO.C, which are treated as separate files by Linux, will create conflicts
when moved to Windows.
/* Preprocessor Section */
#include <stdio.h> /* printf needs this file */
#define PI 3.142 /* PI is a constant */
/* Program Body */
int main(void) /* This is where the action begins */
{
/* Variable declarations */
int radius = 5; /* Integer type */
float area; /* Floating point type */
/* Other Statements */
printf(“All numbers are stored in binary\n”);
printf(“Radius of circle = %d\n”, radius);
area = PI * radius * radius;
printf(“Area of circle having radius %d = %f\n”, radius, area);
area of type float (floating point). These C keywords, int and float, are two of the frequently used
data types in C. At this stage, we have no idea what the initial value of area is.
The next statement (area = PI * radius * radius;) uses the multiplication operator, *, to calculate
the area of a circle. The result is then assigned to the variable area. Note that the compiler doesn’t
see PI, but 3.142, since the preprocessor has already made this substitution. We have now seen the
use of two members (= and *) of C’s vast arsenal of operators.
Note: All variable declarations should be made at the beginning—after the preprocessor directives
and before the statements.
The main Function Is printf the only C function we find in this program? No, we should have
known that the word main is actually a function; it too is followed by a pair of parentheses. For now,
let’s simply note that every program has a main function which is automatically invoked to execute
the statements in the program body. We will discuss this function in Section 11.15.
GUI Mode The Build menu in the Menu bar has all the necessary options for compilation and
execution. In this mode, you need to invoke the compile and link phases separately:
Preprocess and Compile Use Build > Compile first_prog.c and observe the window pane at the
bottom. If you see compilation errors, note their line numbers, edit the source file and repeat
the compilation. You may ignore the warnings for the time being. On successful compilation,
you should see the message first_prog.obj - 0 error(s), signifying that the object file,
first_proj.obj, has been created. This file contains machine code but is not ready to run
because it contains unresolved references (3.15).
Link Linking is done with Build > Build first_prog.exe, when you should see the message
first_prog.exe - 0 error(s). The executable, first_prog.exe has been created.
You can now run this executable with Build > ! Execute first_prog.exe. A new window will open
up with the output of the program. The screen dumps of these activities are shown in Figure 4.2.
Tip: Visual Studio offers shortcuts for all three activities: [Ctrl][F7] for compiling, [F7] for linking
and [Ctrl][F5] for executing. Also, you’ll find separate icons representing these activities in one of
the toolbars.
CUI Mode Invoke the MSDOS shell or command prompt (using Run > cmd) and then invoke
the following command:
C:\> cl first_prog.c
/out:first_prog.exe
first_prog.obj
The program cl.exe invokes link.exe to create the executable, which can then simply be run like
this:
C:\> .\first_prog Note the .\
All numbers are stored in binary
Radius of circle = 5
Area of circle having radius 5 = 78.550003
The output is correct, which means there are no semantic errors in the program. In case you
encounter errors, locate the line numbers provided in the error messages to edit the source code.
Recompile the program and re-execute first_prog.exe. Handling error messages is taken up in
Section 4.6.
Note: The standalone executable (a.out or first_prog.exe) can now run on this and similar machines
even if the C compiler is not installed on these machines.
Did the compiler get the line number wrong? Not really; it’s just that the missing ; on line 17 lured
the compiler into assuming that lines 17 and 18 constituted a single statement. Since the statement
terminator is a semicolon, the compiler keeps scanning until it finds one.
A Taste of C 133
Visual Studio also displays a similar message, but it generates a warning as well:
first_prog.c(16) : warning C4244: ‘=’ : conversion from ‘double ‘ to ‘float ‘,
possible loss of data
first_prog.c(18) : error C2146: syntax error : missing ‘;’
before identifier ‘printf’
Error executing cl.exe.
first_prog.obj - 1 error(s), 1 warning(s)
This warning will make sense after you have learned that, like variables, constants have data types
(5.1.2). Here, the constant PI has the type double, which on this machine is longer than float.
The compiler is worried at the possible loss of information that could be caused by assigning
a value of a larger type (double) to a variable (area) of smaller type (float). A warning is not an
error and the code will still compile. However, you should know what you are doing, so after some
time, you should be able to handle these warnings as well.
The omission of the ; at the end of a C statement is an example of a syntax error. A syntax error
occurs when a statement fails to conform to the rules of the C language. The compiler doesn’t
generate the executable when such an error occurs. The previous error message helped us locate
the offending line without any problem, but some errors could be a little difficult to locate.
However, even if you manage to successfully clear the compilation and linking phases, your
program may still not behave in the manner intended. You may have entered = instead of == (both
are valid C operators), or 65 instead of 65.0. These are semantic errors which signify errors in
meaning. For instance, if (x == 5) is not the same as if (x = 5), even though both are syntactically
correct. Semantic errors are encountered only at runtime, i.e., when the program is actually run.
The compiler doesn’t detect them; it’s your job to do that—using a debugging program if necessary.
Tip: Syntax errors are normally located early, but semantic errors can often be difficult to identify.
These errors may not show up in every invocation of the program simply because some data may
cause problems but some may not. Pay attention to the warnings; they often provide valuable clues.
WHAT TO LEARN
Constants represent data that don’t change. In the expression (fahrenheit - 32) / 9.0, both
32 and 9.0 are constants. The first argument used with printf is often a string constant, say,
“Printing ASCII list”. Like variables, constants also occupy space in memory. These constants
have no names, but later in the chapter we’ll encounter constants that have names. We’ll also have
a look at variables that behave like constants.
5.2 VARIABLES
A variable is a name given to a memory location that is accessed by that name to fetch or set
a value at that location. Variable usage is either mandatory or compelling. For instance, if a while
loop has to execute a finite number of times, you need a variable to determine when the loop will
terminate (mandatory). On the other hand, if the rupee-dollar conversion rate is used multiple
times in a program, then this value is better stored in a variable (compelling). Here, the variable
behaves like a constant while the program is running.
5.2.1 Naming Variables
The rules for framing variable names apply to all identifiers, which include arrays and functions.
A variable name can begin with a letter or the underscore (_) character, but the remaining part of
the name can comprise only the following characters:
150 Computer Fundamentals & C Programming
Tip: Use meaningful lowercase names for variables. Names like x and abc are valid, but they don’t
intuitively reveal what they represent—unlike variables like sampling_speed and conversion_rate.
to be interpreted as a single binary number. This knowledge is vital because a chunk of 4 bytes can
be interpreted as an integer, a floating point number or a three-character (not four) string.
The value of an uninitialized integer variable is indeterminate (i.e., junk); it can’t be assumed to
be zero. The value is actually one that was resident in memory when the program was executed.
Never use an uninitialized variable in an expression!
Tip: Even though a variable declaration can occur anywhere in a program as long as it precedes
usage, it is good programming practice to bunch all declarations immediately after main. However,
global variables (differerent from the ones discussed here) have to be declared before main (14.8).
/* ... and also reassigned, this time with the scanf function */
printf(“Now key in any real number: “);
scanf(“%f”, &float_x1);
printf(“float_x1 = %f\n”, float_x1);
return 0;
}
The derived types are variations of the fundamental types. C also allows you to define your own data
types for handling complex data. However, the language doesn’t have a separate type for strings.
In this chapter, we’ll discuss the fundamental types and briefly understand how C implements
a string.
ANSI’s endorsement of the K&R C prescription (the first C definition from Kernighan and
Ritchie) of minimum sizes needs to be kept in mind when developing portable applications.
Even though ANSI specifies the minimum size of int as 2 bytes, your machine will in all probability
have a 4-byte int. And if portability is not a concern, there is no reason why you shouldn’t take
advantage of this enlarged size.
The sizeof operator evaluates the size of all data types—the fundamental types, pointers, arrays
and constants. This is how you can find the size of the int data type on your computer:
printf(“Size of int: %d\n”, sizeof(int));
This should print 4 on your PC. Note that sizeof is not a function even though it looks like one.
It is an operator (like = and +) which works on an operand, which here is enclosed within parentheses
in function-like manner. The next program uses sizeof both with and without parentheses.
Takeaway: There are no fixed sizes for the fundamental data types, but only ANSI-specified
minimum sizes. This was done to protect the applications that were developed prior to the
ANSI standard.
Takeaway: You can’t be assured of seeing a fixed size for any type, but ANSI guarantees
a minimum size. It also specifies a relationship between the sizes.
bytes used by unsigned short can represent values between 0 and 216 - 1, i.e. 65,535. This range
changes to -32,768 to 32,767 (-215 to 215 - 1) for signed short.
Table 5.1 displays the essential attributes of these integers, their unsigned maximum values and
the format specifiers used by printf and scanf for handling them. Note that the unsigned format
specifier has the d replaced with u. Thus, %ld becomes %lu, %d becomes %u, and so forth.
Note: The basic format specifier for the signed integer data type is %d. A modifier is needed for
short (h), long (l) and long long (ll). For unsigned types, replace %d with %u with the same modifiers
as considered necessary. The complete list of these specifiers used by printf and scanf can be found
in Chapter 9.
158 Computer Fundamentals & C Programming
The last two printf statements use wrong format specifiers. We first printed a negative integer with
%u, the specifier meant for unsigned int. We then printed the new value of int_x (123456) with %hd,
the specifier meant for short. This number also exceeds the maximum value that can be handled
by short. Both statements output junk values.
Note: The last two printf statements use symbols like %%d and %%u to print the strings %d and %u,
respectively. Because % is interpreted in a special manner (the specifier prefix) by printf, the only
way to literally print a % is to prefix it with another.
int main(void)
{
short short_x = 32767; /* Signed -- uses 15 bits */
int int_x = -65; /* Signed -- uses 31 bits */
unsigned long long_x = 400000; /* Unsigned -- uses 32 bits */
return 0;
}
The numeric value stored in a char variable can easily be displayed in its equivalent character
form and vice versa.
Strings owe their origin to char. A string is simply an array of type char.
The first point implies that the value 65 stored as a char can be printed as A by printf using %c.
Conversely, the character A input from the keyboard can be saved in a char variable as 65 by scanf
using %c. Data of type char can also be represented in two other ways:
By a character enclosed within single quotes (e.g. ‘A’).
By a special escape sequence like ‘\c’, but only a handful of non-printable characters can be
represented by an escape sequence.
Like the other integer types, char occurs in signed and unsigned forms. The signed form can hold
values between -128 to 127, while the range for the unsigned type is 0 to 255. Unlike the other
integer types, which are signed by default, the default type of char is system-dependent. So, if you
need to store an 8-bit ASCII character, specify the data type explicitly as unsigned char.
char let1 = ‘A’; short let2 = 97; char let3 = ‘9’; int let4 = 7;
Code Output
printf(“‘%c’ = %d\n”, let1, let1); ‘A’ = 65
printf(“‘%c’ = %d\n”, let2, let2); ‘a’ = 97
printf(“‘%c’ = %d\n”, let3, let3); ‘9’ = 57
printf(“‘%c’ = %d\n”, let4, let4); ‘’ = 7
The number 7 is stored in memory as (0000 0111)2. But ‘7’ is a character, whose ASCII value (55)
is stored as (0011 0111)2. When you input 7 from the keyboard in response to a scanf call, it’s ‘7’
that is sent to the keyboard buffer (4.8.2—How It Works). The %d specifier tells scanf to convert
‘7’ to 7 (if the intent was to use an integer).
You can use octal and hexadecimal numbers too. Simply precede the number with 0 and 0x,
respectively:
char c = 0101; 101 = 1 ¥ 82 + 0 + 1 ¥ 80 = 65
char c = 0x41; 41 = 4 ¥ 161 + 1 ¥ 160 = 65
Beginners often make the mistake of using double quotes (“A” instead of ‘A’). Double-quoted
characters (like “A” or “Internet of things”) represent a string, which is not a fundamental data
type. C understands a string as an array (a derived data type) of type char, but more of that later.
Data—Variables and Constants 165
Note: In C, ‘A’ is different from “A”. The former is a character and the latter is a string. This string
has two characters (and not one), which may puzzle you now but not after you have read
Section 5.15.
Note: Because letters and numerals occur in a contiguous sequence (but in separate blocks) in the
ASCII list, it’s convenient to sort words and lines containing these characters. A simple while loop
can print a list of all letters or numerals.
Note: You can use a leading zero to represent an octal or hexadecimal character, but only when the
character is embedded in a string. Thus, “Wake up\a”, “Wake up\07” and “Wake up\7” are equivalent.
#include <stdio.h>
int main(void)
{
char schar = 250;
unsigned char uchar = 250;
char letter = ‘A’; int numeral = ‘9’;
Between the two loops, a printf statement demonstrates the use of the \ and escape sequences.
A \t shifts the cursor by eight spaces, so using two of them offsets the line by 16 spaces. If your
terminal supports the beep sound, you’ll hear a beep as well (\07).
Note: You must know the distinction between ‘A’, ‘APE’, “A” and “APE”. ‘A’ is a character constant
whose ASCII value (65) is stored as a binary number. ‘APE’ is not a valid character constant because
only the last character (‘E’) is stored. “A” and “APE” are legal strings, occupying two and four
characters in memory, respectively. Why an extra character for the strings? Read on.
168 Computer Fundamentals & C Programming
For instance, the compiler, which otherwise sees 3 as an int, treats 3L as a long. There are no
constants of type short. Next time you see the constants 540U or 450L, remember to treat them as
unsigned int and signed long, respectively.
Floating Point Constants C treats a real constant as a double which takes up 8 bytes on most
systems. Constants like 3.142 and 1789.456 have the type double even though a float (4 bytes) is
wide enough for them. However, unlike integer constants which can only be promoted to long and
long long, real constants can be both promoted and demoted:
The F or f suffix demotes a real constant to float. The constants 3.142f and 1789.456F have
the type float.
The L or l (el) suffix promotes a real constant to long double, which may take up to 16 bytes.
These suffixes work with the exponential form also (like 3E4F). Demoting a constant to float often
makes sense because it leads to savings in memory space and computation time.
Character Constants Any character or escape sequence enclosed in single quotes represents
a character constant. The characters ‘A’, ‘\t’ and ‘\7’ are character constants having the ASCII
values 65, 11 and 7, respectively. Strangely enough, C treats character constants as type int rather
than char. This means the constant ‘A’ is stored in a space of 4 bytes (size of int).
Takeaway: The default type for an integer constant is int. For a real number, the default
is double. A character constant is stored as an int. C doesn’t support a constant of
type short.
The const qualifier protects a variable from being rewritten by marking it read-only. You’ll often
see this qualifier in the syntax of many C string-handling functions.
is not used for the constant.) If the value of a constant doesn’t change elsewhere in the program or
when the program is running, why use a variable at all? However, the topic appropriately belongs
to Chapter 17 which discusses preprocessor directives.
Tip: If you need to use a constant repeatedly in a program, either define it as a symbolic constant
or declare it as a variable using the const qualifier.
int main(void)
{
char letter = ‘A’;
printf(“Size in bytes of the fundamental data types on this machine:\n”);
printf(“int: %d, long: %d, float: %d, double:% d, long double: %d\n”,
sizeof(int), sizeof(long), sizeof(float),
sizeof(double), sizeof(long double));
printf(“\nSize of constants on this machine:\n”);
printf(“Size of 34 = %d bytes\n”, sizeof 34);
printf(“Size of ‘A’ = %d bytes\n”, sizeof ‘A’);
printf(“Size of letter which is set to ‘A’ = %d byte\n”, sizeof letter);
printf(“Size of 34L = %d bytes\n”, sizeof 34L);
printf(“Size of 3.142 = %d bytes\n”, sizeof 3.142);
printf(“Size of 3.142F = %d bytes\n”, sizeof(3.142F));
printf(“Size of 3.142L = %d bytes\n”, sizeof(3.142L));
printf(“Size of LOOP_VAR = %d bytes\n”, sizeof(LOOP_VAR));
WHAT TO LEARN
6.1 EXPRESSIONS
Variables and constants represent data in their most elemental form. These data objects become
useful when combined with one another to form expressions. The components of an expression
are linked to one another by symbols called operators. For instance, a + b / 7 is an expression
where + and / are operators. The expression has a value which here is evaluated arithmetically.
An arithmetic expression is not the only type of expression you’ll encounter in C. There are other
types—like relational and logical expressions. For instance, a > b is not an arithmetic expression
but it still has a value. The following examples illustrate the diversity of expressions used in C:
C Construct Expression
interest = principal * rate / 100; principal * rate / 100 (arithmetic)
if (age > 18) age > 18 (relational)
while (answer == ‘y’) answer == ‘y’ (relational)
if (age > 15 && age < 25) age > 15 && age < 25 (logical)
(Continued)
Operators and Expressions 179
(Continued)
C Construct Expression
while (count-- >= 0) count-- >= 0 (relational)
answer = ‘y’; answer = ‘y’ (assignment; also an expression)
++count; ++count (expression without operators)
if (count) count (Ditto; simplest expression)
Except for the last one, all of these expressions use one or more operators. The simplest expression,
however, uses no operators. This means that the variable count and the constant 5 are two valid
expressions. This all-embracing view of expressions may seem trivial but it has important
consequences, as you will gradually discover.
Every C expression has a value and the significance of this value depends on the nature of the
expression. For an arithmetic expression (like a + b) it’s the computed value that interests us.
But relational expressions (like age > 18) evaluate to either of two boolean values, which we
interpret as true (value > 0) or false (value = 0).
6.2 OPERATORS
Operators form the connecting link between variables and constants in expressions. An operator
acts on one or more operands. For instance, in the expression x - 5, the - symbol is an operator,
which acts on the operands x and 5. C supports a rich collection of operators—richer than any
language known previously. These operators can be grouped into the following types:
Arithmetic operators (like +, -, etc.)
Assignment operators (like =, +=, -=, *=, etc.)
Increment and decrement operators (++ and --)
Relational operators (like >, <, <=, etc.)
Logical operators (&&, || and !)
Bitwise operators (like &, |, >>, <<, etc.)
The comma, sizeof and cast operators
An operator may be unary, binary or ternary. A unary operator has one operand. For instance,
the - symbol in the negative constant -5 is a unary operator which multiplies its operand by -1.
(The unary - is different from the binary - which performs subtraction.) The ++ in count++ is
a unary operator which increments its operand by one.
Most operators are of the binary type which needs two operands. The assignment operator = in x = 5
is a binary operator. Arithmetic operators like * and / and relational operators like > and < are also
binary operators. C has one ternary operator which uses the ? and : symbols.
When an expression contains multiple operators, the order of their evaluation becomes important.
For instance, when evaluating the expression x + y * z, does multiplication occur before addition?
For this purpose, C specifies two attributes for each operator:
180 Computer Fundamentals & C Programming
The precedence (priority) ensures that a high-priority operator is acted upon before
a low-priority one. In the expression x + y * z, the * has a higher precedence than +, so
multiplication will be done first.
The associativity determines the direction of evaluation (left-to-right or right-to-left). In the
expression x * y / z, it is associativity and not precedence that determines that multiplication
will be done first. You may think that it doesn’t matter, but if y and z are integers, then it
definitely matters (6.10.3).
These two attributes will be examined in detail later in the chapter. It’s important that you understand
them completely because a little learning in this area would certainly be a dangerous thing.
Note: The constant 5 is an expression but 5; is a valid statement. Since many functions return a
value, they can also be considered as expressions. The printf function returns a value and so can
be used anywhere an expression is used. Our first program, expressions.c, clearly demonstrates this.
This represents the well-known formula that converts temperatures between Celsius and Fahrenheit.
The constant -40.0 represents the temperature in Celsius. This is how C evaluates the expression:
1. Among these operators, the unary operator, -, has the highest level, so C first multiplies 40.0 with -1.
2. The sub-expression, -40.0 * 9 / 5 is then evaluated because the * and / have a higher priority
than the binary +. Here, we have two operators belonging to the same level. For reasons of
associativity that will be explained later, C performs the multiplication before the division, but
before doing so, it promotes the type of 9 to double (the type of -40.0).
3. The sub-expression at this stage has the value -360.0 which has to be divided by 5. C now
promotes the type of 5 (by default, int) to double also. Division of -360.0 by 5.0 yields -72.0.
4. C now performs the addition operation, but only after promoting the type of 32 to double. The
final result is 32.0 + -72.0 = -40.0.
Operators and Expressions 189
5. The = operator has the lowest precedence in our list, so the result of the previous operation is
finally assigned to fahrenheit. If fahrenheit is of type double, the right-hand side needs no
conversion, but if it is a float, then the expression will be converted to float before assignment.
This could lead to truncation but not with the value that we are working with.
Here, the expression -40 - 32 is evaluated first (but after multiplying 40 by -1). In the absence
of parentheses, -32 would have been multiplied by 5 first. This would have resulted in erroneous
evaluation.
Note: The expression -40 - 32 needs two operations for evaluation and not one. The first - is the
unary minus which multiplies 40 by -1. 32 is next subtracted from the result. However, C treats
-40 -32 and -40 - 32 as equivalent.
Takeaway: Operator associativity becomes a determining factor only when two operators
having the same precedence share an operand. When equal-priority operators don’t share an
operand, the outcome is implementation-dependent but it won’t lead to an error. An exception
can be made when using the logical operators (6.16).
Note: Table 6.2 lists all operators featured in the 17 chapters of this book. The bitwise operators
(discussed in Chapter 17) are included in the complete version of the table (Appendix A).
Part 1 This part features three simple expressions that use the arithmetic operators. It’s now
a given that * and / have a higher precedence than + and -. But in the expression used for a leap
year check, note that year % 4 is computed before the subtraction because % has a higher precedence
than -.
Part 2 Refer to Part 2 of Program 6.3 (implicit_conversion.c), where we noted that the constant
1.0 must be placed at the beginning of the expression to prevent truncation in division. We have
achieved the same result here by placing the variable celsius before 9 / 5. The explanation is
simple: since / and * have the same precedence and L-R associativity, celsius * 9 is evaluated first
(but only after 9 has been converted to double).
192 Computer Fundamentals & C Programming
Tip: If you encounter an expression in the form b / c or b / c * a, where b and c are of type
int and a is of type float, you can easily prevent truncation of the decimal part. For b / c, either
multiply the expression by 1.0 at the beginning or use a cast for b or c. For b / c * a, rearrange
the operands to have a * b / c, in which case a cast is not necessary.
This statement represents two separate tasks performed with a single operator. The += evaluates the
expression count + 5 before assigning the result to count. The evaluation is considered to be the
“main” task and the assignment is interpreted as a side effect. The other two-character assignment
operators (like -=) and the operators, ++ and --, also have side effects. Like the =, all of these
operators have low precedence and R-L associativity.
TABLE 6.3 The Assignment Operators
Operator Example Equivalent to
= count = 5; -
+= count += 3; count = count + 3;
-= count -= 3; count = count - 3;
*= count *= 4; count = count * 4;
/= count /= 4; count = count / 4;
%= count %= 5; count = count % 5;
count = 10;
while (count-- > 0) Loop executes 10 times
count = 10;
while (--count > 0) Loop executes 9 times
In Chapter 8, you’ll acquire the skill to handle this difference of 1 that arises between the prefix
and postfix operations.
Part 2 Unlike the technique used in Program 6.2, this program uses a while loop to calculate
the sum of the first 100 integers. The loop repeats as long as inta is less than LAST_INT + 1.
To know the sum of the first 200 integers, simply change the #define directive.
Part 3 This part calculates the power of a number (basepower), where base and power are integers
taken from user input. Because the *= repeatedly multiplies base by itself, total2 progressively
acquires the following values: 1, base, base * base, base * base * base, and so on. Note that this
while loop increments intb and checks its value in the same expression. Amazing power of C!
Note: Even though we tend to think of 1 and 0 as true and false values, respectively, the term true
actually represents any non-zero value. Thus, the minimalist expression 5 is always true.
This expression, which owes its origin to Kernighan and Ritchie, is commonly used inside a while
loop to repeatedly invoke the getchar function to read a character from a file or the terminal. Here,
the return value of getchar is assigned to c, which is then checked for non-equality with a symbolic
constant. This expression has the side effect of reading a character every time it is evaluated.
198 Computer Fundamentals & C Programming
if (a == 0 && b == 0) {
printf(“Both integers are zero\n”);
return 1; Intelligent use of return value
}
A compound expression can include more than one logical operator. The following expression
evaluates to true when all of the relational expressions also evaluate to true:
a <= 0 && b <= 0 && c <= 0
Compound expressions like the one above are useful only when we don’t want to know the precise
reason of failure; it’s either a, b or c, that’s all we care to know. Sometimes, you may need to make
separate decisions for each of three possible outcomes. In that case, you need to use a separate
if statement with each expression.