Programming Concepts and Logics

Unit 5 · 8 teaching hours · 51 min read

Programming Concepts and Logics

What the syllabus asks for 16
  • Introduction to programming languages; Low level, High level, 4GL
  • Compiler, Interpreter and Assembler
  • Syntax, Semantic and Runtime errors
  • Control Structures: Sequence, Selection and Iteration
  • Program Design tools: Algorithm, Flowchart and Pseudocode
  • Absolute binary, BCD, ASCII and Unicode
  • C: Introduction and features; Structure of C program
  • C Preprocessor and Header Files; Character Set; Comments
  • Identifiers, Keywords and Tokens; Basic Data Types; Constants and Variables
  • Type Specifier; Simple and Compound Statements
  • Operators and Expressions: arithmetic, relational, logical, assignment, unary, conditional
  • Input/Output Functions
  • Selection Control Statement: if, if-else, if-else-if, nested, switch
  • Iteration Control Statement: while, do while, for, nested loops
  • Array: definition, 1D and 2D, matrix addition and subtraction
  • String: definition and string functions strlen, strcat, strcmp, strrev, strcpy, strlwr, strupr

A computer does nothing on its own. Every useful thing it does — adding a column of marks, drawing a chart, sending a message — happens because somebody wrote an ordered list of instructions and the machine carried them out. This unit teaches you to write that list. You will first learn to think the solution out on paper as an algorithm and a flowchart, and only then to write it in C, the language the NEB course uses. Everything in Grade 12 programming is built on this unit, so do not just read the programs — type them, compile them, break them and fix them.

What the examiner wants from this unit

Two kinds of marks live here. The theory marks are definitions and comparisons: compiler vs interpreter, the three kinds of error, the three control structures, algorithm vs flowchart vs pseudocode, ASCII vs Unicode. The programming marks want working C code — a full program with #include, main(), declarations, the logic, and return 0;. Write the whole program, not a fragment. A flowchart question always wants the correct shapes: oval for start/stop, parallelogram for input/output, rectangle for process, diamond for decision.

5.1 Introduction to programming languages; low level, high level and 4GL

Program and programming language

A program is a finite set of instructions, written in a defined order, that tells a computer how to solve a particular problem. A programming language is the set of symbols, words and rules (its syntax) used to write such programs.

Languages are classified by how close they sit to the machine.

Machine language (1GL) is pure binary — the only language the CPU actually understands. An instruction such as 10110000 01100001 means "move 97 into register AL" on an x86 processor. It runs directly, with no translation, and is therefore the fastest, but it is almost impossible for a human to read, write or debug, and a program written for one processor will not run on another.

Assembly language (2GL) replaces those bit patterns with short mnemonics — MOV, ADD, SUB, JMP — and lets you name memory locations. MOV AL, 61h is the same instruction as above. It still maps one line to one machine instruction, so it is still machine dependent, but it can be read. An assembler translates it to machine code. Assembly is used today for device drivers, embedded microcontrollers and small time-critical routines.

Machine and assembly language together are called low-level languages.

High-level languages (3GL) — C, C++, Java, Python, FORTRAN, COBOL, BASIC — use ordinary English words and ordinary algebra. One statement such as area = 3.1416 * r * r; becomes many machine instructions. They are machine independent: the same source file compiles and runs on a laptop in Butwal and on a server in Singapore. They need a compiler or interpreter, and the code they produce is usually a little slower and larger than hand-written assembly.

Fourth-generation languages (4GL) go one step further: you state what you want, not how to get it. SQL is the standard example —

SELECT name, marks FROM students WHERE marks > 80 ORDER BY marks DESC;

says nothing about loops or comparisons, yet a whole search is performed. Other 4GLs include report generators, spreadsheet formulas, MATLAB and Oracle Forms. 4GLs are very fast to write and are used by non-programmers, but they are specialised — you cannot write an operating system in SQL.

Generation Name Written as Translator Machine dependent?
1GL Machine language 0s and 1s none Yes
2GL Assembly language mnemonics (MOV, ADD) assembler Yes
3GL High-level language English-like statements compiler / interpreter No
4GL Very high-level / query what, not how (SQL) interpreter / engine No
5GL Logic / AI languages constraints and facts (PROLOG) inference engine No

figure
Figure 1. Levels of programming language. The higher you go, the closer the language is to human thought and the further it is from the hardware; the more translation is then needed before the CPU can run it.

5.2 Compiler, interpreter and assembler

A CPU can execute only machine code, so every program written in any other language must be translated. The three translators differ in what they translate and how much they translate at a time.

The three language translators

An assembler translates assembly language into machine language.

A compiler translates a complete high-level source program into machine code (an object/executable file) in one go, reporting all the errors it finds, and the resulting file is then run on its own.

An interpreter takes the high-level source program and translates and executes it one statement at a time, stopping at the first error.

figure
Figure 2. What a compiler does compared with an interpreter. The compiler produces a standalone executable that the user runs without the source; the interpreter keeps translating the same source every time the program is run.

Compiler Interpreter
Unit translated whole program at once one statement at a time
Errors reported all errors of the whole program together stops at the first error
Output file produces an object/executable file produces no separate file
Speed of execution fast (translated once, then just runs) slow (retranslates every run)
Memory needed more (object code is stored) less
Debugging harder — errors listed away from the run easier — you see exactly where it stopped
Source needed at run time? No Yes
Examples C, C++, Java (to bytecode), Pascal Python, BASIC, Ruby, JavaScript, PHP

In real life a C program goes through four steps: preprocessing (handling the lines that begin with #), compiling (C to assembly/object code), assembling, and linking (joining your object code to the library code for printf and friends) to make the final executable. An Integrated Development Environment (IDE) such as Dev-C++, Code::Blocks or Turbo C hides all four behind one "Compile and Run" button.

photograph
1Menu bar — File, Edit, Execute (Compile, Run, Compile & Run)2The compiler this project uses — here TDM-GCC 9.2.0, the same GCC family used to test every program in this chapter3Editor window with automatic line numbers and colour-coded syntax4Compile Log tab — read this first when something goes wrong5Errors: 0, Warnings: 0 and the name of the .exe that was produced. Anything other than 0 errors means no program was built
Figure 3. A real C program in the Dev-C++ IDE. The compile log at the bottom is what you must learn to read: it reports the number of errors, the name of the executable that was produced, and how long compiling took. Source: OxyLight / Wikimedia Commons (CC BY 4.0)

5.3 Syntax, semantic and runtime errors

An error in a program is called a bug, and removing it is debugging. There are three kinds, and telling them apart is an exam favourite.

A syntax error breaks a grammar rule of the language — a missing semicolon, an unclosed brace, a misspelt keyword. The compiler catches every one of them and refuses to produce a program at all. Here is a real one. The semicolon after b = 3 is missing:

#include <stdio.h>
int main(void)
{
    int a = 5, b = 3
    printf("%d\n", a + b);
    return 0;
}

GCC replies:

e1.c: In function 'main':
e1.c:5:5: error: expected ',' or ';' before 'printf'
    5 |     printf("%d\n", a + b);
      |     ^~~~~~

Notice that the compiler blames line 5, but the mistake is on line 4. A compiler reports where it first noticed trouble, not where you made it: always look at the line above as well.

A semantic error (also called a logical error) is grammatically perfect but says the wrong thing. The program compiles, runs, and quietly prints nonsense. This program converts Celsius to Fahrenheit with the fraction upside down:

f = c * 5 / 9 + 32;          /* wrong: should be c * 9 / 5 + 32 */

With c = 37.0 the correct formula prints 37.0 C = 98.6 F, while the wrong one compiles without a single complaint and prints:

37.0 C = 52.6 F

No tool will find this for you. Only testing with values whose answer you already know will.

A runtime error appears only while the program is running, when it is asked to do something impossible — divide by zero, open a file that does not exist, use an array index that is out of range, or run out of memory. This program is perfectly legal C:

scanf("%d %d", &a, &b);
c = a / b;

With the input 20 4 it prints a / b = 5. With the input 20 0 the program crashes; on Linux the shell reports:

Floating point exception
"It compiled" does not mean "it is correct"

A clean compile only proves that your grammar is right. Marks in the board exam are given for a program that produces the right output, so always hand-trace your program with one small test value before you write it out in the answer sheet.

Syntax error Semantic (logical) error Runtime error
When found at compile time never automatically while running
Program produced? No Yes Yes
Example missing ;, prinf for printf wrong formula, < for > divide by zero, bad array index
Who finds it the compiler the programmer, by testing the user, usually

5.4 Control structures: sequence, selection and iteration

Control structure

A control structure is a block of code that decides the order in which the statements of a program are executed. The structured programming theorem states that any program, however complicated, can be written using only three of them: sequence, selection and iteration.

  • Sequence — statements are carried out one after another, top to bottom, exactly once each.
  • Selection (branching) — a condition is tested and one of two or more paths is taken. In C: if, if-else, if-else-if, switch.
  • Iteration (looping/repetition) — a block is repeated while a condition holds. In C: while, do-while, for.

figure
Figure 4. The three control structures drawn as flowchart fragments. Every one has exactly one way in and one way out, which is why they can be stacked and nested without the logic becoming tangled.

5.5 Program design tools: algorithm, flowchart and pseudocode

Before any code is typed, the solution is designed. Three tools are used, and the NEB paper may ask for any of them.

Algorithm, flowchart, pseudocode

An algorithm is a finite, ordered sequence of clear, unambiguous steps that solves a problem in a finite time. It is written in plain English and numbered.

A flowchart is the pictorial representation of an algorithm, drawn with standard symbols joined by flow lines.

Pseudocode is a half-way language: the structure of a program written with programming keywords (IF, WHILE, ENDIF) but with English inside, and with no attention to the syntax rules of any real language.

Every algorithm must have these five properties: input (zero or more), output (at least one), definiteness (each step unambiguous), finiteness (it must stop) and effectiveness (each step can actually be carried out).

Symbol Name Used for
Oval (rounded) Terminal START and STOP
Parallelogram Input/Output READ, PRINT
Rectangle Process calculation, assignment
Diamond Decision a Yes/No test
Circle Connector joining parts of a chart on the same page
Arrow Flow line the direction of flow
Worked example 5.1 — factorial of a number, all three ways

Problem. Design an algorithm, pseudocode and flowchart to read a positive integer and print its factorial, then write the C program.

Solution.

Algorithm

  1. Start.
  2. Read the number n.
  3. Set fact = 1 and i = 1.
  4. If i > n, go to step 8.
  5. Compute fact = fact * i.
  6. Compute i = i + 1.
  7. Go to step 4.
  8. Print fact.
  9. Stop.

Pseudocode

BEGIN
    READ n
    SET fact = 1
    FOR i = 1 TO n DO
        fact = fact * i
    ENDFOR
    PRINT fact
END

C program

#include <stdio.h>
int main(void)
{
    int n, i;
    long fact = 1;
    printf("Enter a positive integer: ");
    scanf("%d", &n);
    if (n < 0) { printf("Factorial is not defined for negatives\n"); return 1; }
    for (i = 1; i <= n; i++)
        fact = fact * i;
    printf("%d! = %ld\n", n, fact);
    return 0;
}

Output for the input 7, and again for the input 0:

Enter a positive integer: 7! = 5040
Enter a positive integer: 0! = 1

The loop for n = 0 runs zero times, so fact stays 1 — which is exactly the mathematical value of 0!.

figure
Figure 5. Flowchart for the factorial program of Worked example 5.1. Note the loop: the decision diamond is tested before the body, and the flow line returns to the diamond after every pass.

Algorithm Flowchart Pseudocode
Form numbered English steps diagram of symbols keyword-and-English text
Easy to draw for a big problem? yes no — becomes huge yes
Easy for a beginner to follow? yes easiest yes
Converts to code needs thought needs thought almost line by line
Standard symbols none ISO/ANSI symbols none

5.6 Absolute binary, BCD, ASCII and Unicode

Numbers and characters must both end up as bit patterns, but they are coded in different ways.

Absolute binary (also called pure or straight binary) is the ordinary positional binary of Unit 2: the whole decimal number is converted as one quantity. So 59 becomes 111011, using six bits.

BCD — Binary Coded Decimal codes each decimal digit separately in four bits. So 59 becomes 0101 1001. BCD wastes space (the six patterns 1010 to 1111 are never used, so about 17% of the codes are thrown away) and arithmetic in BCD is slower, but conversion to and from decimal needs no calculation at all — which is why BCD is used in calculators, digital clocks, electricity meters and seven-segment displays.

Worked example 5.2 — absolute binary against BCD

Problem. Represent (a) 59 and (b) 274 in absolute binary and in BCD, and comment on the number of bits used.

Solution.

(a) Absolute binary: 59 = 32 + 16 + 8 + 2 + 1 = 111011 — 6 bits. BCD: digit 5 = 0101, digit 9 = 1001, so 0101 1001 — 8 bits.

(b) Absolute binary: 274 = 256 + 16 + 2 = 100010010 — 9 bits. BCD: 2 = 0010, 7 = 0111, 4 = 0100, so 0010 0111 0100 — 12 bits.

BCD always needs 4 bits per decimal digit, so it needs more bits than absolute binary for the same value. The gain is that each digit can be read off, and sent to a display, on its own.

ASCII (American Standard Code for Information Interchange) codes characters. The standard version uses 7 bits, giving 2⁷ = 128 codes, numbered 0 to 127. Extended ASCII uses 8 bits and gives 256. The codes worth memorising are:

Character(s) ASCII code (decimal)
NUL (null) 0
Space 32
0 to 9 48 to 57
A to Z 65 to 90
a to z 97 to 122
DEL 127

Because the letters are consecutive and lower case is exactly 32 more than upper case, character arithmetic works. This program prints the codes:

#include <stdio.h>
int main(void)
{
    char ch = 'A';
    printf("'%c' is stored as %d\n", ch, ch);
    printf("'%c' is stored as %d\n", 'a', 'a');
    printf("'%c' is stored as %d\n", '0', '0');
    printf("ch + 32 gives '%c'\n", ch + 32);
    printf("The 26 capitals: ");
    for (ch = 'A'; ch <= 'Z'; ch++) printf("%c", ch);
    printf("\n");
    return 0;
}
'A' is stored as 65
'a' is stored as 97
'0' is stored as 48
ch + 32 gives 'a'
The 26 capitals: ABCDEFGHIJKLMNOPQRSTUVWXYZ

photograph
Figure 6. The 128 codes of standard 7-bit ASCII. Read a code as row + column in hexadecimal: 'A' is in row 4, column 1, so its code is 41 in hex = 65 in decimal. The 33 shaded entries (00–1F and 7F) are non-printing control characters. Source: Anomie / Wikimedia Commons (Public domain)

Unicode was created because 256 codes cannot hold the world's writing systems — Devanagari alone needs more than 128. Unicode gives every character of every language one unique number, called a code point, written like U+0915 (क, DEVANAGARI LETTER KA). It has room for 1,114,112 code points, of which about 150,000 are assigned. The first 128 code points of Unicode are exactly ASCII, so every ASCII file is already a valid Unicode (UTF-8) file. This is why you can type नेपाल, 日本 and Nepal in the same document.

ASCII Unicode
Bits per character 7 (extended: 8) 8, 16 or 32, depending on encoding
Number of characters 128 (extended: 256) over 1.1 million possible
Languages covered English only practically all languages
Compatible with — includes ASCII as its first 128 codes
Common encodings — UTF-8, UTF-16, UTF-32

5.7 C: introduction and features; structure of a C program

C was written by Dennis Ritchie at Bell Laboratories, USA, in 1972, to rewrite the UNIX operating system. It grew out of an earlier language called B (Ken Thompson, 1970), which came from BCPL. In 1978 Brian Kernighan and Dennis Ritchie published The C Programming Language, the book that defined "K&R C"; the language was standardised by ANSI in 1989 (ANSI C / C89) and by ISO in 1990.

Its features, in the order examiners usually want them:

  • General purpose and structured — programs are built from functions and the three control structures, so large problems break into small ones.
  • Middle-level language — it has the readability of a high-level language and low-level facilities (pointers, bitwise operators, direct memory access), which is why operating systems are written in it.
  • Portable — the same source compiles on Windows, Linux, macOS and on microcontrollers.
  • Rich library — hundreds of ready-made functions in header files.
  • Fast and compact, with only 32 keywords to learn.
  • Extensible — you add your own functions and your own header files.
  • Case sensitive — sum, Sum and SUM are three different names.

A C program has this fixed order:

Section Example Compulsory?
Documentation (comments) /* Program to find area */ optional
Link / preprocessor #include <stdio.h> practically always
Definition #define PI 3.1416 optional
Global declaration int count; float area(float); optional
main() function int main(void) { ... return 0; } compulsory
User-defined functions float area(float r) { ... } optional
/* p01.c - the smallest complete C program with every part labelled */
#include <stdio.h>          /* preprocessor directive: brings in printf   */
#define PI 3.1416           /* symbolic constant                          */

int main(void)              /* execution always begins here               */
{
    float r = 7.0, area;    /* declaration                                */
    area = PI * r * r;      /* statement                                  */
    printf("Namaste, NEBians!\n");
    printf("Area of a circle of radius %.1f cm = %.4f sq cm\n", r, area);
    return 0;               /* 0 tells the OS the program succeeded       */
}
Namaste, NEBians!
Area of a circle of radius 7.0 cm = 153.9384 sq cm
Every C program has exactly one `main()`

Execution always begins at main(), wherever it appears in the file, and a program with no main() will compile its pieces but refuse to link. The braces { } that open and close main() must match, and every statement inside ends with a semicolon.

5.8 The C preprocessor and header files; character set; comments

The preprocessor is the first program to touch your source file. It obeys every line that starts with # — and those lines are not C statements, so they carry no semicolon.

Directive What it does
#include <stdio.h> copies the whole of the header file stdio.h into your file (searches the system directories)
#include "myfile.h" the same, but searches your own folder first
#define PI 3.1416 macro substitution: every later PI is replaced by 3.1416 before compiling
#define SQ(x) ((x)*(x)) a macro with an argument
#undef PI cancels a previous #define
#ifdef / #endif conditional compilation

A header file (extension .h) holds the declarations of library functions so the compiler knows how to call them.

Header Gives you
stdio.h printf, scanf, getchar, putchar, gets, puts
conio.h clrscr(), getch() — Turbo C only, not standard C
math.h sqrt, pow, abs, sin, cos, log
string.h strlen, strcpy, strcat, strcmp
stdlib.h atoi, rand, malloc, exit
ctype.h toupper, tolower, isalpha, isdigit

The C character set is everything you are allowed to type in a program:

  • Letters — A to Z and a to z
  • Digits — 0 to 9
  • Special characters — , . ; : ? ' " ( ) [ ] { } < > ! | / \ ~ _ $ % & ^ * - + = #
  • White space — blank, tab, newline, form feed
  • Escape sequences — \n newline, \t tab, \b backspace, \\ backslash, \" double quote, \0 null character

Comments are notes for humans; the compiler deletes them. C has two forms:

/* this is a multi-line comment
   it may run over as many lines as you like */
// this is a single-line comment (C99 onwards)

Comments cannot be nested — a /* inside another /* ... */ does not work.

5.9 Identifiers, keywords and tokens; basic data types; constants and variables

A token is the smallest individual unit of a C program. There are six kinds:

Token Examples
Keywords int, if, while, return
Identifiers sum, marks, main, roll_no
Constants 25, 3.1416, 'A', "Nepal"
Strings "Kathmandu"
Operators +, -, *, ==, &&, ++
Special symbols ; , ( ) { } [ ] #

Keywords are the 32 reserved words of ANSI C. They are always lower case and can never be used as a name of your own:

auto     break    case     char     const    continue default  do
double   else     enum     extern   float    for      goto     if
int      long     register return   short    signed   sizeof   static
struct   switch   typedef  union    unsigned void     volatile while

An identifier is a name you invent for a variable, function, array or label. The rules — worth five easy marks — are:

  1. It may contain only letters, digits and the underscore _.
  2. It must begin with a letter or an underscore, never a digit.
  3. No blank space and no special character (marks obtained and roll-no are both illegal).
  4. It must not be a keyword.
  5. C is case sensitive: Total and total are different identifiers.

So sum, _count, marks2, roll_no are valid; 2marks, net pay, float, pass% are not.

The basic (primary) data types are:

Type Typical size Range (typical) Format specifier
char 1 byte −128 to 127 %c
int 4 bytes −2,147,483,648 to 2,147,483,647 %d
short int 2 bytes −32,768 to 32,767 %hd
long int 4 or 8 bytes much larger %ld
float 4 bytes about 3.4 × 10⁻³⁸ to 3.4 × 10³⁸, 6 digits %f
double 8 bytes about 1.7 × 10⁻³⁰⁸ to 1.7 × 10³⁰⁸, 15 digits %lf
void 0 no value at all —

Sizes are not fixed by the language — they depend on the compiler and the machine — which is why C gives you the sizeof operator to ask:

#include <stdio.h>
int main(void)
{
    int    a = 2147483647;
    float  b = 3.14159f;
    double c = 3.141592653589793;
    char   d = 'K';
    printf("int    %d  size %zu bytes\n", a, sizeof(int));
    printf("float  %f  size %zu bytes\n", b, sizeof(float));
    printf("double %.15f  size %zu bytes\n", c, sizeof(double));
    printf("char   %c (ASCII %d)  size %zu byte\n", d, d, sizeof(char));
    printf("short %zu, long %zu, unsigned int %zu\n",
           sizeof(short), sizeof(long), sizeof(unsigned int));
    return 0;
}

On a 64-bit Linux machine with GCC this prints:

int    2147483647  size 4 bytes
float  3.141590  size 4 bytes
double 3.141592653589793  size 8 bytes
char   K (ASCII 75)  size 1 byte
short 2, long 8, unsigned int 4
Constant and variable

A constant is a quantity whose value cannot change while the program runs: 25, -7 (integer constants), 3.1416, 2.5e3 (real constants), 'A' (character constant, in single quotes), "Nepal" (string constant, in double quotes).

A variable is a named location in memory whose value can change. It must be declared with a type before it is used: int roll; and it may be initialised at the same time: int roll = 12;

There are two more ways to make a constant, and the difference is examinable:

#define PI 3.1416      /* preprocessor macro: textual replacement, no memory used */
const float pi = 3.1416f;   /* a real variable that the compiler refuses to change */

5.10 Type specifiers; simple and compound statements

A type specifier is the keyword that states the type of a variable — char, int, float, double, void — optionally preceded by a modifier that changes its size or sign: short, long, signed, unsigned.

Declaration Meaning
unsigned int n; no negative values, so the positive range doubles (0 to 4,294,967,295)
signed char c; −128 to 127 (the default on most compilers)
unsigned char c; 0 to 255
long int population; a wider integer
short int age; a narrower integer

A simple statement is a single instruction closed by a semicolon:

sum = a + b;

A compound statement (a block) is a group of statements wrapped in braces and treated as one statement. Anywhere C allows one statement, it allows a block:

if (marks >= 40) {
    printf("Pass\n");
    pass_count = pass_count + 1;
}

Variables declared inside a block are local to it and vanish when the closing brace is reached.

5.11 Operators and expressions

An operator acts on operands; an expression is a combination of operands and operators that reduces to a single value.

Class Operators Note
Arithmetic + - * / % % (modulus) works on integers only
Relational < > <= >= == != result is 1 (true) or 0 (false)
Logical && (and), ! (not), and OR — see below combine conditions
Assignment = += -= *= /= %= a += b means a = a + b
Unary + - ++ -- ! sizeof & one operand only
Conditional (ternary) ? : the only three-operand operator
Bitwise & \| ^ ~ << >> work bit by bit

The logical OR operator is typed as two vertical-bar characters, ||. So (a > b) || (b > 0) reads "a is greater than b, or b is greater than 0".

Operators are also counted by how many operands they take: unary (one, e.g. ++), binary (two, e.g. +), ternary (three — only ? :).

#include <stdio.h>
int main(void)
{
    int a = 17, b = 5, x, y;
    printf("Arithmetic : %d %d %d %d %d\n", a+b, a-b, a*b, a/b, a%b);
    printf("Real divide: %.2f\n", a / 5.0);
    printf("Relational : %d %d %d %d\n", a>b, a<b, a==b, a!=b);
    printf("Logical    : %d %d %d\n", (a>b)&&(b>0), (a<b)||(b>0), !(a>b));
    y = a; y += b; printf("y += b  -> %d\n", y);
    y -= 2;        printf("y -= 2  -> %d\n", y);
    y *= 3;        printf("y *= 3  -> %d\n", y);
    x = 10;  y = x++;   printf("post: y = x++ gives y = %d, x = %d\n", y, x);
    x = 10;  y = ++x;   printf("pre : y = ++x gives y = %d, x = %d\n", y, x);
    printf("Larger of %d and %d is %d\n", a, b, (a > b) ? a : b);
    printf("Mixed 2+3*4-6/2 = %d\n", 2 + 3 * 4 - 6 / 2);
    return 0;
}
Arithmetic : 22 12 85 3 2
Real divide: 3.40
Relational : 1 0 0 1
Logical    : 1 1 0
y += b  -> 22
y -= 2  -> 20
y *= 3  -> 60
post: y = x++ gives y = 10, x = 11
pre : y = ++x gives y = 11, x = 11
Larger of 17 and 5 is 17
Mixed 2+3*4-6/2 = 11

Three results in that output deserve a second look.

17 / 5 gives 3, not 3.4. When both operands are integers, C does integer division and throws the fraction away. Write 17 / 5.0 and you get 3.40.

y = x++ gives y = 10 but leaves x = 11. The post-increment x++ uses the old value first and increases afterwards. The pre-increment ++x increases first, so y = ++x gives 11.

2 + 3 * 4 - 6 / 2 is 11, not 7. Operators are applied in order of precedence, and only then left to right:

Precedence Operators Associativity
highest ( ) [ ] left to right
! ++ -- sizeof unary - right to left
* / % left to right
+ - left to right
< <= > >= left to right
== != left to right
&& left to right
logical OR left to right
?: right to left
lowest = += -= *= /= right to left

So 3 * 4 = 12 and 6 / 2 = 3 are done first, leaving 2 + 12 - 3 = 11.

`=` is not `==`

a = 5 stores 5 in a and the expression's value is 5, which C counts as true. a == 5 compares. Writing if (a = 5) therefore always takes the true branch and silently destroys a. This single typing mistake costs more marks than any other in the C paper.

5.12 Input/output functions

C itself has no input or output statements; everything is done by library functions declared in stdio.h.

Function Does Example
printf() formatted output to the screen printf("Total = %d\n", t);
scanf() formatted input from the keyboard scanf("%d", &n);
getchar() reads one character ch = getchar();
putchar() writes one character putchar(ch);
gets() reads a whole line into a string gets(name);
puts() writes a string and a newline puts(name);

The format specifier tells the function what kind of data to expect:

Specifier Data Specifier Data
%d int (decimal) %c char
%f float %s string
%lf double %u unsigned int
%ld long int %x hexadecimal
%.2f float, 2 decimal places %5d int, right-aligned in 5 columns
#include <stdio.h>
int main(void)
{
    int roll;  float marks;  char section;  char name[20];
    printf("Enter roll, marks, section and name: ");
    scanf("%d %f %c %s", &roll, &marks, &section, name);
    printf("Roll no   : %d\n", roll);
    printf("Marks     : %.2f\n", marks);
    printf("Section   : %c\n", section);
    printf("Name      : %s\n", name);
    printf("Grade point (marks/25): %.2f\n", marks / 25.0);
    return 0;
}

Typing 17 82.5 B Sushmita gives:

Enter roll, marks, section and name: Roll no   : 17
Marks     : 82.50
Section   : B
Name      : Sushmita
Grade point (marks/25): 3.30
`scanf` needs the address operator `&`

scanf("%d", n); compiles but destroys memory, because scanf must be told where to put the value. Write scanf("%d", &n);. The one exception is a string: an array name is already an address, so scanf("%s", name); is correct without &.

5.13 Selection control statements: if, if-else, if-else-if, nested if, switch

Form Shape
if if (condition) statement;
if-else if (condition) statement1; else statement2;
if-else-if (ladder) a chain of tests; the first true one runs and the rest are skipped
nested if an if written inside the body of another if
switch one variable compared against a list of constant case labels

A grade calculator is the standard if-else-if question:

#include <stdio.h>
int main(void)
{
    float marks;
    printf("Enter marks: ");
    scanf("%f", &marks);
    if (marks >= 90)        printf("Grade A+\n");
    else if (marks >= 80)   printf("Grade A\n");
    else if (marks >= 70)   printf("Grade B+\n");
    else if (marks >= 60)   printf("Grade B\n");
    else if (marks >= 40)   printf("Grade C\n");
    else                    printf("Not graded\n");
    return 0;
}
Enter marks: Grade A          <- input was 83
Enter marks: Not graded       <- input was 35

The ladder works because the tests are checked in order and stop at the first true one: 83 fails >= 90, passes >= 80, and the remaining tests are never reached.

switch is used when one variable is compared with several constant values. It is tidier than a long ladder, but it cannot test a range or a real number.

#include <stdio.h>
int main(void)
{
    int a, b, choice;
    printf("1.Add 2.Subtract 3.Multiply 4.Divide\n");
    printf("Enter two numbers and your choice: ");
    scanf("%d %d %d", &a, &b, &choice);
    switch (choice) {
        case 1: printf("Sum        = %d\n", a + b);        break;
        case 2: printf("Difference = %d\n", a - b);        break;
        case 3: printf("Product    = %d\n", a * b);        break;
        case 4:
            if (b != 0) printf("Quotient   = %.2f\n", (float)a / b);
            else        printf("Division by zero is not allowed\n");
            break;
        default: printf("Invalid choice\n");
    }
    return 0;
}
1.Add 2.Subtract 3.Multiply 4.Divide
Enter two numbers and your choice: Quotient   = 5.00      <- input 45 9 4
1.Add 2.Subtract 3.Multiply 4.Divide
Enter two numbers and your choice: Invalid choice         <- input 45 9 7
Forgetting `break` makes the cases "fall through"

Without break, control runs straight on into the next case and every following one executes too. Check every case has its break, and give the switch a default for inputs you did not plan for.

if-else-if ladder switch
Tests any condition, including ranges equality with constants only
Data types any, including float int and char only
If no case matches final else default
Needs break? no yes, in every case

5.14 Iteration control statements: while, do-while, for, nested loops

Every loop needs three things: initialisation of a counter, a test condition, and updating of the counter. The three C loops differ only in where those three sit.

Loop Form Test happens Minimum runs
while while (cond) { body } before the body 0
do-while do { body } while (cond); after the body 1
for for (init; cond; update) { body } before the body 0

while is the entry-controlled loop, do-while the exit-controlled loop. Note the semicolon after while (cond); in do-while — it is the only place a loop keyword takes one.

#include <stdio.h>
int main(void)
{
    int i, n = 5, sum = 0;
    printf("for      : ");
    for (i = 1; i <= n; i++) { printf("%d ", i); sum += i; }
    printf("| sum = %d\n", sum);

    i = 1; sum = 0;
    printf("while    : ");
    while (i <= n) { printf("%d ", i); sum += i; i++; }
    printf("| sum = %d\n", sum);

    i = 1; sum = 0;
    printf("do-while : ");
    do { printf("%d ", i); sum += i; i++; } while (i <= n);
    printf("| sum = %d\n", sum);

    i = 100;                                  /* condition is FALSE now */
    while (i < 5)
        printf("this line never prints\n");
    do
        printf("but do-while still prints once, with i = %d\n", i);
    while (i < 5);
    return 0;
}
for      : 1 2 3 4 5 | sum = 15
while    : 1 2 3 4 5 | sum = 15
do-while : 1 2 3 4 5 | sum = 15
but do-while still prints once, with i = 100

The last four lines are the whole difference between while and do-while, proved by the machine: with i = 100 the while body never ran, but the do-while body ran once before the condition was even looked at.

A nested loop is a loop inside a loop. For every single turn of the outer loop, the inner loop runs all the way through. This is how patterns and tables are printed:

#include <stdio.h>
int main(void)
{
    int i, j;
    for (i = 1; i <= 5; i++) {          /* outer loop: one row per turn  */
        for (j = 1; j <= i; j++)        /* inner loop: i stars in row i  */
            printf("* ");
        printf("\n");
    }
    printf("\n");
    for (i = 1; i <= 3; i++) {
        for (j = 1; j <= 5; j++)
            printf("%4d", i * j);
        printf("\n");
    }
    return 0;
}
* 
* * 
* * * 
* * * * 
* * * * * 

   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15

Two jump statements are used inside loops: break leaves the loop immediately, and continue skips the rest of this turn and goes on to the next one.

The infinite loop

for (i = 1; i <= 10; i--) and a while loop whose counter is never updated both run forever. Before you write a loop in the exam, point at the statement that changes the counter. If you cannot find it, the loop is infinite.

5.15 Arrays: definition, one-dimensional and two-dimensional, matrix addition and subtraction

Array

An array is a collection of a fixed number of elements of the same data type, stored in consecutive memory locations and referred to by a common name, each element being reached by an index (subscript).

Without arrays, storing the marks of 50 students needs 50 separate variable names. With an array it is one name and a loop.

int marks[5];                       /* declaration: 5 integers           */
int marks[5] = {78, 52, 91, 45, 84};/* declaration with initialisation   */

The index always starts at 0, so a five-element array uses marks[0] to marks[4]. The total memory used is number of elements × size of one element — here 5 × 4 = 20 bytes.

#include <stdio.h>
int main(void)
{
    int marks[5] = {78, 52, 91, 45, 84};
    int i, sum = 0, max, min;
    max = min = marks[0];
    for (i = 0; i < 5; i++) {
        printf("marks[%d] = %d\n", i, marks[i]);
        sum += marks[i];
        if (marks[i] > max) max = marks[i];
        if (marks[i] < min) min = marks[i];
    }
    printf("Total   = %d\n", sum);
    printf("Average = %.2f\n", sum / 5.0);
    printf("Highest = %d, Lowest = %d\n", max, min);
    return 0;
}
marks[0] = 78
marks[1] = 52
marks[2] = 91
marks[3] = 45
marks[4] = 84
Total   = 350
Average = 70.00
Highest = 91, Lowest = 45
C does not check array bounds

marks[5] and marks[-1] are outside a five-element array, but C will happily read or write them and corrupt whatever is next in memory. The loop condition is i < 5, not i <= 5.

A two-dimensional array is an array of arrays — a table with rows and columns, which is how a matrix is stored.

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};   /* 2 rows, 3 columns */

C stores it in row-major order: the whole of row 0 first, then the whole of row 1, in one unbroken run of memory.

figure
Figure 7. A 2\times3 array in memory. The programmer sees a table; the machine sees one straight run of six integers stored row after row. This is why `a[1][0]` follows immediately after `a[0][2]`.

Two matrices can be added or subtracted only if they have the same order, and the rule is element by element: the element in row i, column j of the answer is formed from the elements in row i, column j of both matrices. That is a nested loop, one loop for rows and one for columns.

Worked example 5.3 — matrix addition and subtraction

Problem. Add and subtract the two 2 × 3 matrices by hand, then write the C program that does it.

Solution. Let A have rows (1, 2, 3) and (4, 5, 6), and B have rows (7, 8, 9) and (1, 0, 2).

For the sum, add matching positions: row 0 gives 1+7 = 8, 2+8 = 10, 3+9 = 12; row 1 gives 4+1 = 5, 5+0 = 5, 6+2 = 8.

For the difference, subtract matching positions: row 0 gives 1−7 = −6, 2−8 = −6, 3−9 = −6; row 1 gives 4−1 = 3, 5−0 = 5, 6−2 = 4.

#include <stdio.h>
int main(void)
{
    int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int b[2][3] = {{7, 8, 9}, {1, 0, 2}};
    int sum[2][3], diff[2][3], i, j;

    for (i = 0; i < 2; i++)
        for (j = 0; j < 3; j++) {
            sum[i][j]  = a[i][j] + b[i][j];
            diff[i][j] = a[i][j] - b[i][j];
        }

    printf("A + B =\n");
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) printf("%4d", sum[i][j]);
        printf("\n");
    }
    printf("A - B =\n");
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) printf("%4d", diff[i][j]);
        printf("\n");
    }
    return 0;
}
A + B =
   8  10  12
   5   5   8
A - B =
  -6  -6  -6
   3   5   4

The machine's answer matches the hand calculation exactly.

5.16 Strings: definition and string functions

String

A string in C is a one-dimensional array of characters terminated by the null character '\0'. There is no separate string data type. The null character is what tells every library function where the string ends, so an array holding n characters must be declared with room for n + 1.

char city[10] = "Pokhara";

reserves 10 bytes and stores P o k h a r a \0, leaving two spare. Note the difference between 'A' (a single character, 1 byte) and "A" (a string, 2 bytes — the letter and the null).

The functions live in string.h:

Function What it does Example Result
strlen(s) returns the length, not counting '\0' strlen("Kathmandu") 9
strcpy(s1,s2) copies s2 into s1 strcpy(s3,"Kathmandu") s3 becomes Kathmandu
strcat(s1,s2) joins s2 to the end of s1 strcat(s3," Valley") Kathmandu Valley
strcmp(s1,s2) compares; 0 if equal, negative if s1 < s2, positive if s1 > s2 strcmp("Kathmandu","Valley") −11
strrev(s) reverses the string strrev("Pokhara") arahkoP
strlwr(s) converts to lower case strlwr("Pokhara") pokhara
strupr(s) converts to upper case strupr("Pokhara") POKHARA
#include <stdio.h>
#include <string.h>
int main(void)
{
    char s1[30] = "Kathmandu";
    char s2[30] = "Valley";
    char s3[30];

    printf("strlen(s1)        = %zu\n", strlen(s1));
    strcpy(s3, s1);
    printf("strcpy(s3, s1)    -> s3 = %s\n", s3);
    strcat(s3, " ");
    strcat(s3, s2);
    printf("strcat            -> s3 = %s\n", s3);
    printf("strcmp(s1, s2)    = %d\n", strcmp(s1, s2));
    printf("strcmp(s1, \"Kathmandu\") = %d\n", strcmp(s1, "Kathmandu"));
    printf("s1[0] = %c, s1[8] = %c\n", s1[0], s1[8]);
    return 0;
}
strlen(s1)        = 9
strcpy(s3, s1)    -> s3 = Kathmandu
strcat            -> s3 = Kathmandu Valley
strcmp(s1, s2)    = -11
strcmp(s1, "Kathmandu") = 0
s1[0] = K, s1[8] = u

Why is strcmp("Kathmandu", "Valley") equal to −11? The function compares character by character until they differ. The very first pair differs: 'K' is ASCII 75 and 'V' is ASCII 86, and 75 − 86 = −11. The sign is what matters — negative means the first string comes earlier in dictionary order.

`strrev`, `strlwr` and `strupr` are not standard C

These three are in the NEB syllabus because they exist in Turbo C and other Borland compilers, but they are not part of the ANSI C library. Compiling strrev(s) with GCC gives a real error:

error: implicit declaration of function 'strrev'; did you mean 'strsep'?

Write them yourself. This version compiles and runs anywhere:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void my_strrev(char s[]) {
    int i, n = strlen(s); char t;
    for (i = 0; i < n / 2; i++) { t = s[i]; s[i] = s[n-1-i]; s[n-1-i] = t; }
}
void my_strupr(char s[]) { int i; for (i = 0; s[i]; i++) s[i] = toupper(s[i]); }
void my_strlwr(char s[]) { int i; for (i = 0; s[i]; i++) s[i] = tolower(s[i]); }

int main(void)
{
    char a[30] = "Pokhara", b[30] = "Pokhara", c[30] = "Pokhara";
    my_strrev(a); printf("strrev(\"Pokhara\")  = %s\n", a);
    my_strupr(b); printf("strupr(\"Pokhara\")  = %s\n", b);
    my_strlwr(c); printf("strlwr(\"Pokhara\")  = %s\n", c);
    return 0;
}
strrev("Pokhara")  = arahkoP
strupr("Pokhara")  = POKHARA
strlwr("Pokhara")  = pokhara

In the board exam, using strrev() is accepted. On a real Linux or modern Windows compiler, it is not.

Worked example 5.4 — count vowels and consonants in a line of text

Problem. Write a C program that reads a line of text and counts its characters, vowels and consonants.

Solution. Read the whole line (spaces included), walk the array until the null character, fold each letter to lower case by ASCII arithmetic, and test it.

#include <stdio.h>
#include <string.h>
int main(void)
{
    char s[100];
    int i, v = 0, cons = 0;
    printf("Enter a line of text: ");
    scanf("%99[^\n]", s);
    for (i = 0; s[i] != '\0'; i++) {
        char ch = s[i];
        if (ch >= 'A' && ch <= 'Z') ch = ch + 32;
        if (ch >= 'a' && ch <= 'z') {
            if (ch=='a'||ch=='e'||ch=='i'||ch=='o'||ch=='u') v++;
            else cons++;
        }
    }
    printf("Length = %zu, vowels = %d, consonants = %d\n", strlen(s), v, cons);
    return 0;
}

With the input Sagarmatha is in Nepal:

Enter a line of text: Length = 22, vowels = 8, consonants = 11

Check by hand: 22 characters including the three spaces; the vowels are a-a-a-a (Sagarmatha), i (is), i (in), e-a (Nepal) = 8; the remaining 11 letters are consonants. ✓

Chapter summary

  • Languages run from 1GL machine code (binary, machine dependent, fastest) up through 2GL assembly (mnemonics, needs an assembler), 3GL high-level (C, Java — machine independent, needs a compiler or interpreter) to 4GL (SQL — you say what, not how).
  • A compiler translates the whole program at once and produces an executable; an interpreter translates and runs one statement at a time and produces no file. Compiled code runs faster; interpreted code is easier to debug.
  • Syntax errors are caught by the compiler and stop it producing a program; semantic (logical) errors compile fine and give wrong answers; runtime errors such as divide-by-zero appear only while running.
  • The three control structures are sequence, selection (if, if-else, if-else-if, switch) and iteration (while, do-while, for). Every program can be built from these three alone.
  • Design tools: algorithm (numbered English steps), flowchart (oval = terminal, parallelogram = I/O, rectangle = process, diamond = decision), pseudocode (keywords plus English).
  • Absolute binary codes the whole number; BCD codes each decimal digit in 4 bits; ASCII codes characters in 7 bits (128 codes: A = 65, a = 97, 0 = 48, space = 32); Unicode gives every character of every language its own code point and contains ASCII as its first 128 codes.
  • C was written by Dennis Ritchie at Bell Labs in 1972. It is a middle-level, structured, portable, case-sensitive language with 32 keywords. Every program has exactly one main().
  • C's six tokens are keywords, identifiers, constants, strings, operators and special symbols. An identifier starts with a letter or _, contains only letters, digits and _, and is not a keyword.
  • Integer division throws the fraction away (17/5 is 3); x++ uses the value then increments while ++x increments first; = assigns and == compares.
  • while tests before the body (may run 0 times); do-while tests after (runs at least once); for packs initialisation, test and update into one line.
  • An array holds a fixed number of same-type elements in consecutive memory, indexed from 0. A 2-D array is stored in row-major order. Matrices of the same order are added or subtracted element by element with a nested loop.
  • A string is a character array ending in '\0', so it needs n + 1 bytes for n characters. strlen, strcpy, strcat and strcmp are standard; strrev, strlwr and strupr are Turbo C extensions.

Practice questions

Group A — Multiple choice (1 mark each)

  1. Which of the following is a low-level language? [1]aCbSQLcAssembly languagedPython
  2. A translator that converts a high-level program into machine code all at once is called [1]aan assemblerba compilercan interpreterda loader
  3. A missing semicolon in a C program produces [1]aa runtime errorba logical errorca syntax errordno error
  4. In a flowchart, the diamond symbol represents [1]astart/stopba processcinput/outputda decision
  5. The ASCII code of the character A is [1]a61b65c97d122
  6. Which one is not a valid C identifier? [1]a_totalbmarks2c2marksdrollNo
  7. The value of 17 % 5 in C is [1]a3b3.4c2d0
  8. Which loop always executes its body at least once? [1]aforbwhilecdo-whilednested for
  9. If int a[5]; is declared, the last valid element is [1]aa[5]ba[4]ca[0]da[6]
Answers to Group A

1. (c) — machine and assembly languages are the low-level ones.

2. (b) — an interpreter does it one statement at a time.

3. (c) — it breaks a grammar rule, so the compiler refuses to build.

4. (d) — the diamond is always a Yes/No test.

5. (b) — A = 65, so Z = 90 and a = 97.

6. (c) — an identifier may not begin with a digit.

7. (c) — % gives the remainder: 17 = 3 × 5 + 2.

8. (c) — do-while tests the condition after the body.

9. (b) — indexing starts at 0, so five elements are a[0] to a[4].

Group B — Short answer (5 marks each)

  1. Differentiate between a compiler and an interpreter with any five points. [5]
  2. Define syntax error, semantic error and runtime error with one example of each. [5]
  3. Write an algorithm and draw a flowchart to read three numbers and print the largest. [5]
  4. Write a C program to check whether a given number is prime or not. [5]
  5. Write a C program to display the first n terms of the Fibonacci series. [5]
  6. Define an array. Write a C program to read 10 numbers into an array and print their sum and average. [5]
Answers to Group B

1. See the comparison table in §5.2: unit translated (whole program / one statement), errors reported (all together / stops at the first), object file (produced / not produced), execution speed (fast / slow), memory (more / less), examples (C, C++ / Python, BASIC).

2. Syntax error — breaks a grammar rule, found by the compiler, no program is produced; example: int a = 5 with no semicolon. Semantic (logical) error — grammatically correct but wrong meaning; example: f = c * 5 / 9 + 32; for a Celsius-to-Fahrenheit conversion, which prints 52.6 instead of 98.6 for 37 °C. Runtime error — occurs while running; example: c = a / b; when the user enters b = 0, which aborts the program with a "Floating point exception".

3. Algorithm: 1. Start. 2. Read a, b, c. 3. If a ≥ b and a ≥ c, print a and go to 6. 4. If b ≥ a and b ≥ c, print b and go to 6. 5. Print c. 6. Stop. Flowchart: an oval START, a parallelogram READ a, b, c, a diamond a ≥ b AND a ≥ c?, its No branch leading to a second diamond b ≥ c?, each branch ending in a parallelogram PRINT, and all three joining an oval STOP. The equivalent C program is:

#include <stdio.h>
int main(void)
{
    float a, b, c;
    printf("Enter three numbers: ");
    scanf("%f %f %f", &a, &b, &c);
    if (a >= b && a >= c)      printf("Largest = %.2f\n", a);
    else if (b >= a && b >= c) printf("Largest = %.2f\n", b);
    else                       printf("Largest = %.2f\n", c);
    return 0;
}

With the input 12 47 29 it prints Largest = 47.00.

4.

#include <stdio.h>
int main(void)
{
    int n, i, isPrime = 1;
    printf("Enter a number: ");
    scanf("%d", &n);
    if (n < 2) isPrime = 0;
    for (i = 2; i <= n / 2; i++)
        if (n % i == 0) { isPrime = 0; break; }
    if (isPrime) printf("%d is a prime number\n", n);
    else         printf("%d is not a prime number\n", n);
    return 0;
}

Tested outputs: 29 gives 29 is a prime number; 91 gives 91 is not a prime number (91 = 7 × 13); 1 gives 1 is not a prime number.

5.

#include <stdio.h>
int main(void)
{
    int n, i, t1 = 0, t2 = 1, next;
    printf("Enter how many terms: ");
    scanf("%d", &n);
    printf("Fibonacci series: ");
    for (i = 1; i <= n; i++) {
        printf("%d ", t1);
        next = t1 + t2;
        t1 = t2;
        t2 = next;
    }
    printf("\n");
    return 0;
}

For n = 10 the tested output is Fibonacci series: 0 1 1 2 3 5 8 13 21 34.

6. An array is a collection of a fixed number of elements of the same data type stored in consecutive memory locations under one name, each reached by an index starting at 0.

#include <stdio.h>
int main(void)
{
    int num[10], i, sum = 0;
    printf("Enter 10 numbers: ");
    for (i = 0; i < 10; i++) scanf("%d", &num[i]);
    for (i = 0; i < 10; i++) sum += num[i];
    printf("Sum = %d, Average = %.2f\n", sum, sum / 10.0);
    return 0;
}

Group C — Long answer (8 marks each)

  1. (a) Explain the three control structures of structured programming with a flowchart fragment for each. [4](b) Write a C program using switch that reads two numbers and a choice (1 = add, 2 = subtract, 3 = multiply, 4 = divide) and prints the result. [4]
  2. (a) Define an array. Explain the difference between a one-dimensional and a two-dimensional array with a declaration of each. [3](b) Write a C program to read two 3 × 3 matrices and print their sum and their difference. [5]
  3. (a) What is a string in C? Why does a string of n characters need n + 1 bytes? [3](b) Explain strlen, strcpy, strcat and strcmp with one example each, and write a C program to check whether a word entered by the user is a palindrome. [5]
Answers to Group C

1. (a) Sequence — statements run top to bottom, each once; drawn as rectangles joined by downward arrows. Selection — a diamond tests a condition and exactly one of the two branches runs before they rejoin. Iteration — a diamond tests a condition, the body runs, and a flow line returns to the diamond; the body may run zero, one or many times. Each structure has one entry and one exit, so they can be stacked and nested. (See Figure 3.)

1. (b) The program is the switch example of §5.13. Tested: the input 45 9 4 prints Quotient = 5.00; the input 45 9 7 prints Invalid choice from the default label.

2. (a) An array is a fixed-size collection of same-type elements in consecutive memory under one name, indexed from 0. A one-dimensional array is a single list and needs one index — int marks[5]; — while a two-dimensional array is a table of rows and columns and needs two — int a[2][3]; — and is stored in row-major order (all of row 0, then all of row 1).

2. (b)

#include <stdio.h>
int main(void)
{
    int a[3][3], b[3][3], i, j;
    printf("Enter 9 elements of matrix A: ");
    for (i = 0; i < 3; i++)
        for (j = 0; j < 3; j++) scanf("%d", &a[i][j]);
    printf("Enter 9 elements of matrix B: ");
    for (i = 0; i < 3; i++)
        for (j = 0; j < 3; j++) scanf("%d", &b[i][j]);
    printf("A + B =\n");
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) printf("%5d", a[i][j] + b[i][j]);
        printf("\n");
    }
    printf("A - B =\n");
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) printf("%5d", a[i][j] - b[i][j]);
        printf("\n");
    }
    return 0;
}

The same nested-loop logic on 2 × 3 matrices was tested in Worked example 5.3 and gave rows (8, 10, 12) and (5, 5, 8) for the sum and (−6, −6, −6) and (3, 5, 4) for the difference.

3. (a) A string is a one-dimensional array of characters terminated by the null character '\0'. The library functions find the end of a string by looking for that null, so one extra byte must be reserved for it: char city[10] = "Pokhara"; stores seven letters plus '\0' and has two bytes spare.

3. (b) strlen("Kathmandu") returns 9 (the null is not counted). strcpy(s3, s1) copies s1 into s3, so s3 becomes Kathmandu. strcat(s3, s2) joins s2 onto the end of s3, giving Kathmandu Valley. strcmp(s1, s2) returns 0 when the strings are equal, and here returns −11 because 'K' (65 + 10 = 75) minus 'V' (86) is −11.

#include <stdio.h>
#include <string.h>
int main(void)
{
    char s[50];
    int i, j, pal = 1;
    printf("Enter a word: ");
    scanf("%49s", s);
    j = strlen(s) - 1;
    for (i = 0; i < j; i++, j--)
        if (s[i] != s[j]) { pal = 0; break; }
    if (pal) printf("\"%s\" is a palindrome\n", s);
    else     printf("\"%s\" is not a palindrome\n", s);
    return 0;
}

Tested outputs: madam gives "madam" is a palindrome; nepal gives "nepal" is not a palindrome.

Practise more: Computer Science question bank