TUpapers logo TUpapers.com

Explore TUpapers

Study materials and tools in one place.

  • Dashboard
  • Blog
  • Search
  • About

Follow us

TUpapers on Facebook
TUpapers on Instagram
Contact TUpapers on WhatsApp
TUpapers subreddit on Reddit
Student Dashboard Student Dashboard
TUpapers logo TUpapers.com
  • Blog
  • About

Support Us

Your support helps us for further development and maintenance of site and resources!

Bank QR code for payment
eSewa QR code for payment
Khalti QR code for payment

The best way to support TUpapers is by purchasing a Premium Suscription or Notes Every purchase directly funds new features, better study resources, and platform maintenance.

On this chapter

Introduction to C programming language and basics

All Chapters

Dashboard

Select a chapter to start reading

Programming in C Notes | BCA First Semester | TU Papers

1 Chapter 1 Preview

No preview available.

Notes for this subject are coming soon — check back later.

Student Dashboard

Continue Reading

Get full notes inside the dashboard, along with other study tools.

Unit 1: Introduction to C Programming Language and Basics [5 Hours]

This unit lays the foundation for everything else in C. It covers how programming languages evolved, why C still matters, how a C program is structured and turned into a running executable, and the basic building blocks (tokens, variables, data types, type casting, and operators) that every later program depends on. Expect direct theory questions on structure, compilation stages, storage classes, and operator precedence, plus short-answer questions on tokens and data types.

1.1 Evolution of Programming Languages

Core Definition

The evolution of programming languages refers to the historical progression of languages from raw binary machine instructions to high-level, human-readable languages, developed to make programming faster, easier, and more portable across machines.


Computers only understand 0s and 1s. Writing programs directly in 0s and 1s was painfully slow and error-prone, so over decades programmers built layers of easier-to-use languages on top of machine code, each generation moving further away from hardware and closer to human thinking.

Detailed Explanation

Programming languages are grouped into five generations, each solving a limitation of the one before it.

First Generation Language (1GL) – Machine Language: raw binary (0s and 1s) understood directly by the CPU. Fast to execute but extremely hard to write, debug, and impossible to reuse across different processor types.

Second Generation Language (2GL) – Assembly Language: replaces binary with mnemonic codes (e.g., MOV, ADD). An assembler converts it to machine code. Easier than 1GL but still hardware-specific.

Third Generation Language (3GL) – High-Level Languages: languages like C, C++, and Java use English-like syntax and are portable across machines through compilers. C belongs to this generation.

Fourth Generation Language (4GL): closer to natural language, focused on what result is needed rather than how to get it. SQL is the classic example: you state the data you want, not the retrieval steps.

Fifth Generation Language (5GL): uses constraints, logic, and AI-based reasoning so the system decides the steps itself. Prolog and AI-driven languages fall here.

Moving up generations increases readability and developer speed but does not automatically increase execution speed. Low-level languages remain faster for hardware-critical tasks like operating system kernels or device drivers.

Let's Break It Down

Think of giving directions to a friend. 1GL is drawing the exact muscle movements needed to walk there. 2GL is writing short coded instructions like "L2, R1, R3." 3GL is simply saying "turn left at the temple, then right." 4GL is just saying "take me to the temple" and letting GPS figure out the route. 5GL is the GPS predicting where you want to go before you even ask.

Common Mistake

Students assume a higher generation language always runs faster than a lower one. In reality, higher generations trade raw execution speed for programmer productivity and portability; assembly and machine code remain faster for time-critical, hardware-level operations.

Test Yourself

  1. Why is assembly language considered easier than machine language but still hardware-dependent?
  2. Give one reason SQL is classified as a 4GL rather than a 3GL.

Answers: 1) Assembly uses mnemonic codes instead of binary, but each mnemonic set is specific to a particular processor's instruction set.
2) SQL describes the desired result (what data to fetch) instead of step-by-step retrieval logic (how to fetch it), which is the defining trait of 4GLs.

Summary

  • Languages evolved from binary (1GL) to logic-based systems (5GL) to reduce programming difficulty.
  • C is a Third Generation Language: portable, structured, and high-level relative to assembly.
  • Higher generation does not mean faster execution, only easier and faster development.

One-Liner Revision

Programming languages evolved through five generations, from raw binary to natural-language-like systems, trading closeness to hardware for ease of human use.

1.2.1 History of C

Core Definition

C is a general-purpose, procedural programming language developed by Dennis Ritchie at Bell Labs between 1969 and 1973, derived from the earlier B and BCPL languages.


C was built so the Unix operating system could be rewritten in a language more powerful than assembly but still close enough to hardware to be efficient. That dual nature, powerful yet close to the machine, is why C is still taught first.

Detailed Explanation

C's lineage: ALGOL → BCPL (Basic Combined Programming Language) → B (simplified by Ken Thompson) → C (Dennis Ritchie added data types and structure). C was first used to rewrite the Unix kernel, proving that an operating system did not need to be written entirely in assembly. It was standardized to keep implementations consistent across vendors: ANSI C (1989, also called C89), ISO C90 (1990, essentially the same standard adopted internationally), C99 (added features like inline functions and variable-length arrays), and C11 (added multithreading and improved Unicode support) [verify exact feature lists per standard].

Summary

  • Created by Dennis Ritchie at Bell Labs (1969–1973).
  • Evolved from BCPL and B; built to rewrite Unix.
  • Standardized as ANSI C (1989) and later C99, C11.

One-Liner Revision

C was created by Dennis Ritchie at Bell Labs to rewrite Unix, evolving from BCPL and B before being standardized as ANSI C.

1.2.2 Characteristics of C

Core Definition

The characteristics of C are the defining properties, procedural, structured, portable, efficient, and close to hardware, that explain why it remains a foundation for system and application programming.


These are simply the reasons C is still relevant: it runs fast, works on almost any machine, lets you organize code into reusable blocks, and lets you talk directly to memory when needed.

Detailed Explanation

Procedural language: a C program is a sequence of instructions executed step by step inside functions, following a clear procedure.

Structured language: code is organized into functions and blocks, making large programs easier to read, debug, and maintain instead of one long unbroken script.

Middle-level language: C combines low-level features (direct memory access through pointers, bit manipulation) with high-level features (functions, loops, structured syntax), sitting between assembly and languages like Python.

Portability: a C program written on one machine can run on another with little or no change, because the compiler, not the program, handles hardware-specific translation.

Efficient and fast: C compiles to very compact machine code with minimal runtime overhead, which is why operating systems and embedded systems still use it.

Rich library support: the Standard Library (stdio.h, stdlib.h, string.h, math.h, etc.) provides ready-made functions for input/output, memory management, and string handling.

Case-sensitive:Total and total are treated as two different identifiers.

Extensible: programmers can add their own functions and data types (via structures, typedef) to extend the language's built-in capability.

Pointer and dynamic memory support: C allows direct access to memory addresses and manual allocation/deallocation, giving fine-grained control unavailable in many higher-level languages.

Test Yourself

  1. Why is C called a "middle-level" language?
  2. How does case sensitivity affect identifier naming in C?

Answers: 1) It offers low-level features like pointers and direct memory access while also supporting high-level structured constructs like functions and loops.
2) Identifiers that differ only in letter case (e.g., sum and Sum) are treated as completely different names.

Summary

  • C is procedural, structured, and middle-level (low-level power with high-level structure).
  • Portable, efficient, case-sensitive, and extensible through user-defined types.
  • Pointer support gives direct memory control, which is rare in higher-level languages.

One-Liner Revision

C is a fast, portable, structured middle-level language that is case-sensitive and gives direct control over memory.

1.2.3 Applications of C

Core Definition

The applications of C are the real-world domains where its speed and hardware closeness make it the preferred or foundational choice.


Wherever software needs to run fast and close to hardware, C is usually somewhere underneath it.

Detailed Explanation

Operating systems: Unix, Linux kernel, and parts of Windows are written in C because it can manage hardware resources directly.

Embedded systems: microcontrollers in appliances, automotive systems, and IoT devices run C due to its small memory footprint.

Compilers and interpreters: many language compilers (including early Python implementations) are themselves written in C.

Database engines: core engines of systems like MySQL and parts of PostgreSQL use C for performance-critical operations.

Device drivers: hardware drivers require direct register and memory access, which C provides.

Game development and graphics engines: performance-critical engine cores are often written in C or C-derived languages.

Summary

  • Used in operating systems, embedded systems, compilers, database engines, drivers, and game engines.
  • Chosen wherever speed and direct hardware access matter most.

One-Liner Revision

C powers operating systems, embedded devices, compilers, and drivers wherever speed and hardware control are critical.

1.3 Structure of a C Program

Core Definition

The structure of a C program is the fixed arrangement of sections, documentation, preprocessor directives, global declarations, the main() function, and user-defined functions, in which every C program must be organized for the compiler to process it correctly.


Every C program follows the same skeleton, like a form with fixed sections you fill in: a place for comments, a place to bring in libraries, a place for global data, the main starting point, and optional extra functions.

Detailed Explanation

A typical C program is built from these sections, in order:

1. Documentation section: comments describing the program's purpose, author, and date. Ignored by the compiler, used by humans.

2. Preprocessor directive section: lines starting with #, such as #include <stdio.h>, that bring in header files before compilation begins.

3. Global declaration section: variables and function prototypes declared outside any function, accessible throughout the file.

4. main() function section: every executable C program must have exactly one main() function; execution always begins here, regardless of where other functions are placed in the file.

5. User-defined function section: additional functions, defined either before or after main(), that main() can call.

SectionPurposeCompiler-visible?
DocumentationExplains program intent to readersNo (ignored)
Preprocessor directivesIncludes headers, defines macrosYes (processed first)
Global declarationsShared variables/prototypes across functionsYes
main() functionProgram's entry pointYes (mandatory)
User-defined functionsReusable blocks of logicYes (optional)
#include <stdio.h> int total = 0; int add(int a, int b); int main() { total = add(5, 3); printf("%d", total); return 0;}int add(int a, int b) { return a + b;}

Let's Break It Down

Picture building a house. The documentation section is the architect's notes on the blueprint. Preprocessor directives are the imported materials list. Global declarations are the shared utility lines (electricity, water) running through the whole house. main() is the front door, the only entry point everyone uses first. User-defined functions are the individual rooms, built separately but reachable from the entrance.

Common Mistake

Students think the compiler executes code top-to-bottom regardless of function placement. In reality, execution always starts at main() no matter where it appears in the file; other functions only run when called from main() or from a function it calls.

Test Yourself

  1. Why must every executable C program contain a main() function?
  2. What happens if a function is defined after main() but never declared before it?

Answers: 1) main() is the fixed entry point; the operating system/runtime always begins execution there.
2) Without a prior prototype, the compiler may not know the function's signature when it is first called inside main(), which can cause a compilation warning or error depending on the compiler.

Summary

  • A C program has five sections: documentation, preprocessor directives, global declarations, main(), and user-defined functions.
  • Execution always begins at main(), regardless of physical placement of other functions.
  • Global declarations and function prototypes make names visible across the whole file.

One-Liner Revision

A C program is organized into documentation, preprocessor directives, global declarations, a mandatory main() entry point, and optional user-defined functions.

1.4 Compilation and Execution Process of a C Program

Core Definition

The compilation and execution process is the sequence of stages, preprocessing, compilation, assembly, linking, and loading, through which human-readable C source code is converted into a running machine-executable program.


You write code in English-like syntax, but the CPU only understands binary. Several tools work one after another to translate your code step by step until it becomes something the machine can actually run.

Detailed Explanation

The process happens in five ordered stages:

Step 1 → Preprocessing: the preprocessor scans the source file (.c) and resolves all lines starting with #. It expands #include by copying header file contents in, replaces #define macros with their values, and removes comments. Output: an expanded source file with no directives left.

Step 2 → Compilation: the compiler takes the preprocessed code and translates it into low-level assembly language for the target CPU, while also performing syntax and semantic checking. If there are syntax errors, the process stops here. Output: an assembly file (.s).

Step 3 → Assembly: the assembler converts the assembly code into machine-readable object code (binary, but not yet a complete program). Output: an object file (.o or .obj), containing machine instructions plus unresolved references to library functions like printf.

Step 4 → Linking: the linker combines the object file with the object code of library functions (such as the C standard library) and resolves all unresolved references, producing one self-contained executable file (.exe on Windows, no extension on Unix/Linux).

Step 5 → Loading and Execution: the loader copies the executable into main memory (RAM), sets up the program's runtime environment, and hands control to the operating system, which begins executing instructions starting from main().

StageToolInputOutput
PreprocessingPreprocessorsource.cExpanded source
CompilationCompilerExpanded sourceAssembly code (.s)
AssemblyAssemblerAssembly codeObject code (.o)
LinkingLinkerObject code + librariesExecutable file
Loading/ExecutionLoader/OSExecutableRunning process

Let's Break It Down

It is like preparing a meal kit for shipping. Preprocessing is gathering all the ingredients listed in the recipe. Compilation is chopping and prepping them into a usable form. Assembly is sealing each prepped ingredient into a labeled packet. Linking is packing every packet plus the shared spice kit (the library) into one sealed box. Loading is the delivery truck placing that box on your kitchen counter, ready to cook (execute) the moment you open it.

Common Mistake

Students confuse "compilation" with the entire build process. Strictly, compilation is only the single stage that converts preprocessed code into assembly; preprocessing, assembling, linking, and loading are separate stages that happen before the program actually runs.

Test Yourself

  1. What does the linker do that the compiler cannot do alone?
  2. At which stage would an undefined reference to a library function like printf typically be caught?

Answers: 1) The linker resolves references to external library functions and combines multiple object files into one complete executable; the compiler only translates a single source file into assembly/object form.
2) During the linking stage, when the linker tries to resolve the function reference and cannot find its definition.

Summary

  • Five stages: preprocessing → compilation → assembly → linking → loading/execution.
  • Each stage has a dedicated tool and produces a specific intermediate file.
  • The compiler only converts code to assembly; turning that into a runnable program needs the assembler and linker too.

One-Liner Revision

C source code becomes a running program through preprocessing → compilation → assembly → linking → loading, each handled by a dedicated tool.

1.5 C Tokens (Overview)

Core Definition

A token is the smallest individual unit of a C program that the compiler recognizes as meaningful, such as a keyword, identifier, constant, string literal, or operator.


Just like a sentence is built from words, a C program is built from tokens; the compiler reads the source code token by token to understand what you wrote.

Detailed Explanation

C recognizes five categories of tokens, each covered in detail next: Keywords (reserved words with fixed meaning), Identifiers (programmer-defined names), Constants (fixed values that never change), String literals (sequences of characters in double quotes), and Operators (symbols that act on data). The compiler's first internal job, lexical analysis, is to break the raw source text into this stream of tokens before any further checking happens.

Summary

  • Tokens are the smallest meaningful units of a C program.
  • Five categories: keywords, identifiers, constants, string literals, operators.
  • The compiler's lexical analysis stage breaks source code into tokens first.

One-Liner Revision

Tokens are the smallest meaningful pieces of a C program: keywords, identifiers, constants, string literals, and operators.

1.5.1 Keywords

Core Definition

Keywords are reserved words in C that have a predefined meaning to the compiler and cannot be used as identifiers (variable, function, or label names).


These are words the language has already claimed for its own grammar, like "int" or "if," so you are not allowed to reuse them as your own variable names.

Detailed Explanation

Standard C has 32 keywords, always written in lowercase. They fall into functional groups:

CategoryExamples
Data type keywordsint, char, float, double, void, short, long, unsigned, signed
Control flow keywordsif, else, switch, case, default, for, while, do, break, continue, goto, return
Storage class keywordsauto, register, static, extern
Structure/derived type keywordsstruct, union, enum, typedef
Other keywordssizeof, const, volatile

Because keywords are fixed, the compiler always interprets them the same way; you cannot redefine what if or int means inside your program.

Common Mistake

Trying to name a variable using a keyword, for example writing int for = 5;, causes a compilation error because for is reserved and cannot be reused as an identifier.

Test Yourself

  1. Why can't float be used as a variable name?

Answers: 1) float is a reserved keyword with a fixed meaning (a data type), so the compiler will not allow it to be reused as an identifier.

Summary

  • 32 reserved, lowercase words with fixed compiler-defined meaning.
  • Grouped into data type, control flow, storage class, and structure-related keywords.
  • Cannot be reused as identifiers.

One-Liner Revision

Keywords are C's 32 reserved, lowercase words with fixed meanings that can never be used as identifier names.

1.5.2 Identifiers

Core Definition

An identifier is a programmer-chosen name used to identify a variable, function, array, or any other user-defined entity in a C program.


Identifiers are simply the names you invent for things in your program, like naming a variable totalMarks so you can refer to it later.

Detailed Explanation

An identifier must follow strict naming rules:

Rule 1: must begin with a letter (A–Z, a–z) or an underscore (_), never a digit. In practice: _count is valid, 1count is not.

Rule 2: after the first character, it can contain letters, digits, and underscores, but no spaces or special characters like @, $, or -.

Rule 3: it cannot be a reserved keyword.

Rule 4: it is case-sensitive, so Sum and sum are two different identifiers.

Rule 5: some compilers only guarantee uniqueness up to a certain number of significant characters (historically 31), so extremely long names risk being treated as identical [verify exact limit per compiler].

IdentifierValid?Reason
total_marksValidStarts with letter, uses underscore
_tempValidStarts with underscore
2ndValueInvalidStarts with a digit
my-varInvalidHyphen is not allowed
intInvalidReserved keyword

Common Mistake

Students try to start an identifier with a digit (e.g., 1total) or insert a space (my total), both of which the compiler rejects; only letters, digits (after the first character), and underscores are allowed, with no spaces.

Test Yourself

  1. Is Total_1 a valid identifier? Why?
  2. Are sum and Sum the same identifier in C?

Answers: 1) Yes, it starts with a letter and contains only letters, a digit, and an underscore.
2) No, C is case-sensitive, so they are treated as two distinct identifiers.

Summary

  • Identifiers must start with a letter or underscore, never a digit.
  • Can contain letters, digits, and underscores only; no spaces or special symbols.
  • Case-sensitive and cannot match a reserved keyword.

One-Liner Revision

Identifiers are programmer-given names that must start with a letter or underscore and contain only letters, digits, and underscores.

1.5.3 Constants

Core Definition

A constant is a fixed value in a C program that does not change during program execution, such as a number or a single character.


A constant is a value you write directly into the code that stays exactly the same every time the program runs, unlike a variable, which can change.

Detailed Explanation

C supports several categories of constants:

Integer constants: whole numbers without a decimal point, e.g., 10, -25. Suffixes can specify type: U/u for unsigned, L/l for long, UL for unsigned long.

Floating-point (real) constants: numbers with a decimal point or exponent, e.g., 3.14, 2.5e3. Suffix f/F marks a value as float instead of the default double.

Character constants: a single character enclosed in single quotes, e.g., 'A', '5'; internally stored as the character's ASCII integer code.

(String constants, sequences of characters in double quotes, are covered separately as String Literals below, since they behave differently from single-value constants: they are stored as an array of characters.)

TypeExampleNotes
Integer100, -7, 50000ULNo decimal point; suffixes change type
Floating-point3.14, 2.0e-3, 9.5fDecimal point or exponent; default type double
Character'A', '7', '\n'Single character in single quotes; stored as ASCII code

Common Mistake

Writing a character constant with double quotes ("A") instead of single quotes ('A'). "A" is actually a string literal (a two-element char array including the null terminator), not a single character constant.

Test Yourself

  1. What value does the character constant 'A' actually store internally?

Answers: 1) It stores the ASCII integer code for 'A', which is 65.

Summary

  • Constants are fixed values: integer, floating-point, and character constants.
  • Suffixes (U, L, f) can specify a constant's exact type.
  • Character constants use single quotes and are stored as ASCII codes.

One-Liner Revision

Constants are fixed integer, floating-point, or character values that never change during execution.

1.5.4 String Literals

Core Definition

A string literal is a sequence of characters enclosed in double quotes, automatically terminated by a null character (\0) and stored internally as a character array.


A string literal is just text in double quotes, like "Hello", and C secretly adds an invisible marker at the end so it knows where the text stops.

Detailed Explanation

Writing "Hello" creates an array of 6 characters in memory: H, e, l, l, o, and the hidden null terminator \0, even though only 5 visible characters were typed. String literals often include escape sequences, special two-character codes representing characters that cannot be typed directly.

Escape SequenceMeaning
\nNew line
\tHorizontal tab
\\Backslash character
\'Single quote character
\"Double quote character
\0Null character (string terminator)

Common Mistake

Students forget the hidden null terminator when calculating memory size; "Hi" looks like 2 characters but actually occupies 3 bytes in memory because of the automatically added \0.

Summary

  • String literals are double-quoted text, stored as a character array.
  • A hidden null terminator (\0) is always added at the end.
  • Escape sequences represent special characters inside string literals.

One-Liner Revision

A string literal is double-quoted text stored as a character array, automatically ending with a hidden null terminator.

1.5.5 Operators (as a Token Category)

Core Definition

An operator is a symbol that instructs the compiler to perform a specific mathematical, relational, or logical action on one or more operands.


Operators are just the action symbols of the language, like + or >, that tell the computer what to do with the values around them.

Detailed Explanation

As a token type, an operator simply marks where an operation happens in an expression, such as + in a + b. C groups operators into several functional families (arithmetic, relational, logical, bitwise, assignment, and special operators), each covered in full depth, with examples and worked behaviour, in Section 1.9.

Summary

  • Operators are symbols that act on operands to perform operations.
  • Full classification (arithmetic, relational, logical, bitwise, etc.) is detailed in Section 1.9.

One-Liner Revision

Operators are symbols that act on data; their full classification is covered separately under Operators and Expressions.

1.6.1 Declaration and Initialization of Variables

Core Definition

Declaration tells the compiler a variable's name and data type so it can reserve memory for it; initialization assigns it a starting value at the moment it is declared.


Declaring a variable is like reserving a labeled box of a certain size; initializing it is putting something into that box right when you create it.

Detailed Explanation

Syntax for declaration: data_type variable_name;, e.g., int age; reserves memory of the size required for an int and labels it age. At this point its value is undefined (garbage) until assigned. Combined declaration and initialization: data_type variable_name = value;, e.g., int age = 20; reserves the memory and immediately stores 20 in it. Multiple variables of the same type can be declared together: int a = 5, b, c = 10;, where b remains uninitialized.

int age; int age = 20; int x = 1, y = 2, z; 

Common Mistake

Using a variable before initializing it, for example printing age right after int age; without assigning it a value, reads unpredictable garbage memory content rather than a safe default like 0.

Summary

  • Declaration reserves memory and a type for a variable; it does not give it a meaningful value.
  • Initialization assigns a starting value at the point of declaration.
  • Uninitialized variables hold unpredictable garbage values until assigned.

One-Liner Revision

Declaration reserves a variable's memory and type; initialization gives it a starting value at the same time.

1.6.2 Scope of Variables

Core Definition

The scope of a variable is the region of the program within which that variable's name can be legally accessed and used.


Scope answers the question: "From where in my code can I actually use this variable's name?"

Detailed Explanation

Local (block) scope: a variable declared inside a function or inside {} braces (a block, like inside an if or for) is only accessible within that block; it disappears once the block ends.

Global (file) scope: a variable declared outside all functions is accessible from any function in the same file, from the point of declaration onward.

Function scope: applies specifically to labels used with goto; a label is visible anywhere within the function it is defined in, regardless of block nesting.

When a local variable has the same name as a global variable, the local one takes priority inside its block, temporarily "hiding" the global one; this is called variable shadowing.

Scope TypeWhere DeclaredAccessible From
Local/BlockInside a function or {} blockOnly within that block
Global/FileOutside all functionsAny function in the file, after declaration
FunctionAs a goto labelAnywhere in the same function
int x = 10; void show() { int x = 5; printf("%d", x); }

Common Mistake

Assuming a local variable with the same name as a global variable overwrites the global one. It does not; it only shadows (temporarily hides) it within its own block. The global variable's value is untouched outside that block.

Test Yourself

  1. What happens to a local variable once its enclosing block finishes execution?
  2. If a local variable shares its name with a global variable, which one is used inside that block?

Answers: 1) It goes out of scope and its memory is released; it can no longer be accessed.
2) The local variable takes priority and is used inside that block; the global variable is temporarily shadowed, not destroyed.

Summary

  • Scope determines where a variable's name can be legally used.
  • Local/block scope is limited to the enclosing block; global scope spans the whole file.
  • A local variable can shadow a global one with the same name within its block.

One-Liner Revision

Scope defines where a variable's name is visible: local to a block, or global across the whole file.

1.6.3 Lifetime (Storage Duration) of Variables

Core Definition

The lifetime of a variable is the duration for which it occupies memory during program execution, from the moment it is created until the moment that memory is released, and this is controlled by its storage class.


Lifetime answers: "How long does this variable actually exist in memory, even if its name later goes out of scope?"

Detailed Explanation

Lifetime in C is governed by four storage class keywords:

auto (Automatic): the default storage class for variables declared inside a function/block. Memory is created when the block is entered and destroyed when the block exits. Most ordinary local variables are auto by default, so the keyword is rarely written explicitly.

register: requests that the compiler store the variable in a CPU register instead of regular memory for faster access; it is a hint, not a guarantee, since registers are limited. Cannot have its address taken with &.

static: a variable retains its value between function calls instead of being recreated each time. It is initialized only once, the first time the block is entered, and persists for the entire program's run even though its scope may still be local to the function.

extern: declares that a variable is defined in another file or elsewhere in the same file; it has global lifetime (exists for the whole program) but does not allocate new memory at the point of declaration, it just refers to existing memory.

Storage ClassDefault Initial ValueScopeLifetime
autoGarbage (undefined)Local (block)Until block exits
registerGarbage (undefined)Local (block)Until block exits
static0 (by default)Local or globalEntire program run
extern0 (by default, set in original file)GlobalEntire program run
void counter() { static int count = 0; count++; printf("%d\n", count);}

Let's Break It Down

Think of a hostel room. An auto variable is like a guest who checks in and checks out within the same day, the room resets completely after they leave. A static variable is like a permanent resident, the room and their belongings stay exactly as they left them, ready the next time they return, even though other guests can use the lobby (scope) only while they are physically present.

Common Mistake

Confusing scope with lifetime. A static local variable still has local scope (only that function can use its name) but its lifetime spans the whole program, unlike a normal local (auto) variable whose memory is destroyed once its block ends.

Test Yourself

  1. Why does a static local variable retain its value across multiple function calls?
  2. What is the key difference between a variable's scope and its lifetime?

Answers: 1) Because static allocates its memory once for the entire program duration and initializes it only on the first call; subsequent calls reuse the same memory without re-initializing it.
2) Scope is about where the variable's name can be accessed in the code; lifetime is about how long the variable's memory actually exists during execution. A variable can have local scope but program-long lifetime, as with static.

Summary

  • Lifetime is controlled by storage class: auto, register, static, extern.
  • auto and register exist only while their block is active; static and extern persist for the whole program.
  • Scope and lifetime are independent concepts; static variables prove this clearly.

One-Liner Revision

A variable's lifetime, how long it exists in memory, is set by its storage class: auto/register last only within their block, while static/extern last the whole program.

1.7.1 Basic (Primary) Data Types

Core Definition

Basic data types are the fundamental, built-in types in C, int, char, float, double, and void, that directly represent the simplest kinds of data without being built from other types.


These are the five core "boxes" the language gives you out of the box: whole numbers, single characters, decimal numbers (two precisions), and a special "nothing" type.

Detailed Explanation

int: stores whole numbers (no decimal point). Typically 2 or 4 bytes depending on the system/compiler.

char: stores a single character, internally as a 1-byte integer (its ASCII code).

float: stores single-precision decimal numbers, typically 4 bytes, with about 6–7 significant digits of precision.

double: stores double-precision decimal numbers, typically 8 bytes, with about 15–16 significant digits of precision, used when more accuracy is needed than float provides.

void: represents the absence of a type, used for functions that return no value, or for generic pointers that can point to any data type.

Modifiers (signed, unsigned, short, long) can be combined with int and char to adjust their size and range. For an n-bit signed integer, the range is calculated as: Minimum = −2(n−1), Maximum = 2(n−1) − 1. For a 16-bit signed int, this gives a range of −32768 to 32767; for a 32-bit signed int, the range is −2147483648 to 2147483647.

TypeTypical SizeTypical Range (signed)Format Specifier
char1 byte−128 to 127%c
int2 or 4 bytes−32768 to 32767 (2 bytes) [verify per system]%d
float4 bytes~1.2E−38 to 3.4E+38 [verify]%f
double8 bytes~2.3E−308 to 1.7E+308 [verify]%lf
voidNo size (no value stored)Not applicableNot applicable

Common Mistake

Assuming int is always exactly 2 or always exactly 4 bytes across all systems. The actual size is compiler and platform dependent; the safe way to check it on a given system is the sizeof(int) operator rather than memorizing one fixed number.

Test Yourself

  1. Why does double offer more precision than float?
  2. What is the range formula for an n-bit signed integer, and what does it give for 16 bits?

Answers: 1) double typically uses 8 bytes compared to float's 4 bytes, allowing more bits for the significant digits and giving roughly double the decimal precision.
2) Range = −2^(n−1) to 2^(n−1) − 1; for 16 bits this gives −32768 to 32767.

Summary

  • Five basic types: int, char, float, double, void.
  • Modifiers (signed, unsigned, short, long) adjust size and range.
  • Signed n-bit integer range = −2^(n−1) to 2^(n−1) − 1.

One-Liner Revision

The basic data types, int, char, float, double, and void, represent whole numbers, characters, decimals of two precisions, and "no value" respectively.

1.7.2 Derived Data Types

Core Definition

Derived data types are types built from basic data types using the language's own constructs, namely arrays, pointers, and functions.


These are not brand-new kinds of data, they are basic types combined or arranged in a new way, like a row of boxes (array) or a note pointing to where a box is kept (pointer).

Detailed Explanation

Arrays: a fixed-size collection of elements of the same data type stored in contiguous memory, accessed using an index, e.g., int marks[5]; stores 5 integers under one name.

Pointers: a variable that stores the memory address of another variable rather than a direct value, e.g., int *p; can hold the address of an int variable.

Functions: a named, reusable block of code that takes inputs (parameters) and optionally returns a value of a specific type; the function itself is treated as having a derived type based on its return type and parameters.

Derived TypeBuilt FromExample
ArrayMultiple elements of one basic typeint marks[5];
PointerAddress of a basic/derived typeint *p;
FunctionBasic/derived return type + parametersint add(int a, int b);

One-Liner Revision

Derived data types, arrays, pointers, and functions, are built by arranging or referencing basic data types in new ways.

Summary

  • Three derived types: arrays, pointers, functions.
  • Arrays group same-type elements; pointers store addresses; functions package reusable logic.

1.7.3 User-Defined Data Types

Core Definition

User-defined data types let a programmer create custom data types using structure, union, enumeration, or typedef, rather than relying only on built-in types.


When the built-in types don't naturally describe what you're modeling, like a student with a name, roll number, and marks together, C lets you design your own type to group them.

Detailed Explanation

Structure (struct): groups variables of different data types under one name, each member getting its own separate memory. Useful for modeling real-world records, e.g., a student record with name, roll number, and marks together.

Union: similar syntax to struct, but all members share the same memory location, so only one member holds a valid value at a time; total size equals the size of its largest member.

Enumeration (enum): assigns readable names to a set of integer constants, e.g., enum Day {MON, TUE, WED}; where MON=0, TUE=1, WED=2 by default, improving code readability over plain numbers.

typedef: creates an alias (alternate name) for an existing type, making complex declarations shorter and code more readable, e.g., typedef unsigned int uint; lets you write uint instead of unsigned int.

TypeMemory BehaviorUse Case
structEach member gets separate memoryGrouping related but different fields (a record)
unionAll members share the same memoryMemory-efficient storage when only one value is needed at a time
enumStored as integers internallyNaming a fixed set of related constants
typedefNo new memory; just an aliasSimplifying complex or repeated type names

Common Mistake

Confusing struct and union sizes. A struct's total size is roughly the sum of its members' sizes; a union's size equals only its largest member's size, since members overlap in the same memory.

Test Yourself

  1. Why is a union's size determined by its largest member rather than the sum of all members?

Answers: 1) Because all members of a union occupy the same shared memory location rather than separate ones, so the union only needs enough space for the biggest member to hold any one of them at a time.

Summary

  • Four user-defined types: struct, union, enum, typedef.
  • struct gives each member separate memory; union shares memory among members.
  • enum names integer constants; typedef just renames an existing type.

One-Liner Revision

User-defined types, struct, union, enum, and typedef, let programmers build or rename types to fit real-world data better than built-in types alone.

1.8 Type Casting: Implicit and Explicit Type Conversion

Core Definition

Type casting is the process of converting a value from one data type to another, either automatically by the compiler (implicit) or manually by the programmer (explicit).


Type casting is just changing what "kind" of value something is treated as, like turning a whole number into a decimal number so a calculation works the way you want.

Detailed Explanation

Implicit type conversion (automatic/coercion): the compiler converts one operand's type to another automatically, usually from a smaller/lower-ranked type to a larger/higher-ranked one, following C's usual arithmetic conversion rules, so no data is lost. Example: in int a = 5; float b = a;, the integer 5 is automatically converted to 5.0 when assigned to b.

Explicit type conversion (casting): the programmer manually forces a conversion using the cast operator (type), often used to convert a larger type to a smaller one, which can lose data (narrowing). Example: int x = (int)3.99; forces the float value to be truncated to 3.

AspectImplicit ConversionExplicit Conversion
Who triggers itCompiler automaticallyProgrammer manually, using (type)
Typical directionLower type to higher type (widening)Often higher type to lower type (narrowing)
Data loss riskUsually safe, no lossPossible loss of precision or truncation
Exampleint → float during assignment(int)3.99 → 3
int a = 5;float b = a; float c = 3.99;int d = (int)c; 

Common Mistake

Assuming explicit casting from float to int rounds the value. It actually truncates (cuts off the decimal part) rather than rounding, so (int)3.99 becomes 3, not 4.

Test Yourself

  1. Why is converting a float to an int considered a "narrowing" conversion?
  2. What is the output of (int)7.8?

Answers: 1) Because it moves from a type that can represent fractional, larger-range values to a type that can only represent whole numbers, risking loss of the decimal portion.
2) 7 (truncation, not rounding).

Summary

  • Implicit conversion happens automatically, usually widening with no data loss.
  • Explicit conversion is manual, using (type), often narrowing and risking data loss.
  • Casting float to int truncates the decimal part rather than rounding.

One-Liner Revision

Implicit casting happens automatically and safely; explicit casting is manual and can lose data through truncation.

1.9.1 Arithmetic Operators

Core Definition

Arithmetic operators are symbols (+, -, *, /, %) that perform basic mathematical operations on numeric operands.


These are the everyday math symbols: add, subtract, multiply, divide, and find the remainder.

Detailed Explanation

All five operators work as expected on numbers, but two behaviours are frequently tested: integer division and the modulo operator.

OperatorMeaningExample (a=10, b=3)Result
+Additiona + b13
-Subtractiona - b7
*Multiplicationa * b30
/Divisiona / b3 (integer division, decimal dropped)
%Modulus (remainder)a % b1

When both operands of / are integers, the result is an integer with the fractional part discarded (not rounded), so 10 / 3 gives 3, not 3.33. The % operator only works with integer operands and gives the remainder after division.

Common Mistake

Expecting 10 / 3 to give 3.33. Since both operands are integers, C performs integer division and discards the decimal part, giving 3. To get a decimal result, at least one operand must be a float, e.g., 10.0 / 3.

One-Liner Revision

Arithmetic operators (+, -, *, /, %) perform basic math; integer division truncates, and % only works on integers.

Summary

  • Five operators: +, -, *, /, %.
  • Integer division truncates the decimal part instead of rounding.
  • % (modulus) requires integer operands and returns the remainder.

1.9.2 Relational Operators

Core Definition

Relational operators compare two values and produce an integer result, 1 for true or 0 for false, since C has no separate boolean type.


These operators just ask a yes/no comparison question, like "is a bigger than b?", and C answers with 1 (yes) or 0 (no).

Detailed Explanation

OperatorMeaningExample (a=5, b=8)Result
<Less thana < b1 (true)
>Greater thana > b0 (false)
<=Less than or equal toa <= b1 (true)
>=Greater than or equal toa >= b0 (false)
==Equal toa == b0 (false)
!=Not equal toa != b1 (true)

Common Mistake

Writing = (assignment) instead of == (comparison) inside a condition, e.g., if (a = 5) assigns 5 to a and the condition becomes true because 5 is non-zero, instead of comparing whether a equals 5.

One-Liner Revision

Relational operators compare two values and return 1 (true) or 0 (false), since C has no built-in boolean type.

Summary

  • Six relational operators:<, >, <=, >=, ==, !=.
  • Results are always 1 (true) or 0 (false), C's substitute for booleans.
  • Mixing up = and == is a classic and serious bug.

1.9.3 Logical Operators

Core Definition

Logical operators (&&, ||, !) combine or invert multiple conditions, treating any non-zero value as true and zero as false.


These let you ask combined questions, like "is it raining AND is it cold?", and C evaluates the whole combined condition to a single true/false answer.

Detailed Explanation

&& (Logical AND): true only if both conditions are true. || (Logical OR): true if at least one condition is true. ! (Logical NOT): reverses a condition's truth value.

C uses short-circuit evaluation for && and ||: in A && B, if A is false, B is never evaluated at all because the overall result is already guaranteed false. Similarly, in A || B, if A is true, B is skipped. This matters when B has side effects, like a function call or an unsafe memory access, since that code may not run at all.

OperatorMeaningExample (a=1, b=0)Result
&&AND (both true)a && b0 (false)
||OR (at least one true)a || b1 (true)
!NOT (inverts)!a0 (false, since a was true)

Let's Break It Down

Picture checking two locks before opening a door: "is the key lock open AND is the chain lock open?" The moment you find the key lock is still locked, you don't even bother checking the chain, you already know the door won't open. That's short-circuit evaluation: C stops checking further conditions the instant the answer is already decided.

Common Mistake

Relying on a side-effect inside the second operand of && or || always running, e.g., if (a != 0 && (b = compute())); if a == 0, compute() never executes due to short-circuiting, so b stays unassigned.

Test Yourself

  1. In x > 0 || y++ > 0, if x is 5, will y get incremented?

Answers: 1) No, because x > 0 is already true, so || short-circuits and the right-hand side y++ > 0 is never evaluated, meaning y is not incremented.

Summary

  • Three logical operators: &&, ||, !.
  • Any non-zero value is treated as true; zero is false.
  • Short-circuit evaluation can skip the second condition entirely, affecting any side effects inside it.

One-Liner Revision

Logical operators (&&, ||, !) combine conditions and use short-circuit evaluation, skipping the second condition when the result is already determined.

1.9.4 Bitwise Operators

Core Definition

Bitwise operators (&, |, ^, ~, <<, >>) operate directly on the individual binary bits of integer operands rather than on their decimal values.


Instead of treating numbers as whole values, bitwise operators look inside the number's binary form, bit by bit, and manipulate each 0 or 1 individually.

Detailed Explanation

& (Bitwise AND): each result bit is 1 only if both corresponding input bits are 1.

| (Bitwise OR): each result bit is 1 if at least one corresponding input bit is 1.

^ (Bitwise XOR): each result bit is 1 only if the corresponding input bits differ.

~ (Bitwise NOT/Complement): flips every bit of its single operand, 0 becomes 1 and 1 becomes 0.

<< (Left shift): shifts all bits left by a given number of positions, filling vacated positions on the right with 0; each left shift by 1 effectively multiplies the value by 2.

>> (Right shift): shifts all bits right by a given number of positions; for unsigned values this fills vacated positions on the left with 0, effectively dividing by 2 per shift.

Worked walkthrough: evaluate 5 & 3 using 4-bit representations.

5 = 01013 = 0011AND (bit by bit): 0101& 0011------ 0001 → result = 15 | 3: 0101| 0011------ 0111 → result = 75 << 1: 0101 shifted left by 1 → 1010 → result = 10 (i.e., 5 × 2)
OperatorNameExampleResult
&AND5 & 31
|OR5 | 37
^XOR5 ^ 36
~NOT~5-6 [verify, depends on bit width/representation]
<<Left shift5 << 110
>>Right shift5 >> 12

Common Mistake

Confusing the bitwise AND/OR (&, |) with the logical AND/OR (&&, ||). Bitwise operators act bit-by-bit on binary representations and can return values other than 0/1, while logical operators always return only 0 or 1 based on overall truth.

Test Yourself

  1. What is the result of 6 & 5, using binary working?
  2. Why does n << 1 effectively multiply n by 2?

Answers: 1) 6 = 0110, 5 = 0101, AND gives 0100 = 4.
2) Shifting all bits one position to the left doubles the place value each bit represents, which is mathematically equivalent to multiplying the whole number by 2.

Summary

  • Bitwise operators act on individual binary bits: &, |, ^, ~, <<, >>.
  • Left shift by n multiplies by 2^n; right shift by n divides by 2^n (for unsigned values).
  • Bitwise operators are distinct from, and easily confused with, logical operators.

One-Liner Revision

Bitwise operators (&, |, ^, ~, <<, >>) manipulate the individual binary bits of integers rather than their overall decimal value.

1.9.5 Assignment Operators

Core Definition

Assignment operators store a value into a variable, with the simple = operator and compound forms (+=, -=, *=, /=, %=) that combine an operation with assignment in one step.


Assignment puts a value into a variable's box; compound assignment operators let you update that value using its own current content in one shorter step.

Detailed Explanation

a = b simply copies the value of b into a. Compound operators are shorthand: a += b means a = a + b; similarly -=, *=, /=, and %= apply the respective arithmetic operation to a's current value and store the result back in a.

OperatorEquivalent ToExample (a=10)Result (a becomes)
=Direct assignmenta = 55
+=a = a + ba += 515
-=a = a - ba -= 55
*=a = a * ba *= 220
/=a = a / ba /= 25
%=a = a % ba %= 31

One-Liner Revision

Compound assignment operators (+=, -=, *=, /=, %=) combine an arithmetic operation with assignment in a single, shorter step.

Summary

  • = assigns a value directly; compound operators combine an arithmetic step with assignment.
  • a += b is shorthand for a = a + b, and similarly for -=, *=, /=, %=.

1.9.6 Increment and Decrement Operators

Core Definition

Increment (++) and decrement (--) operators increase or decrease a variable's value by exactly 1, and can be applied either before (prefix) or after (postfix) the variable.


These are shortcuts for adding or subtracting 1, but where you place the symbol, before or after the variable, changes exactly when the increase happens relative to the rest of the expression.

Detailed Explanation

Prefix (++a): the variable is incremented first, and the already-updated value is used in the surrounding expression.

Postfix (a++): the current (old) value of the variable is used in the surrounding expression first, and only afterward is the variable incremented.

Worked walkthrough:

int a = 5;int x = ++a; int b = 5;int y = b++; 

When used as standalone statements (e.g., a++; alone on its own line), prefix and postfix produce the identical end result; the difference only matters when the increment is part of a larger expression that also reads the value, such as an assignment or function argument.

Common Mistake

Assuming a++ and ++a always behave identically. They differ only in what value gets used at the moment of the surrounding expression; the variable's final stored value after the statement completes is the same either way, but the value used inside the expression differs.

Test Yourself

  1. If int p = 3; int q = p++ + 2;, what are the final values of p and q?

Answers: 1) q uses the old value of p (3) before incrementing, so q = 3 + 2 = 5; p is then incremented to 4.

Summary

  • ++ and -- adjust a variable's value by exactly 1.
  • Prefix updates the variable before using its value; postfix uses the old value first, then updates.
  • The difference only matters when the increment is embedded inside a larger expression.

One-Liner Revision

Prefix (++a) increments before using the value; postfix (a++) uses the old value first, then increments.

1.9.7 Conditional (Ternary) Operator

Core Definition

The conditional (ternary) operatorcondition ? expr1 : expr2 evaluates a condition and returns expr1 if it is true, or expr2 if it is false, all within a single expression.


It is a compact one-line replacement for a simple if-else: "if this is true, give me this value, otherwise give me that one."

Detailed Explanation

It is called "ternary" because it is the only operator in C that takes three operands: the condition, the true-result expression, and the false-result expression. It is most useful for short, single-value decisions rather than entire blocks of logic.

int a = 10, b = 20, max;max = (a > b) ? a : b; 

Common Mistake

Nesting too many ternary operators inside one expression to replace a multi-branch if-else chain. While syntactically valid, this quickly becomes hard to read and debug; a regular if-else or switch is clearer for more than one condition level.

Test Yourself

  1. Rewrite result = (x % 2 == 0) ? "Even" : "Odd"; as an if-else statement.

Answers: 1) if (x % 2 == 0) { result = "Even"; } else { result = "Odd"; }

Summary

  • Ternary operator: condition ? expr1 : expr2, the only three-operand operator in C.
  • Best for short, single-value decisions; avoid deep nesting for readability.

One-Liner Revision

The ternary operator (condition ? a : b) is a compact one-line substitute for a simple if-else.

1.9.8 Special Operators: sizeof, Comma, Address-of, and Dereference

Core Definition

Special operators, sizeof, the comma operator (,), address-of (&), and dereference (*), each perform a distinct utility role beyond ordinary arithmetic or logical operations.


These four operators each do one specific job: measure size, chain expressions, find an address, or read the value an address points to.

Detailed Explanation

sizeof: returns the number of bytes occupied in memory by a variable or data type, evaluated at compile time. Example: sizeof(int) typically returns 4 on most modern systems [verify per system].

Comma operator (,): evaluates multiple expressions left to right within a single statement, and the overall expression's value is the value of the rightmost expression. Commonly used inside for loop headers to update multiple variables. Example: for (i = 0, j = 10; i < j; i++, j--) updates both i and j each iteration.

Address-of (&): returns the memory address where a variable is stored. Example: &a gives the address of variable a, commonly used to initialize pointers.

Dereference (*): when applied to a pointer, accesses the value stored at the address the pointer holds. Example: if p holds the address of a, then *p gives the actual value of a.

OperatorPurposeExample
sizeofReturns size in bytes of a type/variablesizeof(int) → 4
, (comma)Evaluates multiple expressions, returns rightmosti++, j--
& (address-of)Gets the memory address of a variable&a
* (dereference)Gets the value at a pointer's address*p
int a = 10;int *p = &a; printf("%d", *p); 

Common Mistake

Confusing the dereference operator * used with pointers (*p, accessing a value at an address) with the multiplication operator * used between two numbers; the same symbol means different things depending on context.

Test Yourself

  1. If p = &a, what does *p give you?

Answers: 1) It gives the actual value stored in the variable a, by following the address stored in p.

Summary

  • sizeof measures memory size in bytes; comma chains expressions and returns the rightmost result.
  • & returns a variable's address; * dereferences a pointer to get the value at that address.
  • * means dereference with pointers but multiplication between numbers, depending on context.

One-Liner Revision

sizeof measures bytes, comma chains expressions, & gets an address, and * dereferences a pointer to its stored value.

1.9.9 Operator Precedence and Associativity

Core Definition

Operator precedence determines which operator is evaluated first when an expression contains multiple operators; associativity determines the evaluation order (left-to-right or right-to-left) among operators of the same precedence level.


Precedence is the rulebook for "which operator goes first," and associativity is the tiebreaker for "which direction to read in" when two operators are equally important.

Detailed Explanation

Without these rules, an expression like 2 + 3 * 4 would be ambiguous. C resolves this with a fixed precedence table; multiplication has higher precedence than addition, so it is evaluated first regardless of left-to-right reading order, giving 2 + 12 = 14, not 5 * 4 = 20.

Precedence (High→Low)OperatorsAssociativity
1 (Highest)() [] -> . (postfix)Left to right
2! ~ ++ -- (unary) sizeof (type) * (deref) & (address-of)Right to left
3* / %Left to right
4+ - (binary)Left to right
5<< >>Left to right
6< <= > >=Left to right
7== !=Left to right
8& (bitwise AND)Left to right
9^Left to right
10|Left to right
11&&Left to right
12||Left to right
13?: (ternary)Right to left
14 (Lowest, excluding comma)= += -= *= /= %=Right to left
15 (Lowest overall), (comma)Left to right

Worked walkthrough: evaluate 10 + 6 / 2 * 3 - 1.

Step 1 (highest precedence among these): / and * have equal, higher precedence than + and -, and are left-associative, so evaluate left to right: 6 / 2 = 3 3 * 3 = 9Step 2: Now the expression is: 10 + 9 - 1 + and - are equal precedence, left-associative: 10 + 9 = 19 19 - 1 = 18Final result: 18

Let's Break It Down

Think of precedence like a queue at a counter sorted by ticket priority: gold tickets (high precedence operators like * and /) get served before silver tickets (+ and -), no matter where they stand in line. Associativity is the rule for two people holding the same priority ticket: left-to-right associativity means whoever is standing more to the left gets served first among equals.

Common Mistake

Assuming assignment (=) happens left to right like most other operators. Assignment is actually right-associative, which is why a chained statement like a = b = 5; correctly assigns 5 to b first, then assigns the result to a, rather than failing or behaving unpredictably.

Test Yourself

  1. Evaluate 5 + 2 * 3 - 1 step by step using precedence rules.
  2. Why is the ternary operator right-associative, and what does that mean for nested ternaries?

Answers: 1) 2 * 3 = 6 first (higher precedence), then 5 + 6 = 11, then 11 - 1 = 10.
2) Right-associativity means that when ternary operators are nested without parentheses, the rightmost condition is grouped and evaluated first, which affects how a chain like a ? b : c ? d : e is interpreted.

Summary

  • Precedence decides which operator runs first; associativity decides direction among equal-precedence operators.
  • Multiplicative operators (*, /, %) outrank additive operators (+, -); both are left-associative.
  • Assignment and the ternary operator are right-associative, unlike most other operators.

One-Liner Revision

Precedence decides which operator runs first; associativity breaks ties between operators of equal precedence, left-to-right for most, right-to-left for assignment and ternary.

Whole Chapter Summary

  • 1.1 Evolution of Programming Languages: languages progressed through five generations, from binary machine code to logic-based 5GL systems, trading hardware closeness for human ease.
  • 1.2.1 History of C: created by Dennis Ritchie at Bell Labs to rewrite Unix, evolving from BCPL and B, later standardized as ANSI C.
  • 1.2.2 Characteristics of C: procedural, structured, middle-level, portable, efficient, case-sensitive, and capable of direct memory access.
  • 1.2.3 Applications of C: used in operating systems, embedded systems, compilers, databases, drivers, and game engines.
  • 1.3 Structure of a C Program: fixed sections, documentation, preprocessor directives, global declarations, main(), and user-defined functions, with execution always starting at main().
  • 1.4 Compilation and Execution Process: source code becomes a running program through preprocessing, compilation, assembly, linking, and loading/execution.
  • 1.5 C Tokens: the smallest meaningful units, keywords, identifiers, constants, string literals, and operators.
  • 1.5.1 Keywords: 32 reserved, fixed-meaning words that cannot be used as identifiers.
  • 1.5.2 Identifiers: programmer-defined names following strict naming rules (start with a letter/underscore, case-sensitive).
  • 1.5.3 Constants: fixed integer, floating-point, and character values that never change.
  • 1.5.4 String Literals: double-quoted text stored as a char array with a hidden null terminator.
  • 1.5.5 Operators (token): symbols acting on operands; full classification covered under 1.9.
  • 1.6.1 Declaration and Initialization: declaration reserves memory and type; initialization gives a starting value.
  • 1.6.2 Scope of Variables: local/block scope is limited to its block; global scope spans the whole file.
  • 1.6.3 Lifetime of Variables: controlled by storage class (auto, register, static, extern); static/extern persist for the whole program.
  • 1.7.1 Basic Data Types: int, char, float, double, void, each with defined size, range, and format specifier.
  • 1.7.2 Derived Data Types: arrays, pointers, and functions, built from basic types.
  • 1.7.3 User-Defined Data Types: struct, union, enum, and typedef for custom data modeling.
  • 1.8 Type Casting: implicit conversion is automatic and safe; explicit conversion is manual and can truncate data.
  • 1.9.1–1.9.9 Operators and Expressions: arithmetic, relational, logical (with short-circuiting), bitwise, assignment, increment/decrement (pre vs post), ternary, special operators (sizeof, comma, &, *), and the precedence/associativity rules that resolve evaluation order in any expression.

Key Formulas and Points Sheet

Formula / RuleMeaning
Signed n-bit integer range = −2^(n−1) to 2^(n−1) − 1Calculates the minimum and maximum value an n-bit signed integer can hold
n << k ≈ n × 2^kLeft-shifting by k positions multiplies the value by 2^k
n >> k ≈ n ÷ 2^k (unsigned)Right-shifting by k positions divides the value by 2^k
a += b ⇔ a = a + bCompound assignment is shorthand for operate-then-assign (same for -=, *=, /=, %=)
Integer division (a / b, both int)Result is truncated toward zero, decimal part discarded
Precedence order (high→low, key groups)() → unary (!, ~, ++, --, sizeof, *, &) → * / % → + - → relational → == != → & → ^ → | → && → || → ?: → = → ,

Last-Minute Revision Sheet

Evolution → 1GL binary, 2GL assembly, 3GL C/high-level, 4GL SQL (what not how), 5GL AI/logic.
C origin → Dennis Ritchie, Bell Labs, derived from B/BCPL, standardized as ANSI C.
C traits → procedural + structured + middle-level + portable + fast + case-sensitive.
Program structure → doc → preprocessor → global decl → main() → functions.
Build pipeline → preprocess → compile (→ assembly) → assemble (→ object) → link (→ exe) → load/run.
Tokens → keywords, identifiers, constants, string literals, operators.
Keywords → 32 reserved words, can't be variable names.
Identifiers → start letter/underscore, no spaces, case-sensitive.
Constants → integer / float / char, fixed value.
String literal → "text" + hidden \0 terminator.
Declaration vs initialization → reserve memory vs give starting value.
Scope → where the name is visible (local/global).
Lifetime → how long memory exists (auto/register = block; static/extern = whole program).
Basic types → int, char, float, double, void.
Derived types → array, pointer, function.
User-defined types → struct (separate memory), union (shared memory), enum (named constants), typedef (alias).
Type casting → implicit = automatic/safe; explicit = manual, can truncate.
Arithmetic → int/int division truncates; % needs integers.
Relational → returns 1/0, no real boolean.
Logical → &&, ||, ! ; short-circuit skips unneeded checks.
Bitwise → &, |, ^, ~, <<, >> operate on binary bits, not decimal value.
Increment/decrement → prefix updates first, postfix uses old value first.
Ternary → condition ? true_val : false_val, right-associative.
Special operators → sizeof (bytes), comma (chain, rightmost wins), & (address), * (dereference).
Precedence/associativity → precedence picks which operator first; associativity breaks ties (most left-to-right, assignment/ternary right-to-left).

Views: …
TUpapers.com logo tupapers.com
  • Privacy Policy

  • Contact Us

  • Terms

  • Pricing

  • SEEpapers.com

TUpapers on Facebook
TUpapers on Instagram
Contact TUpapers on WhatsApp Contact TUpapers on WhatsApp
TUpapers subreddit on Reddit

Courses

  • BBA

  • BCA

  • BIT

  • CSIT

  • BBS

  • BHM

  • BBM

  • BITM

  • BTTM

  • BA

  • BE

  • BSW

© 2026 tupapers.com. All rights reserved.