CSS Prepare

optional · CSS study notes

II.8 Program Structure & Data Types

⬆️ P-I.II. Programming Fundamentals · Question Bank · Chapter II (2016–2026)

🧠

Remember: Type decides the values; scope decides the name; lifetime decides the object.

Start here — what you should be able to do

  • Read a complete program and identify declarations, definitions and initialization.
  • Choose types and explain conversion/integer-division pitfalls.
  • Distinguish scope, storage duration and object lifetime.

Reading order: foundation checks → full notes and examples → exam traps → self-test without notes → past-paper answers. All sections below remain part of the topic; code examples are kept in full.

Foundation checks

Essential distinctions

ConceptExampleMeaning
Declarationextern int count;Introduces a name and type; need not allocate storage.
Definitionint count = 0;Defines the object.
Initializationint x = 3;Gives the object its initial value.
Assignmentx = 4;Changes an existing object.
  • int is not guaranteed to occupy four bytes; use sizeof and the implementation's limits.
  • Both implicit and explicit conversions can lose information.
  • Cast before division: static_cast<double>(sum) / count, with count nonzero.
  • typedef/using create aliases, not distinct new types.
  • Initialize ordinary local variables before reading them.

Sources: C++ types, C++ conversions.

1. Anatomy of a Program (C/C++)

#include <stdio.h>      // 1. Preprocessor directives
#define MAX 100          //    (headers, macros)

int globalCount = 0;     // 2. Global declarations

int square(int n) {      // 3. Function prototypes/definitions
    return n * n;
}

int main() {              // 4. main() — program entry point
    int x = 5;             //    local declarations
    x = square(x);         //    statements/processing
    printf("%d", x);       //    output
    return 0;               // 5. return — exit status to OS
}
  1. Preprocessor directives — #include, #define, processed before compilation
  2. Global declarations — variables/constants visible to the whole file
  3. Function prototypes and definitions — including main(), the mandatory entry point
  4. main() body — local declarations, statements, control flow
  5. Return statement — sends an exit status back to the operating system (0 = success by convention)

2. Data Types

Primitive (built-in) types:

TypeTypical Size (C/C++)Holds
int4 bytesWhole numbers
float4 bytesSingle-precision decimal
double8 bytesDouble-precision decimal
char1 byteSingle character
bool (C++)1 bytetrue/false
void—No value / empty type
  • Type modifiers: signed, unsigned, short, long adjust range/sign (e.g. unsigned int, long long)

Derived/composite types: array, pointer, function

User-defined types: struct, union, enum, class (C++), typedef-based aliases

3. Variables: Declaration, Scope, Lifetime

  • Declaration: int age; binds an identifier to a data type and reserves memory for it
  • Initialization: int age = 25; declares and assigns a value in one step
  • Scope — where in the code a variable name is visible: local (inside a function/block) vs global (whole file/program)
  • Lifetime — how long a variable's memory persists: automatic (created/destroyed with each function call, default for locals) vs static (persists for the entire program run) vs dynamic (programmer-controlled via malloc/new and free/delete)

4. Type Conversion

  • Implicit (automatic) conversion: the compiler converts one type to another automatically, e.g. int → float in a mixed expression (widening, generally safe)
  • Explicit conversion (casting): the programmer forces a conversion, e.g. (int) 3.99 → 3 (may lose data — narrowing)

5. 💻 Code Examples: C & C++

The same program anatomy (preprocessor → globals → functions → main → return) with the full primitive type set, plus C++'s extra bool type and implicit/explicit conversion:

C:

#include <stdio.h>          // 1. Preprocessor directive
#define MAX 100

int globalCount = 0;         // 2. Global declaration

int square(int n) {          // 3. Function definition
    return n * n;
}

int main(void) {               // 4. main() -- entry point
    int x = 5;                  // local declaration
    unsigned long big = 100000UL;
    float pi = 3.14f;
    char grade = 'A';
    x = square(x);
    float avg = 7 / 2;           // implicit conversion: int -> float, but 7/2 truncates to 3 first
    int rounded = (int) 3.99;    // explicit conversion (cast): -> 3, decimal part lost
    printf("%d %c %.1f %d\n", x, grade, avg, rounded);
    return 0;                     // 5. return
}

C++:

#include <iostream>
using namespace std;
#define MAX 100

int globalCount = 0;

int square(int n) {
    return n * n;
}

int main() {
    int x = 5;
    bool passed = true;           // C++-only primitive type (true/false)
    double pi = 3.14159;
    char grade = 'A';
    x = square(x);
    double avg = 7.0 / 2;          // implicit conversion, no truncation this time
    int rounded = static_cast<int>(3.99);  // explicit conversion, C++ style cast
    cout << x << " " << grade << " " << avg << " " << rounded
         << " " << boolalpha << passed << endl;
    return 0;
}

6. MCQ Traps

  • main: normal hosted C/C++ application control reaches main through runtime startup; initialization may happen beforehand. main's position in the source file does not determine execution order.
  • Declaration versus initialization: a declaration introduces a name/type; a definition supplies the entity. An ordinary uninitialized local must not be read before receiving a valid value.
  • Implicit conversion from float to int truncates the decimal part; it does not round
  • void is a valid type for "no return value" or "no parameters," but a variable cannot be declared of type void
  • Automatic (stack) variables lose their value when the function returns; static variables retain their value across calls

7. ✅ Self-Test Questions (with Answers)

Q1. List, in order, the standard sections of a C/C++ program.

Answer — key points

  • A conventional C/C++ source file is laid out in five sections, in this order:
  1. Preprocessor directives — #include for headers and #define for macros; processed before compilation begins
  2. Global declarations — global variables, constants and function prototypes, visible throughout the file
  3. Function definitions — the bodies of the user-defined functions
  4. main() function — the mandatory entry point, containing local declarations, processing statements and output
  5. Return statement — return 0; sends an exit status to the operating system, where 0 conventionally means success
#include <iostream>          // 1. Preprocessor directives
#define MAX 100
using namespace std;

int globalCount = 0;          // 2. Global declarations
int square(int n);            //    function prototype

int square(int n) {           // 3. Function definition
    return n * n;
}

int main() {                  // 4. main() -- entry point
    int x = 5;                //    local declaration
    x = square(x);            //    processing
    cout << x << endl;        //    output -> 25
    return 0;                 // 5. return exit status to the OS
}
  • A prototype in section 2 lets main() call a function whose body appears later in the file; without it the compiler reports "not declared in this scope"
  • Sections 3 and 4 may be interchanged, provided prototypes are present — the order above is convention, not a compiler requirement
  • main: normal hosted C/C++ application control reaches main through runtime startup; initialization may happen beforehand. main's position in the source file does not determine execution order.

Q2. What is the difference between a primitive and a derived data type? Give one example of each.

Answer

  • Fundamental types: language-provided types such as integers, floating-point types, Boolean and void.
  • Compound/derived forms: arrays, pointers, references and function types are formed using other types.
  • Class/enum types: structs, classes, unions and enumerations provide additional modelling tools.
  • Alias: typedef and using name an existing type; they do not by themselves create a distinct new type.
  • C versus C++: category names and supported forms differ; C does not have C++ reference types.
  • Example: int is fundamental; int[5] is an array type; int* is a pointer type.
CategoryBuilt fromHoldsExamples
PrimitiveThe language itselfA single atomic valueint, float, double, char, bool, void
DerivedExisting typesA collection of, or reference to, valuesarray, pointer, function, reference
User-definedProgrammer's own definitionA named composite of membersstruct, union, enum, class, typedef
// PRIMITIVE: one atomic value each
int   age    = 25;        // 4 bytes
char  grade  = 'A';       // 1 byte
double pi    = 3.14159;   // 8 bytes

// DERIVED: built out of the primitive int
int   marks[5] = {80, 75, 90, 60, 88};  // array  -> 5 ints, 20 bytes
int  *p        = &age;                  // pointer-> holds an address
int   square(int n);                    // function-> derived type too

// USER-DEFINED: a composite the programmer names
struct Student { int roll; char grade; double gpa; };

cout << sizeof(age)   << endl;   // 4
cout << sizeof(marks) << endl;   // 20  (5 * 4)
  • MCQ trap: void is a primitive type but no variable can be declared of type void — it means "no value", used for a function's return type or an empty parameter list (void* is different: a generic pointer).
  • Examiners also test that an array is a derived type, not a primitive one, and that a function counts as a derived type in the standard C classification, which surprises most candidates.

Q3. Differentiate scope from lifetime using a local variable as an example.

Answer

  • Scope: where a name can be used in source code.
  • Storage duration: how long storage is available.
  • Object lifetime: when an object exists in that storage; construction/destruction can make this more specific than storage duration.
  • Ordinary local: normally automatic storage; its lifetime ends when its block exits.
  • Static local: block scope, persistent storage across calls.
  • Dynamic object: can outlive the local pointer that first referred to it.
  • Implementation: “stack” and “data segment” describe common implementations, not universal language requirements.
#include <iostream>
using namespace std;

int g = 100;                 // global: file scope, static lifetime

void counterDemo() {
    int autoVar = 0;         // block scope, AUTOMATIC lifetime -> reset every call
    static int stat = 0;     // block scope, STATIC lifetime   -> survives calls
    autoVar++;  stat++;
    cout << autoVar << " " << stat << endl;
}

int main() {
    counterDemo();   // 1 1
    counterDemo();   // 1 2
    counterDemo();   // 1 3   <- stat remembers; autoVar does not
    // cout << autoVar;  // ERROR: out of scope here
    return 0;
}
Variable kindScopeLifetimeStored in
Local (automatic)Its block onlyUntil the block exitsStack
Static localIts block onlyWhole program runData segment
GlobalWhole file / programWhole program runData segment
Dynamic (new/malloc)Wherever the pointer reachesUntil delete/free is calledHeap
  • MCQ trap: a static local has block scope but program lifetime — the classic "which of these keeps its value between calls?"
  • question.
  • Note also the reverse mismatch: memory from new has a lifetime that outlives the scope of the pointer that created it, and forgetting delete causes a memory leak.
  • Returning the address of a local (return &x;) yields a dangling pointer, because the scope ended and the lifetime ended together.

Q4. What is the difference between implicit and explicit type conversion?

Answer

  • Implicit conversion: applied without an explicit cast, according to the language's conversion rules.
  • Explicit conversion: requested with a cast, such as static_cast<double>(sum).
  • Information loss: either can lose range or precision; implicit does not mean safe or lossless.
  • Integer division: double x = 5 / 2; gives 2.0 because division happened first.
  • Correct form: double x = 5.0 / 2; gives 2.5.
  • Floating to integer: representable values are truncated toward zero; range must be valid.
  • Avoid: a universal “char → short → int → long → float → double” safety ladder.
AspectImplicit ConversionExplicit Conversion (Cast)
Performed byThe compiler, automaticallyThe programmer
SyntaxNone; happens silently(int)x or static_cast<int>(x)
DirectionUsually wideningOften narrowing
Data lossUsually nonePossible and expected
Exampledouble d = 5;int n = (int)3.99;
int    a = 7, b = 2;
double d;

d = a / b;          // 3.0  -- TRAP: int/int = 3 FIRST, then widened
d = (double)a / b;  // 3.5  -- cast forces real division
d = a / 2.0;        // 3.5  -- 2.0 is a double, so a is promoted

int n = (int)3.99;          // 3  -- TRUNCATES, does not round
int m = static_cast<int>(-3.99);  // -3 -- truncates toward zero
char c = 'A';
int  k = c + 1;             // 66 -- 'A' implicitly promoted to its ASCII 65

Conversion trap: a representable floating-to-integer conversion truncates toward zero. Use an appropriate rounding function rather than assuming x + 0.5 handles every sign and case; cast before integer division when a fractional result is needed.

Q5. Why does declaring int x; without initialization still "work" but produce unpredictable output if used before assignment?

Answer

  • Declaration/definition: int x; defines an ordinary local object without giving it a usable initial integer value.
  • Initialization: int x = 0; establishes a known value immediately.
  • Reading too early: do not predict a “garbage” number; an uninitialized read is not a valid way to obtain a value.
  • Size: use sizeof(int); four bytes is common, not guaranteed.
  • Practice: initialise counters and accumulators and enable compiler warnings.
  • Contrast: static-storage objects have zero-initialization rules that ordinary automatic locals do not share.
#include <iostream>
using namespace std;

int counter;            // GLOBAL/static -> automatically zero-initialised to 0

int main() {
    int x;              // LOCAL (automatic) -> garbage, NOT zero
    int y = 0;          // safely initialised
    cout << counter;    // always 0
    cout << x;          // unpredictable: 0, 32767, -858993460, ...
    x = 10;             // from here on x is well defined
    cout << x;          // 10
    return 0;
}

Accumulator rule: initialise the running total before the first addition.

int sum;                        // BUG: starts at garbage
for (int i = 1; i <= 5; i++) sum += i;
cout << sum;                    // should be 15; prints garbage + 15
// FIX: int sum = 0;

MCQ trap: global and static variables ARE zero-initialised automatically; local (automatic) variables are NOT. This asymmetry is the single most-tested point here. Always initialise counters and accumulators at declaration — and compile with -Wall so the warning is not missed.

8. 📜 Past-Paper Questions & MCQs (CSS 2016–2026)

2019 · Paper-I · Q3(c) · 5 marks

Recall cue: Explain preprocessing; give include, macro and conditional-compilation examples.

Q. What is the role of preprocessor directives? Give three examples in C++.

Answer — key points

  • Role: preprocessor directives are instructions beginning with # that are handled before compilation. They include files, define macros and constants, and select which code is compiled.
  • #include: inserts a header file, e.g. #include <iostream>.
  • #define: defines a macro or constant, e.g. #define PI 3.14159.
  • #ifndef / #define / #endif: conditional compilation and include guards, which stop a header from being included twice.
  • Others: #undef, #ifdef, #pragma once.

MCQs

2025 P-I · Q6. Which of the following is the false statement in the C language?

  • (A) static a = 10;
  • (B) static int func (int);
  • (C) static static int a; ✅
  • (D) None of these
  • Answer: (C) static static int a;.
  • Why: a declaration may have only one storage-class specifier, so repeating static is a compile error. (A) is accepted by older C compilers (the type defaults to int), and (B) is a valid declaration of a function with internal linkage.

Recall check and coverage

  • Explain the three learning outcomes at the top without looking.
  • Reproduce one example or trace and test a boundary case.
  • Answer each self-test, then compare with the key.
  • Attempt each recorded past-paper task on this page.

Recorded written references: 2019 · Paper-I · Q3(c) · 5 marks

Evidence limit: this page preserves the question records found in your Notion notes. Disputed labels and questions not checked against original PDFs remain flagged in the Question Bank; this is not a claim of exhaustive original-paper verification.