Overview
This unit introduces variables and expressions as the basic building blocks of programming. Students learn what variables are, how to choose meaningful names, and how data types determine what values can be stored and what operations are valid. The unit examines constants, literal values, and different kinds of expressions including arithmetic, relational, logical and assignment expressions. It emphasizes the rules of operator precedence and associativity so students can predict expression results without running a program. The unit also covers type conversion (implicit and explicit), the effect of operator types on outcomes (for example integer division vs floating-point division), and the role of expressions in controlling program flow. Understanding variables and expressions is essential because all computation in software involves storing values and calculating new values from them; mastering these foundations prepares students for writing correct, efficient algorithms and avoiding common errors like type mismatches, off-by-one mistakes, and unintended assignments. Practical examples and exercises train students to trace expressions, choose the right data types, and write clear code that computes the intended results.
Learning Objectives
- Define variables, constants and literals and distinguish between them.
- Explain common primitive data types and choose appropriate types for given data.
- Apply rules of naming and scope to declare and use variables correctly.
- Formulate and evaluate arithmetic, relational, logical and assignment expressions.
- Use operator precedence and associativity to determine the order of evaluation.
- Demonstrate type conversion, both implicit and explicit, and predict its effects.
- Identify and correct common errors involving variables and expressions.
- Construct compound expressions and simplify them step by step.
Topics in this chapter
19 topics · tap a topic title to jump straight to it.
What is a Variable?
Introduction
A variable is a named storage location in a running program used to hold a value that can change during execution. When you write code you often need to store information temporarily — like a user’s age, the result of a calculation, or a counter used in a loop. A variable provides a name for that storage so you can refer to the value later in the program. Thinking of a variable as a labelled box helps: the label is the name, the box contains the value, and you can open the box to change or read what is inside.
Attributes of a variable
Three attributes define a variable: its name, its type, and its current value. The name identifies the variable in the code. The type determines what kinds of values are allowed (for example whole numbers, fractional numbers, text, or true/false) and which operations make sense. The value is whatever is currently stored. Some languages also associate storage location details such as memory address and size, but at a conceptual level the triplet name-type-value is enough to understand behaviour.
Declaration and initialization
Before using many variables you declare them — tell the computer that you will use a variable with a certain name and type. Declaration may happen separately from initialization (giving an initial value). For instance, you might declare an integer variable score and later assign score = 0 once you know the initial value. Languages differ: some require explicit declarations with types, others infer type from initialization. When a variable is declared but not initialized its value may be undefined, so best practice is to initialize variables before use to avoid unpredictable results.
Why variables matter
Variables make programs flexible: instead of repeating literal values, you store a value in a variable and refer to it by name. If the value changes, you change it in one place (by assignment) and the rest of the code uses the updated value. Variables enable computation, allow programs to react to user input, and form the basis of data structures like arrays and objects. Understanding variables is the first step to understanding how programs store and manipulate data.
Good naming and scope
Choose informative names so that anyone reading the code understands the variable’s purpose. Keep variable scope — the region of code where the name is valid — as small as possible to reduce errors. Local variables inside functions or blocks reduce accidental interactions. Follow the naming rules of your language and avoid reserved words. Clear naming, correct typing, and careful initialization together produce code that is easier to read, test, and maintain.
- Declare an integer variable named count and initialize it to 0: int count = 0;
- Use variables length and breadth to compute area: area = length * breadth;
- A variable studentName holds text like "Asha" while score holds numeric value like 85;
- A boolean flag isLoggedIn can be true or false to represent login status.
- variable := name + (type) + value
- Declaration: type name;
- Initialization: name = value;
Constants and Literals
Basic idea
In programming, a literal is a fixed value written directly in the code — like 10, 3.14, 'A' or "hello". A constant is a named identifier bound to a value that should not change during execution. While literals are the raw values you type, constants give those values meaningful names. For example, instead of scattering the number 3.14159 throughout a program, you can give it the name PI and use PI everywhere you need the circular constant. This makes programs clearer and easier to update.
Kinds of literals
Literals appear in several forms: integer literals (e.g., 42), floating-point literals (e.g., 2.5), character literals (e.g., 'X'), string literals (e.g., "India"), and boolean literals (true, false). Some languages support additional literal kinds such as hexadecimal or binary numbers, and language-specific forms for large numbers or precise decimals. Each literal carries an inherent type recognised by the language, and that type affects how expressions using the literal are evaluated.
Defining constants
Constants are typically declared with a keyword or modifier that prevents reassignment after initialization. For example, many languages use const or final. Declaring a named constant communicates programmer intent: the value is important and fixed. Constants also reduce errors: you cannot accidentally change a value used across the program. When the value needs to change (e.g., different configuration for testing vs production), you change the constant in one place rather than hunting through code.
Advantages of using constants
Named constants improve readability, maintainability and reduce magic numbers (unnamed numeric literals) in your code. They centralize configuration, making it easier to manage changes and avoid inconsistent values. Compilers can sometimes optimize code by inlining constants or performing constant folding, which may improve performance. Additionally, constants can document units and meaning (for instance TAX_RATE_PERCENT = 5 clarifies that 5 means percent).
Practical tips
Use clear names for constants — many teams adopt UPPERCASE_WITH_UNDERSCORES for visibility. Group related constants in a configuration section or module to make them easy to find. For sensitive secrets do not store them as plain constants in source code; instead use secure configuration or environment variables. When writing code, prefer constants for values that are conceptually fixed so your intent is explicit and future maintenance is simpler.
- Use PI as a constant to compute the circumference: circumference = 2 * PI * radius.
- Declare MAX_STUDENTS = 50 and use it to check enrollment limits.
- Boolean literal example: isActive = true.
- String literal example: greeting = "Good morning".
- Literal: a fixed value written directly in code, e.g., 42, 3.14, "text".
- Constant declaration: const NAME = value;
Data Types and Primitive Types
What are data types?
Data types tell a programming language how to interpret the bits stored in memory and which operations are valid on them. They are essential because operations that make sense for one kind of data may be meaningless for another; for example adding two numbers is different from concatenating two strings. Primitive types are the basic built-in types provided by a language; they form the foundation for building more complex types like arrays or objects.
Common primitive types
Most languages provide a set of standard primitive types: integers for whole numbers, floating-point types for numbers with fractions, characters for single textual symbols, booleans for true/false values, and strings for text sequences (strings are sometimes implemented as a primitive or a core library type). Integers may come in sizes like byte, short, int and long with different ranges. Floating types include float and double with differing precision. Knowing the available types helps choose the correct one for a task.
Range and precision
Each numeric type has a finite range and precision. Integer types hold exact values in a limited range: adding numbers beyond that range causes overflow. Floating-point types represent real values approximately and can express very large or small numbers but with rounding errors. For tasks requiring exact decimal arithmetic (such as currency), avoid plain floating point and use fixed-point or decimal libraries if available; otherwise handle rounding explicitly.
Character and string handling
Characters store single symbols and are often represented internally as numeric codes (like ASCII or Unicode). Strings are ordered sequences of characters used for names, messages and textual data. Operations on strings include concatenation, substring extraction, search and comparison. Understanding encoding (UTF-8, UTF-16) is important for internationalisation, because characters may require more than one byte.
Booleans
Boolean type holds true or false and is crucial for decision making and control flow. Relational and logical operators produce boolean results which then guide if statements and loop conditions. Using boolean variables with descriptive names (for example isPrime, isLoggedIn) improves code readability and reduces errors compared to embedding complex expressions directly.
Choosing types
Choose the smallest type that safely fits the data to conserve memory and reduce overflow risk. Prefer exact types when precision matters. In mixed-type expressions, languages usually promote values to a common type; understand promotion rules to avoid surprises. Proper choice of data types helps produce efficient, correct and maintainable code.
- Use int for counting students and float for measuring height in metres.
- Store a grade letter in a char variable: grade = 'A'.
- Use boolean isPassed = score >= passMark to represent pass/fail.
- Represent a name with a string: name = "Ramesh".
- Type declaration: type name;
- Example types: int, float, double, char, boolean, string
Variable Naming Rules and Conventions
Syntax rules
Variable names must obey the language’s syntax. Common rules include: the name must begin with a letter or underscore, it may contain letters, digits and underscores, it cannot contain spaces or special characters, and it must not be a reserved keyword (for example if, class, int). Many languages are case-sensitive, so student and Student are different identifiers. Understanding the exact legal characters and reserved words for your language prevents simple compile-time errors.
Naming conventions
Conventions are style guidelines that help programmers read and maintain code. Typical conventions include camelCase (studentCount) for variable and function names, PascalCase (StudentDetails) for class names, and UPPERCASE_WITH_UNDERSCORES (MAX_SCORE) for constants. Consistency within a project matters more than which specific convention you choose. Good conventions make code self-documenting and reduce the need for comments that restate the obvious.
Descriptive names
Prefer meaningful names that explain the role of a variable. For example, totalMarks is clearer than t or x. Good names reduce cognitive load when reading code and make debugging easier. When a variable serves a specific purpose, include that purpose in the name: averageAge, remainingAttempts, bufferSize. Avoid abbreviations that are unclear to new readers unless the abbreviation is standard and widely understood.
Scope-aware naming
Keep variable names short when their scope is small and their purpose obvious (for example loop counters i, j inside small loops). For global or widely used variables, choose longer descriptive names to avoid conflicts and make the role clear. Avoid reusing the same name for different purposes in overlapping scopes which can cause confusion due to shadowing. Use prefixes or suffixes where helpful to indicate units or types (e.g., priceInPaise or countStr), but do not encode type in names inconsistently.
Avoiding problems
Do not use names that mislead — for instance using nameList for a single name. Avoid names that look similar (l and 1, O and 0). Keep identifiers readable by using underscores or camelCase to separate words. Follow team or language-specific style guides when available, and review names in code reviews to improve clarity. Thoughtful naming reduces bugs, simplifies maintenance, and produces code that others can understand quickly.
- Good name: studentAge; Bad name: a.
- Constant naming: MAX_SCORE = 100.
- Loop variable: for(int i = 0; i < n; i++) is acceptable for short scope.
- Avoid reserved words like int, class as variable names.
- Variable name rules: start with letter/underscore, followed by letters/digits/underscores, not a reserved word.
Assignment and Read/Write Operations
What is assignment?
Assignment is the operation that stores a value into a variable. The common assignment operator is = which takes the evaluated value of the right-hand side expression and places it into the left-hand side variable. Assignment changes program state; after assignment, the variable holds the new value until another assignment changes it. It is important to remember that assignment is not equality; it is an action that updates a name with a value.
Evaluation order
When an assignment occurs, the right-hand side expression is evaluated first and then the result is stored. If the right-hand side references the variable being assigned, the old value is used during evaluation (unless the language defines otherwise). In chained assignments like a = b = 5, evaluation proceeds right to left so b is set to 5, then a is set to b. Understanding the evaluation order avoids subtle bugs.
Compound assignment
Languages often provide compound assignment operators that combine an arithmetic or bitwise operation with assignment. Examples include +=, -=, *=, and /=. The statement x += 5 is shorthand for x = x + 5. Compound assignments can be more concise and sometimes more efficient, and they make intent clearer when updating a variable relative to its previous value.
Input (read) operations
Reading input assigns external data (from a keyboard, file, or network) into variables. Input operations must validate the data before use to avoid type errors or invalid states. For example, reading an integer from user input requires checking that the entered string contains digits. Always handle input errors gracefully to avoid crashes or incorrect data stored in variables.
Output (write) operations
Writing output prints variable values or messages for the user or other systems. Output is helpful for showing results and for debugging by printing intermediate values. However, excessive printing harms performance and pollutes program logs, so use logging levels or disable debug prints in production. Keep input and output separate from core logic when possible so that functions remain reusable and easy to test.
Immutability and special assignment forms
Constants and immutable variables can be assigned only once; attempting to reassign them causes an error. Some languages support read-only properties, destructuring assignments and multiple-assignment forms that initialize several variables at once. Understand the specific assignment semantics of your language platform to avoid accidental overwrites or unexpected behaviours.
- Simple assignment: score = 90 assigns 90 to score.
- Chained assignment: a = b = 10 assigns 10 to both b and a.
- Compound assignment: total += tax is same as total = total + tax.
- Reading input: read(age); then age holds the user-provided value.
- Assignment: variable = expression;
- Compound: variable op= expression; (e.g., x += 2)
Arithmetic Expressions and Operators
Core operators
Arithmetic expressions combine numeric values using operators such as addition (+), subtraction (-), multiplication (*), division (/) and modulus (%). These operators follow mathematical rules but are also subject to the programming language’s type system and evaluation rules. Expressions may be simple (a + b) or nested and complex ((a + b) * (c - d) / e). Being able to predict the result of an arithmetic expression is essential for writing correct programs.
Precedence and grouping
Operators have precedence levels that determine the order of evaluation when parentheses are not present. Typically multiplication, division and modulus are evaluated before addition and subtraction. Parentheses override precedence and make grouping explicit. For example 3 + 4 * 2 equals 11 because multiplication happens first, while (3 + 4) * 2 equals 14. Always use parentheses when readability or correctness could be affected.
Integer vs floating-point arithmetic
Integer arithmetic works with whole numbers; division between integers usually discards the fractional part. Floating-point arithmetic handles fractions but may introduce rounding errors due to finite precision. When combining integers and floating-point numbers, implicit type promotion usually converts integers to floating-point so the result keeps fractions. To avoid accidental truncation, convert operands appropriately or use floating-point literals (for example 3.0 instead of 3).
Modulus operator
The modulus operator (%) returns the remainder of an integer division. It is frequently used to test divisibility (n % d == 0), to cycle through a range (index = (index + 1) % n), and to extract digits (lastDigit = n % 10). Remember that behaviour with negative numbers can be language-dependent, so check your language’s definition when negatives may appear.
Order of evaluation and side effects
While arithmetic operators usually have straightforward evaluation, expressions that include function calls or increment/decrement operators can produce side effects and change evaluation results. For example, using i++ within an expression both returns a value and increments i. Prefer breaking complex expressions into clear steps to avoid subtle bugs related to order of evaluation and side effects.
Practical tips
Use parentheses for clarity, choose appropriate numeric types for precision and range, and test edge cases such as zero divisors and extremes that may cause overflow. When implementing formulas from mathematics, carefully replicate the mathematical grouping to obtain expected results in code.
- Compute area: area = length * breadth.
- Evaluate 3 + 4 * 2 = 11 because multiplication first.
- Integer division: 7 / 2 = 3 (if using integers); 7.0 / 2 = 3.5 with floating point.
- Modulus example: 17 % 5 = 2.
- Precedence: parentheses () > * / % > + -
- Associativity: left to right for + - * / %
- Modulus: a % b gives remainder of a divided by b
Relational Operators and Boolean Expressions
Relational operators
Relational operators compare two values and return a boolean value: true or false. The common relational operators are equal (==), not equal (!=), greater than (>), less than (<), greater than or equal (>=), and less than or equal (<=). These operators are typically used to form conditions inside if statements, loops, and other control structures. Understanding relational operators is necessary to express conditions that cause different parts of a program to execute.
Boolean expressions
A boolean expression is any expression that evaluates to either true or false. A relational operator produces a boolean expression, and boolean expressions can be combined using logical operators to form more complex conditions. For example, (age >= 18) produces true when age is at least 18. You can store boolean results in variables, pass them to functions, or directly use them in control statements.
Logical operators
Logical operators allow combining boolean expressions: AND (&&) returns true only if both operands are true; OR (||) returns true if at least one operand is true; NOT (!) inverts a boolean value. Combining relational expressions with logical operators enables richer conditions. For example (score >= passMark) && (attendance >= minAttendance) checks two requirements at once.
Short-circuit evaluation
Many languages use short-circuit evaluation for AND and OR: in an AND expression if the first operand is false, the second is not evaluated because the whole expression cannot be true; similarly, in an OR expression if the first operand is true, the second is skipped. Short-circuiting is useful to avoid errors — for example, check for null before dereferencing: if (ptr != null && ptr.value == 10) ensures the second part runs only if ptr is valid.
Comparison of non-numeric types
Relational operators may behave differently for strings or other types: equality usually compares content, while order comparisons may use lexicographic order. Be careful when comparing floating-point numbers for equality because precision issues may cause unexpected false results; prefer checking if the absolute difference is within a small epsilon for approximate equality.
Readability and testing
Keep boolean expressions simple and readable. Break complex conditions into named boolean variables or helper functions with descriptive names. Test boolean expressions with boundary values and combinations to ensure all branches behave as expected. Clear and well-tested boolean logic prevents many common program errors.
- Check eligibility: isEligible = (age >= 18) && (age <= 60).
- Compare scores: if (score1 != score2) then print 'Different'.
- Range check with OR: if (x < 0 || x > 100) then print 'Out of range'.
- Short-circuit example: if (ptr != null && ptr.value == 10) prevents null access.
- Relational: a == b, a != b, a > b, a < b, a >= b, a <= b
- Logical: A && B (AND), A || B (OR), !A (NOT)
Operator Precedence and Associativity
Why precedence matters
Operator precedence and associativity determine the order in which parts of an expression are evaluated when multiple operators are present. Without these rules, expressions like 3 + 4 * 5 would be ambiguous. Precedence gives some operators priority over others; associativity resolves the order among operators of equal precedence. Knowing these rules helps you predict expression results without running code.
Common precedence order
While exact details vary by language, common precedence rules place parentheses first, then unary operators (such as unary minus), then multiplicative operators (*, /, %), then additive operators (+, -), then relational, logical, and finally assignment operators. Parentheses override all precedence rules and should be used to express grouping explicitly when in doubt. This avoids misinterpretation and documents the intended order of operations for human readers.
Associativity explained
Associativity decides how to group operators with the same precedence. Most binary arithmetic operators are left-associative, meaning they group from left to right: a - b - c is interpreted as (a - b) - c. Some operators, such as assignment, are right-associative in many languages: a = b = c is evaluated as a = (b = c), which assigns c to b then assigns b to a. Knowing associativity prevents mistakes especially when chaining operators without parentheses.
Unary operators and special cases
Unary operators like +, -, and logical NOT apply to a single operand and usually have higher precedence than binary operators. Increment and decrement operators (prefix ++x vs postfix x++) have particular evaluation rules and side effects that can interact with associativity and precedence in non-intuitive ways. Avoid complex expressions that rely on sequence points or undefined evaluation order.
Practical rules and clarity
Use parentheses to make the intended evaluation order explicit rather than relying on memory of a complex precedence table. This improves readability and reduces the chance of bugs. When writing expressions in exams or code, show intermediate grouping with parentheses if the expression will be evaluated by others or graded; that demonstrates clear understanding and prevents misinterpretation.
How to evaluate
To evaluate an expression step-by-step: 1) resolve parenthesised sub-expressions, 2) apply operators by precedence level from highest to lowest, 3) within the same precedence apply associativity rules, and 4) perform any necessary type conversions. Practise with examples until the rules become intuitive, but always prefer clarity in real code.
- Evaluate 3 + 4 * 5 = 3 + (4 * 5) = 23.
- Evaluate 10 - 2 - 3 = (10 - 2) - 3 = 5 with left associativity.
- Assignment associativity: a = b = 2 sets b = 2 then a = b.
- Use parentheses to change order: (3 + 4) * 5 = 35.
- Order example: () > unary > * / % > + - > relational > logical > assignment
- Associativity: left-to-right for most arithmetic; right-to-left for assignment
Type Conversion and Casting
Why conversions occur
Type conversion changes data from one type to another to make operations between differing types possible. When an expression contains operands of different types (for example an integer and a floating-point number), the language must decide how to combine them. Conversions can be implicit — performed by the language automatically according to promotion rules — or explicit — directed by the programmer using casting syntax. Understanding both kinds avoids surprises and unintended data loss.
Implicit promotion rules
Implicit conversions follow language-specific rules that promote a smaller or less precise type to a larger or more precise type so that the operation preserves information where possible. For instance, adding an int to a float generally promotes the int to a float, and the result is a float. Promotions prevent loss of fractional parts but can also introduce subtle behaviour when mixed with integer operations or when very large values are involved.
Explicit casting
Casting is when the programmer requests a specific conversion. The syntax often looks like (type) expression. Casting can be used to force a floating point result into an integer or to reinterpret a value in a different type. Because casting can lose information (for example truncating 3.9 to 3), it must be used carefully and with awareness of its consequences. Explicit casts make the programmer’s intent clear and are often necessary when automatic conversion is not allowed.
Narrowing vs widening
A widening conversion moves to a type that can hold all values of the original (for example int to long or int to float) and is usually safe. A narrowing conversion moves to a smaller or less precise type (for example double to float, long to int) and risks overflow or rounding errors. Always check ranges and consider using checks or alternative strategies for safe conversion when narrowing.
Examples and pitfalls
Integer division is a common pitfall: 7 / 2 using integers yields 3, while casting or using a float (7.0 / 2) yields 3.5. Floating-point rounding means equality comparisons can fail unexpectedly; prefer checking if values are within a small range of each other. Converting user input strings to numbers requires validation to avoid exceptions. Finally, be mindful of platform-specific details: some languages have signed vs unsigned types, which change conversion and comparison behaviour.
Best practices
Use explicit casting when you intend to change precision or representation and document why. Minimise unnecessary conversions by choosing appropriate types up front. Test conversion boundaries and include checks to prevent overflow or loss of precision. When working with money or where exact decimals are needed prefer decimal types or integer representation of minor units to avoid floating-point errors.
- Implicit: int 5 + float 2.0 -> float 7.0.
- Explicit cast: int x = (int) 3.9 results in x = 3.
- Narrowing danger: long big = 1234567890123L; int small = (int) big may lose data.
- Use cast to force floating division: double r = (double) 7 / 2 = 3.5.
- Casting syntax example: (type) expression
- Promotion: int -> float when combined with float
Expressions as Statements and Side Effects
Expression vs statement
An expression computes a value. A statement performs an action. Many programming languages allow expressions to be used where statements are expected; in such cases the expression's value may be ignored while any side effects take place. Side effects are operations that change program state or interact with the outside world, such as assigning to a variable, writing to a file, or printing to the screen. Understanding when an expression has side effects is important for predicting program behaviour.
Assignments and side effects
Assignment expressions are among the most common side-effecting expressions because they update the contents of a variable. When assignment appears on a line by itself it acts as a statement: x = y + 2 computes y + 2 then stores the result in x. The side effect — changing x — is the main outcome. Many languages return a value from assignment expressions which allows constructs like a = b = 5; but this also increases the chance of confusion, so use such constructs sparingly for clarity.
Function calls and I/O
Function calls often produce side effects: a function may modify global state, change object fields, or perform input/output. For example, print() writes to the console, and writeToFile() changes a file. When these calls are part of larger expressions, the order of evaluation matters because side effects can alter values used elsewhere in the expression. Modern languages and coding standards encourage separating pure computations (without side effects) from actions to improve testability and reasoning.
Increment and decrement operators
Pre- and post-increment operators (++x vs x++) are classic examples of expressions with side effects that also return values. Post-increment returns the old value then increments; pre-increment increments first then returns the new value. Using these inside larger expressions can be confusing and lead to subtle bugs, particularly when combined with other side effects or when language evaluation order is unspecified. Prefer explicit assignment steps for clarity when side effects matter.
Order and predictability
The order in which expressions with side effects execute affects final program state. Some languages guarantee left-to-right evaluation, others do not, and some use short-circuit rules for logical operators. Rely on clear, simple sequences of statements to avoid relying on unspecified evaluation order. Keep side effects local and limited to reduce surprising interactions and to make the code easier to test and maintain.
Best practices
Avoid writing expressions that mix multiple side effects. Separate computation from state changes: first compute a value in a pure expression, then assign or perform I/O in a separate statement. This reduces bugs and makes it easier to reason about the program when reading or debugging. When side effects are necessary, document them and write unit tests that verify the resulting state changes.
- Assignment as statement: total = total + price; changes total.
- Function call with side effect: log("Error") writes to a log file.
- Increment in expression: y = x++ + 2 may yield different results than y = ++x + 2.
- Avoid: array[index++] = index; which mixes side effects and uses result unpredictably.
- Post-increment: x++ returns old value then increments.
- Pre-increment: ++x increments then returns new value.
String Expressions and Concatenation
Strings as data
Strings store sequences of characters and are used for names, messages, file paths and any textual data. In expressions strings can be compared, sliced, searched, and combined. One of the most common operations is concatenation: joining two or more strings end-to-end to form a new string. Languages provide different ways to concatenate: many use + for convenience, others provide specific library functions or methods for joining strings efficiently.
Concatenation rules and mixing types
When languages allow + to work for both numeric addition and string concatenation, the combination of numbers and strings in the same expression can be tricky. Evaluation is usually left-to-right, so "Total = " + 10 + 5 can produce "Total = 105" because 10 is converted to "10" and then concatenated with "5". To get numeric addition first, use parentheses: "Total = " + (10 + 5). Understanding how the language converts numbers to strings (or vice versa) prevents unexpected results.
Immutability and performance
Many languages treat strings as immutable: concatenation creates a new string rather than modifying an existing one. Repeated concatenation in loops can therefore be inefficient because it creates many temporary objects. Most languages provide alternatives like StringBuilder or join functions to accumulate strings efficiently. When performance matters, prefer buffered or incremental building rather than naive repeated concatenation.
Common string operations
Beyond concatenation, strings support operations like length, substring extraction, indexing, search (find, indexOf), replace, and case conversion. Comparison of strings for equality usually checks content; ordering comparisons use lexicographic rules often based on character codes. Remember that locale and encoding can affect comparisons and ordering, and different characters may occupy variable bytes depending on encoding.
Formatting and localisation
For user-facing messages prefer formatted output functions or templates that insert values into placeholders (for example "Name: %s, Score: %d"). This approach separates data from presentation and makes localisation (translating to other languages) easier. Use libraries for formatting currencies, dates and numbers to respect locale conventions.
Practical advice
Use meaningful names for string variables, validate inputs to avoid injection vulnerabilities when strings are used in queries or system commands, and document expected encodings. When combining strings and numbers, be explicit about conversions and prefer parentheses to make intent clear. For repeated building of large strings use efficient builders provided by the language.
- Concatenate first and last name: fullName = firstName + " " + lastName.
- Mixing numbers and strings: "Total = " + 10 + 5 may produce "Total = 105" if concatenation left-to-right, so use parentheses: "Total = " + (10 + 5).
- Get substring: name.substring(0, 3) to take first three letters.
- Use string builder pattern to append repeatedly in a loop for performance.
- Concatenation: s3 = s1 + s2
- Length: n = s.length()
Naming Scope and Lifetime of Variables
Defining scope
Scope specifies the region of a program where a variable name is visible and can be used. Typical scopes include local (inside a function or block), global (visible across the module or entire program), and class/object scope (fields accessible to methods). When a variable is declared in a local scope it hides or shadows any variable of the same name in an outer scope for the duration of the inner scope. Proper scoping prevents accidental access and name conflicts.
Lifetime and storage
Lifetime refers to how long a variable occupies memory during execution. Local variables often have lifetimes tied to function calls or block execution — created when execution enters the scope and destroyed when it leaves. Global variables typically exist for the entire program execution. Some languages also support static variables that persist across function calls but are limited in visibility. Understanding lifetime ensures you do not access variables after they cease to exist.
Stack vs heap
Many languages allocate local variables on the call stack where they are efficiently created and destroyed with function calls. Dynamic data such as objects or arrays may be allocated on the heap and persist beyond the function that created them, controlled by references and garbage collection in managed languages. Knowing whether data lives on the stack or heap helps reason about performance and when resources are freed.
Shadowing and name clashes
Shadowing occurs when an inner scope declares a variable with the same name as an outer scope, temporarily hiding the outer variable. While allowed, shadowing can lead to confusion and bugs if a programmer mistakes which variable is being used. To avoid errors, prefer unique names across nested scopes when values are related or comment clearly when shadowing is intentional.
Best practices
Keep variable scope as small as possible — declare variables close to where they are used. Avoid global state unless necessary; prefer passing values to functions and returning results to maintain modular code. Use meaningful names and consistent conventions to reduce accidental reuse. In resource-constrained contexts release resources promptly or use language features that manage lifetime automatically (for instance RAII in some languages or try-with-resources patterns).
Debugging scope issues
Scope problems often show up as unexpected values or errors when a variable is referenced outside its intended region. Use clear naming, code reviews, and static analysis tools to detect shadowing or unused variables. Understanding scoping rules helps in reading unfamiliar code and in designing APIs that minimize unintended interactions between parts of a program.
- Local variable example: inside function calculate(), temp is available only within that function.
- Global variable example: a configuration constant used across multiple functions.
- Shadowing: a local variable named count inside a loop hides an outer count.
- Lifetime example: variable declared inside loop is created and destroyed each iteration (language-dependent).
Constants vs Variables in Memory
Storage and mutability
Both constants and variables occupy memory, but they are treated differently by compilers and runtimes. A variable’s memory holds data that can change during execution; it is allocated and written to as the program runs. A constant represents data that must not change; some languages allocate a dedicated read-only memory area for constants, while others may embed constant values directly into instructions during compilation. Because constants do not change, compilers can perform optimisations like inlining or constant folding, replacing repeated expressions with a single constant value.
Memory segments
Program memory is often divided into segments: code (instructions), read-only data (constants), writable data (global variables), heap (dynamically allocated objects), and stack (local variables). Constants may live in the read-only segment making accidental modification impossible; variables typically reside in writable areas (stack or heap). Understanding where different kinds of data live helps diagnose memory-related issues and contributes to writing secure code that avoids accidental modifications.
Immutability advantages
Immutability brings safety: if data cannot change, functions that read it can rely on a stable value. Constants help prevent accidental reassignment and can make reasoning about code easier. They also aid thread-safety since immutable data can be shared without locks. For configuration values and fixed parameters declare constants so their intent is clear and accidental modification is prevented by the language or tooling.
Compiler and runtime behaviour
Some compilers replace uses of a constant with its literal value during compilation; this is called inlining. This can reduce memory usage and improve speed but means changing the constant value requires recompiling clients that used it. For large constant data (for example lookup tables), placing them in separate resources or files may be preferable. Variables, conversely, cannot be folded away because their values may change at runtime.
Practical considerations
Use constants for values that are truly fixed: mathematical constants, fixed configuration defaults, and protocol values. Use variables where values change due to user input or computation. Keep large data out of global constants when memory footprint matters, and prefer external configuration for environment-specific values. Use the language’s const or final keywords to document intent and let the compiler or runtime enforce immutability where possible.
Security and performance
For sensitive secrets avoid hardcoding them as constants in source code because inlined constants can be discovered easily; instead use secure storage and environment variables. For performance-critical constants small immutable values are beneficial because they enable optimisations; for large constants balance memory use and performance trade-offs carefully.
- Compile-time constant PI may be inlined by the compiler into expressions.
- Mutable variable buffer[] can be changed to store input data.
- Using const for configuration prevents accidental reassignment in code.
- Large constant data kept in a separate file to avoid bloating program memory.
Common Errors with Variables and Expressions
Type mismatch errors
A frequent error is assigning a value of the wrong type to a variable or using an operator on incompatible types. For example, attempting arithmetic on a string without conversion or assigning text to a numeric variable triggers errors or unexpected behaviour. Strongly typed languages will report such errors at compile time; weakly typed languages may produce runtime errors or incorrect results. Always check types when declaring variables and when passing values between functions.
Uninitialized variables
Using a variable before it has a defined value leads to undefined behaviour, unpredictable outputs, or runtime exceptions. Some languages initialise variables to default values, but relying on defaults is risky. Always initialize variables explicitly before use; this makes intent clear and prevents subtle bugs that can be hard to trace.
Off-by-one errors
Off-by-one mistakes are common in loops and indexing. They occur when a loop runs one time too many or too few, typically from incorrect boundary conditions such as using <= instead of <, or starting an index at 1 instead of 0. Arrays and collections usually have bounds; accessing outside those bounds causes errors. Test loop boundaries with small inputs and check indices carefully to avoid such mistakes.
Integer overflow and precision loss
Storing results outside a type’s representable range causes overflow, yielding incorrect values. Similarly, converting floating-point numbers to integers truncates fractional parts. Anticipate ranges and choose appropriate types or check values before conversion. Use larger integer types or arbitrary-precision arithmetic for very large numbers, and use decimal types or scaling for precise financial calculations.
Operator confusion
Confusing assignment (=) with equality (==), or mixing bitwise and logical operators, leads to logical errors. Also confusing pre- and post-increment can change results unexpectedly. Use parentheses and clear separate statements to avoid ambiguity. Static analysis tools and compiler warnings often catch these mistakes; heed them to prevent bugs.
Other pitfalls
Relying on unspecified evaluation order can produce inconsistent results across compilers or platforms. Mixing side effects in expressions makes code hard to understand and maintain. Not validating user input can cause exceptions or security issues. Debugging is easier when code is simple, well-documented, and checked with unit tests that cover edge cases.
- Uninitialized: int x; print(x); may print garbage or default value depending on language.
- Off-by-one: for (i = 0; i <= n; i++) uses n+1 iterations if n is intended count.
- Overflow: storing 10^12 into a 32-bit int may wrap-around.
- Assignment in condition: if (x = 0) { ... } assigns 0 rather than comparing x == 0.
Constants for Configuration and Readability
Why configuration constants?
Configuration constants hold values that affect program behaviour but are not expected to change while the program runs — for example default timeout durations, maximum number of retries, or file path defaults. Placing such values as named constants, ideally in a single configuration area or module, makes the program easier to understand and maintain. If the configuration needs to change for testing or deployment, you change the constants in one place rather than searching through the code for magic numbers.
Readability and documentation
Named constants act as documentation. A value MAX_USERS = 100 is clearer than seeing the number 100 scattered in code. By choosing descriptive constant names you convey units and purpose: TIMEOUT_SECONDS is better than TIMEOUT or 30 alone because it clarifies that the value is in seconds. Use consistent naming conventions and group related constants together for discoverability.
Separation of concerns
Keep configuration separate from algorithmic code: load constants from a configuration module, file, or environment variables. This separation allows the same codebase to run in different environments (development, testing, production) with different settings. For constants that must be modified without recompiling the application, prefer external configuration sources rather than hard-coded constants.
Immutability and safety
Declare configuration values as immutable constants when they should not change during execution. This prevents accidental modification and helps reasoning about code. For sensitive data such as passwords or secret keys, do not hard-code them as constants in source files; instead use secure storage or environment variables and appropriate access controls to protect them.
Practical organisation
Place constants at the top of a file or in dedicated configuration modules. Document units and acceptable ranges in comments. When constants are used across modules, expose them through well-defined interfaces rather than globals to control access and modification. For large sets of related constants prefer enumerations (enums) or configuration objects to group logically related items.
Testing and deployment
For tests, override configuration constants with test-specific values to exercise boundary conditions and error handling. For deployment, provide environment-specific configuration and avoid recompiling code just to change settings. Thoughtful use of constants improves readability, reduces bugs, and simplifies configuration management for projects of any size.
- Define MAX_CONNECTIONS = 100 and use it to set limits across the application.
- Use DEFAULT_CURRENCY = "INR" to display prices consistently.
- Keep API endpoint URLs in configuration constants to switch environments easily.
- Document units: TAX_RATE_PERCENT = 5 indicates percentage form.
Expressions in Control Flow (if, loops)
Conditions for decisions
Boolean expressions are used to control program flow with statements like if, else if, else, while and for. In an if-statement the boolean condition decides whether the then-block runs; otherwise the else-block runs if present. Writing clear conditions is essential for correct branching behaviour. For example if (score >= passMark) triggers one block of code when the student passes and another when they do not.
Loop control
Loops depend on boolean expressions to decide continuation. A while loop evaluates its condition before every iteration and repeats the loop body while the condition is true. A for loop typically uses initialization, a boolean condition, and an update expression to control iteration. Setting the correct loop condition prevents infinite loops and ensures each element or iteration is processed once. Edge cases often cause errors, so boundaries (start and end values) must be carefully chosen.
Combining conditions
Complex control flow often requires combining relational expressions with logical operators to form compound conditions. For example while (i < n && !isClosed) continues iterating only while both conditions hold. Use parentheses to group logical operations and ensure correct evaluation. For readability, break complex conditions into named boolean variables like canContinue to explain the intent of the check.
Short-circuiting in control flow
Short-circuit evaluation helps write safe control statements. For instance, in if (ptr != null && ptr.value == target) the second part is evaluated only if the first is true, preventing null dereference. Use this property to guard risky operations, such as array access or function calls that assume preconditions. But be mindful that relying on side effects in short-circuited expressions can be confusing; keep side effects minimal in conditions.
Loop invariants and correctness
A loop invariant is a condition that remains true before and after each loop iteration; reasoning with invariants helps prove loop correctness. Though formal proofs are not always required, thinking about invariants (for example that an index remains within bounds) helps design correct loops. Test loops with boundary inputs and special cases to ensure termination and correctness.
Readability and structure
Prefer small, clearly named helper functions when conditions become complex: isEligibleForDiscount(customer) expresses intent more clearly than a long expression inline. Use early returns to handle error conditions and reduce nesting. Clear structure and simple expressions in control flow make code easier to test and maintain.
- if (score >= passMark) print('Pass') else print('Fail').
- for (i = 0; i < n; i++) processes n elements using condition i < n.
- Use boolean named: isAdult = (age >= 18); if (isAdult) allowPurchase();
- Safe access: if (ptr != null && ptr.value == target) then use ptr.
Building Compound Expressions
Combining operations
Compound expressions combine arithmetic, relational and logical operations to compute complex values or conditions. For example computing a weighted average requires combining multiplications and additions with a final division. Compound expressions are powerful but can become hard to read or maintain if too dense. To reduce errors, build complex expressions from smaller, well-named sub-expressions that document intent and simplify debugging.
Stepwise construction
Break down a compound expression into intermediate steps and assign these to descriptive variables. This practice improves readability and allows inspection of intermediate values. For example compute subtotal = sum(prices); tax = subtotal * TAX_RATE; total = subtotal + tax is easier to read and test than a single long expression. Refactoring into steps also helps localise errors: if the result is wrong you can check which intermediate value is off.
Using parentheses
Use parentheses liberally to make grouping clear. Parentheses are not only for correctness but also for documentation. When mixing addition and multiplication, or arithmetic with concatenation and string operations, parentheses show which operations you expect to happen together. Explicit grouping prevents dependence on remembering complex precedence rules and reduces the chance of logical mistakes.
Ternary and conditional expressions
Many languages offer a conditional (ternary) operator that compactly chooses between two expressions: condition ? expr1 : expr2. This can make simple if-else assignments concise, but overuse reduces readability. Prefer ternary only for short, simple choices and use multi-line if-else when conditions or results are complex.
Testing and correctness
Thoroughly test compound expressions especially at boundaries and with combinations of boolean flags. When expressions mix types, ensure conversions are correct to avoid truncation or rounding errors. Use unit tests to exercise different branches and document expected outcomes for clarity. When performance matters, evaluate whether combining operations into one expression affects optimisation or temporaries; micro-optimise only when necessary and after measuring performance.
Readability over cleverness
Prioritise clear code: choose descriptive variable names for sub-expressions, prefer multiple statements over a single dense line when it improves understanding, and comment non-obvious groupings. Compound expressions are a useful tool but should be used with judicious design to keep code maintainable and correct.
- Weighted average: result = (a * w1 + b * w2) / (w1 + w2).
- Ternary: grade = (marks >= 90) ? 'A' : 'B'.
- Split complex: subtotal = sum(prices); tax = subtotal * TAX_RATE; total = subtotal + tax.
- Combined condition: if ((age >= 18 && age <= 25) || (hasPermission)) then allow.
- Ternary operator: condition ? expr1 : expr2
- Weighted average: (Σ weight_i * value_i) / (Σ weight_i)
Debugging Expressions and Tracing Values
Tracing by hand
Tracing means following the values of variables step-by-step as the program executes. For a given input, write down initial variable values, then evaluate each statement in order and update the table. This manual technique is especially useful in exams and when debugging logic problems because it forces you to consider exactly how each expression is evaluated. Include intermediate values when expressions are compound so you can spot where values diverge from expectation.
Using print-based debugging
A simple and effective method is to insert print statements that show the values of variables at key points. Print intermediate results before and after operations to confirm they match expected values. Use clear labels in prints so output can be easily matched to code positions. Remember to remove or disable these prints after debugging to avoid cluttering program output and logs.
Interactive debugging tools
Modern IDEs offer debuggers with breakpoints, single-step execution, and watches. Set a breakpoint where you suspect a problem and inspect local variables and the call stack. Watches let you track specific variables as execution proceeds. Use step-over and step-into features to examine function behaviour and confirm that expressions evaluate as intended. These tools reveal the program state without changing it and are invaluable for complex bugs.
Checklists and common approaches
A debugging checklist helps work systematically: (1) reproduce the problem reliably, (2) isolate the smallest failing case, (3) inspect values with prints or debugger, (4) check types and initializations, (5) look for boundary conditions and off-by-one errors, (6) verify conversions and rounding. This disciplined approach reduces guesswork and helps pinpoint root causes faster.
Assertions and tests
Use assertions to declare expected properties of variables at runtime; assertions fail early and point directly to violated assumptions. Unit tests automate checking of expressions across many scenarios and prevent regressions. Write tests for edge cases like zero, negative numbers, extremely large values, and empty inputs. Tests and assertions provide a safety net that makes future changes safer.
Documentation and reproducibility
When a bug is found, document the failing input and the steps to reproduce it. After fixing, add tests that cover the scenario. Reproducible test cases ensure the problem stays fixed and help others understand and validate the solution. Combined with modular code and clear variable naming, disciplined debugging and tracing practices produce reliable and maintainable programs.
- Trace expression x = (a + b) * c step-by-step with given a, b, c to obtain final x.
- Insert print statements: print("subtotal=", subtotal) before computing total.
- Use a debugger to set breakpoint at loop start and watch index and accumulator values.
- Add assertion: assert(total >= 0) to ensure value invariant holds during execution.
Practical Exercises and Examples
Purpose of exercises
Practical exercises apply the theory of variables and expressions to concrete problems. They develop the habit of choosing correct variable types, naming variables clearly, writing correct expressions and testing results with multiple inputs. Exercises should range from simple calculations to multi-step problems that combine arithmetic, string handling and boolean logic so students gain confidence in composing expressions and tracing values.
Simple arithmetic problems
Start with tasks such as computing area, perimeter, averages and percentage. These problems reinforce declaring appropriate variables, performing arithmetic with correct order of operations, and printing results. For example, compute the area of a triangle using area = 0.5 * base * height and test with integer and floating inputs to see effects of integer division and casting.
String and formatting tasks
Exercises on constructing messages, concatenating names, and formatting currency or dates teach string expressions and conversions between numbers and strings. For instance build a greeting message using firstName and lastName, and format a numeric score to two decimal places. Emphasise using efficient builders or formatters when repeated concatenation would be inefficient.
Boolean logic and control flow
Create problems that use relational and logical operators: eligibility checks, range tests, combined conditions for discounts or permissions. Ask students to rewrite long conditions using named boolean variables for clarity. Provide edge cases to test, like boundary ages or exactly equal values, and show how short-circuit evaluation can prevent errors such as null dereference.
Mixed-type and precision examples
Exercises that mix integers and floats show implicit promotion and require explicit casting where needed. For example, compute average marks and ensure the result shows decimal places. Tasks involving currency can demonstrate why using decimal types or integer minor-units avoids floating-point rounding errors. Discuss trade-offs for accuracy versus performance.
Debugging and tracing exercises
Provide intentionally buggy code and ask students to trace and fix it. Include common mistakes such as off-by-one errors, uninitialised variables, wrong operator use, and incorrect casting. Require writing test cases that prove the bug is fixed. Encouraging peer review and written explanations of fixes reinforces learning and develops communication skills around code.
- Compute income tax: taxable = income - deductions; tax = taxable * TAX_RATE; net = income - tax.
- Determine grade: if (marks >= 90) grade = 'A' else if (marks >= 75) grade = 'B' else 'C'.
- Convert temperature: celsius = (fahrenheit - 32) * 5 / 9 with careful casting to preserve fractions.
- Format output: message = "Hello, " + name + "! Your score: " + (score) to present results.
Key Concepts
- Variable
- A named storage location in a program that can hold a value which may change.
- Constant
- A named value that does not change during program execution.
- Literal
- A fixed value written directly in the code such as 42 or "hello".
- Data type
- A classification that specifies the kind of values a variable can hold and the operations allowed.
- Declaration
- An instruction that introduces a variable name and its data type to the program.
- Initialization
- The assignment of an initial value to a variable at the time of declaration or later.
- Assignment
- The operation of storing a value into a variable using an assignment operator.
- Expression
- A combination of values, variables and operators that evaluates to a single value.
- Operator precedence
- Rules that determine the order in which operators are applied in an expression.
- Associativity
- The rule that resolves evaluation order among operators of the same precedence (left or right).
- Type conversion
- The process of changing a value from one data type to another, either implicitly or explicitly.
- Casting
- An explicit request by the programmer to convert a value to a different data type.
- Boolean expression
- An expression that evaluates to true or false.
- Side effect
- A change of program state caused by an expression, such as modifying a variable or I/O.
- Scope
- The region of a program where a variable name is visible and can be used.
- Lifetime
- The period during program execution when a variable occupies memory and holds a value.
- Modulus
- An operator that returns the remainder after integer division.
- Concatenation
- The operation of joining two strings end-to-end.
Practice Questions
-
What is a variable and why do we use it? / चर क्या है और हम इसका उपयोग क्यों करते हैं?
Show answer
A variable is a named storage location in a program that holds a value that can change; we use variables to store and manipulate data so programs can work with input, compute results and avoid repeating literal values. / एक चर प्रोग्राम में एक नामित भंडारण स्थान है जो एक मान रखता है जो बदल सकता है; हम चर का उपयोग डेटा संग्रहीत करने और संसाधित करने के लिए करते हैं ताकि प्रोग्राम इनपुट के साथ काम कर सकें, परिणाम गणना कर सकें और हार्ड-कोड किए गए मानों की पुनरावृत्ति से बचा जा सके।
-
Declare an integer variable count and initialize it to 10. / एक पूर्णांक चर count घोषित करें और इसे 10 से आरंभ करें।
Show answer
Declaration example: int count = 10; This creates an integer variable named count with initial value 10. / घोषणा उदाहरण: int count = 10; इससे count नाम का एक पूर्णांक चर बनता है जिसकी प्रारंभिक मान 10 होती है।
-
What is the difference between a literal and a constant? / एक लिटरल और एक कॉन्स्टेंट में क्या अंतर है?
Show answer
A literal is a fixed value written directly in code (for example 5 or "hi"); a constant is a named identifier bound to a fixed value that cannot change, improving readability and maintainability. / एक लिटरल कोड में सीधे लिखा गया स्थिर मान होता है (जैसे 5 या "hi"); एक कॉन्स्टेंट एक नामित पहचानकर्ता है जो एक स्थिर मान से जुड़ा होता है और बदल नहीं सकता, जो पठनीयता और रखरखाव में सुधार करता है।
-
Evaluate the expression 3 + 4 * 2 and explain the precedence used. / 3 + 4 * 2 अभिव्यक्ति का मूल्यांकन करें और प्रयोग की गई प्राधिकारता समझाएँ।
Show answer
3 + 4 * 2 = 3 + (4 * 2) = 3 + 8 = 11 because multiplication has higher precedence than addition. / 3 + 4 * 2 = 3 + (4 * 2) = 3 + 8 = 11 क्योंकि गुणा का अभिव्यक्ति में जोड़ से अधिक प्राधिकार है।
-
What is the result of integer division 7 / 2 and how can you get 3.5 instead? / पूर्णांक विभाजन 7 / 2 का परिणाम क्या होगा और 3.5 कैसे प्राप्त करेंगे?
Show answer
Integer division 7 / 2 gives 3 (fraction truncated). To get 3.5 use floating division by converting at least one operand to float: 7.0 / 2 or (double)7 / 2 gives 3.5. / पूर्णांक विभाजन 7 / 2 का परिणाम 3 होगा (दरज भाग लिया गया). 3.5 प्राप्त करने के लिए कम से कम एक अपरेन्ड को फ्लोट में बदलें: 7.0 / 2 या (double)7 / 2 3.5 देगा।
-
Write a boolean expression to check if x is between 10 and 20 inclusive. / x का मान 10 और 20 के बीच (सहित) है यह जांचने के लिये एक बूलियन अभिव्यक्ति लिखें।
Show answer
Expression: (x >= 10) && (x <= 20). This is true when x is 10 through 20 inclusive. / अभिव्यक्ति: (x >= 10) && (x <= 20). यह तब सत्य होगा जब x 10 से 20 तक (दोनों सहित) होगा।
-
Explain implicit and explicit type conversion with an example. / एक उदाहरण के साथ निहित (implicit) और स्पष्ट (explicit) प्रकार रूपांतरण समझाइए।
Show answer
Implicit conversion is automatic promotion, e.g., int 5 added to float 2.0 gives float 7.0. Explicit conversion (casting) is forced by the programmer, e.g., int x = (int)3.9 gives x = 3 where fractional part is truncated. / निहित रूपांतरण स्वचालित प्रमोशन है, जैसे int 5 को float 2.0 में जोड़ने पर float 7.0 मिलता है। स्पष्ट रूपांतरण (casting) प्रोग्रामर द्वारा जबरदस्ती होता है, जैसे int x = (int)3.9 देने पर x = 3 होगा और दशमलव भाग कट जाएगा।
-
What is a side effect in an expression? Give one example. / अभिव्यक्ति में side effect क्या है? एक उदाहरण दें।
Show answer
A side effect is a change in program state caused by evaluating an expression, such as modifying a variable or performing I/O. Example: x = x + 1 has the side effect of changing x; print(x) writes output. / Side effect वह होता है जब किसी अभिव्यक्ति के मूल्यांकन से प्रोग्राम की स्थिति बदलती है, जैसे किसी चर का मान बदलना या I/O करना। उदाहरण: x = x + 1 से x का मान बदल जाता है; print(x) आउटपुट लिखता है।
-
Identify the error: if (a = 0) { ... } / त्रुटि पहचानें: if (a = 0) { ... }
Show answer
This uses assignment (=) instead of comparison (==). It assigns 0 to a and usually causes logic error; correct form is if (a == 0). / यह तुलना (==) के बजाय असाइनमेंट (=) का प्रयोग कर रहा है। यह a को 0 असाइन कर देगा और सामान्यतः तर्क त्रुटि पैदा करेगा; सही रूप if (a == 0) है।
-
How can you avoid off-by-one errors in loops? / loops में off-by-one त्रुटियों से कैसे बचा जा सकता है?
Show answer
Avoid off-by-one errors by carefully deciding start and end conditions, using < rather than <= when iterating 0 to n-1, testing boundary cases, and writing clear loop invariants or using descriptive variable names. / शुरुआत और समाप्ति स्थिति को सावधानी से तय करके, 0 से n-1 तक के लिए < का उपयोग करके (<= के बजाय), सीमा मामलों का परीक्षण करके, और स्पष्ट लूप इनवारियंट या वर्णनात्मक नामों का प्रयोग करके off-by-one त्रुटियों से बचा जा सकता है।
-
Given: int a = 5; int b = a++; What are values of a and b after execution? / दिया है: int a = 5; int b = a++; निष्पादन के बाद a और b के मान क्या होंगे?
Show answer
After execution, a becomes 6 and b is 5 because post-increment returns the original value then increments the variable. / निष्पादन के बाद a 6 हो जाएगा और b 5 होगा क्योंकि post-increment पहले मूल मान लौटाता है और फिर चर को एक से बढ़ाता है।
-
Write an expression to compute the average of three numbers a, b and c as a floating-point result. / तीन संख्याओं a, b और c का औसत एक floating-point परिणाम के रूप में निकालने के लिये अभिव्यक्ति लिखें।
Show answer
Use: average = (a + b + c) / 3.0; Ensure 3.0 is floating to avoid integer division; alternatively cast: (double)(a + b + c) / 3. / प्रयोग करें: average = (a + b + c) / 3.0; 3.0 को floating रखें ताकि integer विभाजन न हो; वैकल्पिक रूप से casting: (double)(a + b + c) / 3।
Related Laws & Principles
Explore allFoundational laws & principles connected to this chapter — tap to open in the Laws Explorer.