QUESTION 01 · Functions
What is a user-defined function?
2 marksAnswer
A user-defined function is a named block of code written by the programmer to perform a task.
- It can receive values through parameters.
- It can return a result to its caller.

AR25 · I Year I Semester · 2025–2026 · Unit III: Functions and Program Structure
QUESTION 01 · Functions
A user-defined function is a named block of code written by the programmer to perform a task.
QUESTION 02 · Functions
A function groups statements that perform a particular task. A program can call the function whenever that task is needed.
The example defines add to receive two integers and return their sum. main calls add(4, 6). The function receives the values in a and b, calculates 10 and returns it. printf then displays the returned result. The function definition appears before main, so it also provides the required declaration before the call.
Keep each function focused on a clear task. Its parameter and return types form its interface: they describe how values enter and leave it. A function is not executed merely because it is defined; a call is needed. For the fixed integer addition shown here, time and extra working space are both O(1).
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main(void)
{
printf("Sum = %d\n", add(4, 6));
return 0;
}This example uses values already written in the program.
Sum = 10Related questions in the function declarations category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define function signature.
Paper P05 · page 1What is the signature of a function?
Paper P06 · page 1QUESTION 03 · Functions
A function prototype declares a function and specifies the types of its parameters.
QUESTION 04 · Functions
A declaration describes a function, a definition supplies its body, and a call executes it.
int square(int number);int before the name is the return type. square is the function name. int number specifies one integer parameter; the parameter name is optional in a prototype. The semicolon ends the declaration. A prototype does not contain the function body.
int square(int number)
{
return number * number;
}In square(5), the value 5 is supplied as an argument. Control enters the definition, number receives 5 and the expression number * number produces 25. return sends the value back to the caller. The example declares the function before main and defines it afterwards.
The compiler can detect many wrong argument counts and incompatible types when a prototype is visible. A prototype does not prove the function computes the right answer; the body must still be tested. The sample square value is deliberately small enough for int arithmetic.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
int square(int number);
int main(void)
{
printf("Square = %d\n", square(5));
return 0;
}
int square(int number)
{
return number * number;
}This example uses values already written in the program.
Square = 25Related questions in the function declarations category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define function signature.
Paper P05 · page 1What is the signature of a function?
Paper P06 · page 1QUESTION 05 · Functions
Functions may have no arguments and no value, arguments and no value, no arguments and a value, or arguments and a value.
QUESTION 06 · Functions
Functions are commonly classified by whether they receive arguments and whether they return a value.
void greet(void)
{
puts("Welcome");
}A function such as void show_square(int n) receives a number and displays its square. The caller supplies the input through an argument, but the function does not return a value. Displaying a result is an output action, not a returned value.
A function such as int fixed_limit(void) can return a fixed limit without receiving arguments. It might instead obtain a value from another permitted source, but that is separate from the parameter list. The caller can store or use its returned value.
A function such as int add(int a, int b) receives two numbers and returns their sum. This is useful when the caller should decide whether to print the result, store it or use it in another calculation.
Choose the interface according to the task. Passing values as arguments makes a function easier to reuse than making every function read directly from the keyboard. Returning a calculated value often makes testing easier. A void function may still change an object through a pointer parameter or display output; void only says there is no returned value.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void greet(void) { puts("Welcome"); }
void show_square(int n) { printf("Square = %d\n", n * n); }
int fixed_limit(void) { return 10; }
int add(int a, int b) { return a + b; }
int main(void)
{
greet();
show_square(3);
printf("Limit = %d\n", fixed_limit());
printf("Sum = %d\n", add(4, 6));
return 0;
}This example uses values already written in the program.
Welcome
Square = 9
Limit = 10
Sum = 10Related questions in the function categories category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Discuss types of functions based on parameters and return type.
Paper P02 · page 2Explain differences between user-defined and library functions.
Paper P02 · page 2QUESTION 07 · Functions
Actual arguments are expressions supplied in a call. Formal parameters are the variables declared in the function definition to receive their values.
QUESTION 08 · Functions
Functions communicate by receiving argument values, returning a value and, when appropriate, accessing objects through pointers or shared declarations.
An argument is an expression written in the call. In add(x, 5), the value of x and the value 5 are supplied. An argument can be a constant, variable or a more complex expression, provided its type and use are suitable for the function.
Parameters are declared in the function definition. In int add(int a, int b), a and b are separate local parameter objects for each call. Their names need not be the same as the caller’s variable names. C passes values: changes to a or b alone do not change the caller’s ordinary integer variables.
return expression; supplies one result value to the caller for a non-void function. The caller can assign that result to a variable, print it or use it in another expression. The return type describes the kind of result.
If x contains 4, add(x, 5) supplies 4 and 5. The parameter objects receive those values. The function returns 9. If the caller writes result = add(x, 5);, result becomes 9 while x remains 4.
Use a visible prototype and compatible types. C does not generally specify the order in which different argument expressions are evaluated. Avoid calls that update the same variable in conflicting argument expressions. Prefer clear, independent arguments. Pointer-based output is introduced separately; the pointer value is still passed by value.
Related questions in the function declarations category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define function signature.
Paper P05 · page 1What is the signature of a function?
Paper P06 · page 1QUESTION 09 · Functions
It ends the current function call and transfers control back to the caller.
QUESTION 10 · Functions
The return statement finishes the current function call. For a non-void function, it can also send a result value to the caller.
return expression; /* value-returning function */
return; /* void function */The type written before the function name specifies its result type. In double half(int n), the function returns a double. The expression n / 2.0 uses floating-point arithmetic, so half(7) returns 3.5. Returning a value can involve conversion to the declared return type.
When return is reached, later statements on that path in the same call do not execute. A function can contain several return statements for different conditions, but a particular call completes through only one return path. The caller resumes after the call with the returned result when there is one.
The sample separates calculation from display. half performs the calculation; main decides the output format. This allows the result to be used in a later calculation without changing half.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
double half(int n)
{
return n / 2.0;
}
int main(void)
{
printf("Half = %.1f\n", half(7));
return 0;
}This example uses values already written in the program.
Half = 3.5Related questions in the function declarations category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define function signature.
Paper P05 · page 1What is the signature of a function?
Paper P06 · page 1QUESTION 11 · Function Communication
No. C passes its value into a separate parameter object.
QUESTION 12 · Function Communication
C uses pass by value: each parameter receives a value supplied by the corresponding argument. An ordinary integer parameter is a separate object from the caller’s integer variable.
main starts with number = 10 and calls change(number). The parameter n receives 10. Inside change, n = 25 changes only n, so the first line prints 25. After the function returns, number in main still contains 10. This shows the difference between a copied value and the original object.
A function can use and update a working parameter without unintentionally replacing the caller’s ordinary value. This helps keep calculations separate. For example, a digit-processing function can repeatedly divide its local copy while the original input remains available to main.
Passing an address does not change C into pass by reference. The address is a pointer value, and that value is copied into a pointer parameter. The function can use the copied pointer to access the same caller-owned object. Changing the pointer parameter itself is different from changing the object to which it points.
The fixed-size integer example uses constant work and a fixed number of objects, so time and extra space are O(1). The copying cost of an argument depends on its type; do not assume every possible argument is a single small integer.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void change(int n)
{
n = 25;
printf("Inside = %d\n", n);
}
int main(void)
{
int number = 10;
change(number);
printf("Outside = %d\n", number);
return 0;
}This example uses values already written in the program.
Inside = 25
Outside = 10Related questions in the function arguments category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define formal arguments.
Paper P02 · page 1Write a C program using functions to swap two numbers using global variables and the call-by-reference concept.
Paper P02 · page 2QUESTION 13 · Function Communication
Pass the integer’s address to an int * parameter and assign through that pointer.
QUESTION 14 · Function Communication
A function can modify a caller’s object when it receives a valid pointer to that writable object and assigns through the pointer.
main starts with x = 4 and y = 9. swap(&x, &y) passes their addresses. The parameter a identifies x and b identifies y. temporary receives 4, *a becomes 9 and *b becomes 4. After the call, the original objects in main contain the swapped values.
This is often called call by address in introductory courses. C itself still passes arguments by value: the pointer values are copied. Assigning a different address to the local parameter a would not change a caller pointer variable. Assigning to *a changes the object reached through the copied pointer.
Both pointers must identify suitable live, writable int objects before they are dereferenced. The example always passes addresses of local variables that remain alive during the call. There are three fixed assignments and one temporary integer, so the swap takes O(1) time and O(1) auxiliary space. Full pointer details belong to Unit V.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void swap(int *a, int *b)
{
int temporary = *a;
*a = *b;
*b = temporary;
}
int main(void)
{
int x = 4, y = 9;
swap(&x, &y);
printf("x = %d, y = %d\n", x, y);
return 0;
}This example uses values already written in the program.
x = 9, y = 4Suppose main contains int x = 4; and int *p = &x;. A function called with p receives a copy of the address stored in p. Call that local parameter q. Inside the function, suppose another local integer is declared as int other = 9;.
| Statement inside the function | Effect inside the function | Effect visible to main |
|---|---|---|
| *q = 20; | Write to the int identified by q | x becomes 20 |
| q = &other; | Make q identify other instead | p still identifies x; x is unchanged by this assignment |
The first statement changes an integer. The second changes only the function’s local pointer variable. A pointer is a value that can be copied, just like an integer; copying it does not create a new copy of the pointed-to object.
temporary = *a saves 4 before x is overwritten.*a = *b places 9 in x. At this point x and y both contain 9.*b = temporary places the saved 4 in y.Without the temporary value, the original 4 would be lost after the second step. Calling swap(&x, &x) is also valid for this implementation: each assignment uses the same live integer and its value stays unchanged. Passing a null pointer is invalid because the function dereferences both parameters.
Related questions in the function arguments category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Define formal arguments.
Paper P02 · page 1Write a C program using functions to swap two numbers using global variables and the call-by-reference concept.
Paper P02 · page 2QUESTION 15 · Scope and Lifetime
Scope is the part of the source program in which a name can be used to refer to its declaration.
QUESTION 16 · Scope and Lifetime
Scope determines where a name is visible in the source program. It does not by itself determine how long the associated object exists.
A local variable declared in a block can normally be used from its declaration to the end of that block. Nested blocks can use a visible outer name unless an inner declaration hides it. Function parameters in a definition are available within that function body.
An object declared outside every function has file scope. Its name is visible from its declaration to the end of the translation unit, subject to hiding. A translation unit is roughly a source file after preprocessing, including text brought in from headers. Linkage determines whether declarations can refer to the same entity across translation units.
The file-scope value is 10. Inside main, a local value is declared as 20, hiding that file-scope name. A nested block declares another value as 30, which hides the outer local name inside that block. The lines therefore print 20, 30 and 20. The object with value 20 was not changed by declaring the inner object.
C also has function scope for labels and function-prototype scope for parameter names in prototypes. Use descriptive names and avoid unnecessary hiding, because similar names can confuse readers. A local static object has block scope but lasts throughout execution; this is why scope and lifetime must be studied separately.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
int value = 10;
int main(void)
{
int value = 20;
printf("Outer = %d\n", value);
{
int value = 30;
printf("Inner = %d\n", value);
}
printf("Outer again = %d\n", value);
return 0;
}This example uses values already written in the program.
Outer = 20
Inner = 30
Outer again = 20Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 17 · Scope and Lifetime
Scope tells where a name is visible; lifetime tells when its object exists during execution.
QUESTION 18 · Scope and Lifetime
Scope, lifetime and linkage answer three different questions about a declaration and its associated object.
A name declared inside a block generally has block scope. Outside that scope, the same spelling cannot be used to reach that declaration. Scope is a source-code rule about names, rather than a count of seconds or function calls.
An ordinary automatic local object is associated with a particular execution of its block. A static-duration object exists throughout program execution. A function call can end the lifetime of an ordinary automatic local object while a local static object continues to exist. Allocated objects have a different lifetime managed through memory allocation, covered in Unit V.
External linkage can connect declarations across translation units. Internal linkage connects declarations within one translation unit. A typical local variable has no linkage. Linkage is not the same as visibility: a file-scope static object has internal linkage, while a block-local static object has no linkage.
In void count(void) { static int total = 0; ++total; }, the name total has block scope. Its object has static storage duration, so the value can remain after count returns. A later call uses the same object. Scope is local, but the lifetime is not limited to one call.
Do not return a pointer to an ordinary local object that stops existing when the call ends. Do not assume that a local name always describes temporary storage. State scope, storage duration and linkage separately when comparing storage classes.
Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 19 · Storage Classes
It has automatic storage duration unless another relevant declaration changes that rule.
QUESTION 20 · Storage Classes
In C11, auto explicitly declares an automatic block-local object. Ordinary local variables usually have the same storage duration without writing auto.
auto int count = 0;
int other_count = 0; /* also automatic here */Each call to show creates its automatic count and initialises it to zero. The increment makes it 1, so three separate calls print 1, 1 and 1. The value is not saved for the next call. A local static counter behaves differently because it refers to one lasting object.
Automatic variables are suitable for temporary calculations, counters and intermediate results that belong to one call. Recursive calls can each have their own automatic parameter and local values. This helps one call avoid overwriting another call’s ordinary locals.
Initialise before reading. Avoid returning the address of an ordinary automatic local object because its lifetime ends when its block execution ends. auto does not mean that the compiler should infer the type in the C11 examples used here; the keyword must be understood in the selected language version.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void show(void)
{
auto int count = 0;
++count;
printf("%d\n", count);
}
int main(void)
{
show(); show(); show();
return 0;
}This example uses values already written in the program.
1
1
1Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 21 · Storage Classes
No. In C11 it is a suggestion that the object may be accessed frequently.
QUESTION 22 · Storage Classes
The register storage-class specifier suggests that a variable may be accessed frequently. It does not guarantee a particular hardware location or faster execution.
register int i;The sample uses i as a small loop counter. It starts at 1, and each iteration adds i to sum. After i = 3 is processed, sum is 6. The loop would calculate the same result if register were omitted. A modern optimiser can choose efficient storage for ordinary variables too.
Do not write &i for a C11 register object. Consequently, a register int cannot directly be supplied to scanf as &i. The keyword is not a request for persistent storage and does not preserve a value across calls. It is also not a way to make shared updates safe between threads.
The example performs one addition for each value from 1 through n in its general form, so the loop takes O(n) time and O(1) auxiliary space. Adding register does not change that growth rate. Optimisation of a particular build and algorithm complexity are separate matters.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
int main(void)
{
int sum = 0;
for (register int i = 1; i <= 3; ++i) { sum += i; }
printf("Sum = %d\n", sum);
return 0;
}This example uses values already written in the program.
Sum = 6Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 23 · Storage Classes
Its object continues to exist and retains its stored value.
QUESTION 24 · Storage Classes
The meaning of static depends on where it is used. A local static object keeps its value across calls; a file-scope static declaration gives internal linkage.
In static int count = 0; inside a function, count has block scope and static storage duration. It is not recreated on every call. In these C examples its initial value is established before program startup, and later calls use the same object. If no initialiser is supplied, an arithmetic static-duration object is initialised to zero.
The first call to visit increments count from 0 to 1. The second increments the same object to 2, and the third to 3. The output is therefore 1, 2 and 3. Contrast this with an automatic count initialised to zero on every call, which would print 1 each time.
At file scope, static int total; defines a static-duration object with internal linkage. Other translation units cannot connect an external declaration to that entity. A static function at file scope also has internal linkage. This helps keep implementation details within one translation unit.
A local static object has no linkage; a file-scope static object has internal linkage. Both have static storage duration, but their scopes are different.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void visit(void)
{
static int count = 0;
++count;
printf("%d\n", count);
}
int main(void)
{
visit(); visit(); visit();
return 0;
}This example uses values already written in the program.
1
2
3Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 25 · Storage Classes
It declares an int named total, normally referring to a definition supplied elsewhere.
QUESTION 26 · Storage Classes
extern is commonly used to declare an object or function whose definition is supplied elsewhere, possibly in another source file.
extern int total; /* declaration */
int total = 10; /* definition at file scope */The declaration tells the compiler the name and type. The definition supplies the object. When compatible declarations have external linkage, they can refer to the same object across translation units. A header can contain an extern declaration while one source file contains the definition.
In the complete single-file example, total is declared before main and defined after main. The earlier declaration makes the name available when main is compiled. The definition gives total the initial value 10, which main prints. The order is chosen to show the difference clearly.
An object declared with external linkage has static storage duration. However, extern is not simply another word for global: a block-scope extern declaration can refer to an object defined outside that block. Linkage also depends on prior visible declarations, so avoid the oversimplification that extern always overrides an earlier static declaration.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
extern int total;
int main(void)
{
printf("Total = %d\n", total);
return 0;
}
int total = 10;This example uses values already written in the program.
Total = 10Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 27 · Storage Classes
Ordinary auto and register local objects have automatic storage duration.
QUESTION 28 · Storage Classes
Storage-class specifiers help describe how declarations relate to storage duration and linkage. Their scope depends on where the declaration appears.
A block-local auto object has automatic storage duration and no linkage. It is normally created for an execution of its block. Without a valid initialisation, an ordinary automatic scalar does not have a useful guaranteed starting value.
A block-local register object is also automatic and has no linkage. It suggests frequent access, but the compiler does not have to place it in a hardware register. In C11, its address cannot be taken with &.
A local static object has block scope, no linkage and a lifetime covering program execution. It retains its value across calls. A file-scope static object instead has file scope and internal linkage. Arithmetic objects with static storage duration are initialised to zero if no explicit initialiser is given.
A common extern declaration refers to an object defined elsewhere. That object can be shared across source files through compatible external-linkage declarations. A declaration without an initialiser does not ordinarily create a separate new object.
Use an automatic temporary for a calculation needed only during one call. Use a local static counter when lasting state is intentional. Use an extern declaration when referring to a shared definition. Do not choose a class solely by a simplified memory-location table: C does not require automatic objects to occupy a particular physical stack or register. State scope, duration and linkage separately.
| Declaration | Scope | Duration | Linkage / main rule |
|---|---|---|---|
| Block auto | Block | Automatic | None; initialise before reading |
| Block register | Block | Automatic | None; address cannot be taken in C11 |
| Block static | Block | Static | None; retains value |
| File static | File | Static | Internal |
| Typical extern declaration | At declaration scope | Static for referred external object | Refers to compatible shared definition |
Related questions in the storage classes category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
If a variable has auto storage class by default, why was the auto keyword introduced in C? Explain.
Paper P01 · page 1List and explain storage classes in C.
Paper P04 · page 1QUESTION 29 · Qualifiers and Preprocessor
It prevents modification through a const-qualified access to that object.
QUESTION 30 · Qualifiers and Preprocessor
Type qualifiers add properties to a type. The main introductory qualifiers are const, volatile and restrict; C11 also includes _Atomic with separate atomic-operation rules.
const int limit = 10; declares an object that cannot be assigned a new value through limit. A pointer to const can be used to allow reading without allowing modification through that pointer. const does not automatically make a C object an integer constant expression. Casting away const does not make an originally const-defined object safely writable.
volatile tells the implementation that accesses to an object have significance beyond ordinary calculations. It is used in implementation-specific hardware interfaces and suitable signal-handling situations. It does not guarantee atomic updates, mutual exclusion or thread synchronisation. A variable changing between threads needs the appropriate atomic or locking rules.
restrict is mainly used with pointer types. It expresses an access promise about the objects reached through pointers during the relevant execution. This can help optimisation when the promise is valid. It does not check the promise at runtime; violating the required access rules can cause undefined behaviour. Full pointer examples are deferred to Unit V.
The program declares a const rate and uses it to compute an amount. The rate can be read, but an assignment such as rate = 0.10 is not allowed through that name. The program does not contain that invalid assignment.
Qualifiers are not storage classes. A const object can still be an automatic local or have static storage duration, depending on its declaration. Qualifying a type does not by itself select a hardware memory location.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
int main(void)
{
const double rate = 0.05;
double amount = 200.0 * rate;
printf("Amount = %.2f\n", amount);
return 0;
}This example uses values already written in the program.
Amount = 10.00QUESTION 31 · Qualifiers and Preprocessor
It handles preprocessing directives and macro replacement before the later translation stages.
QUESTION 32 · Qualifiers and Preprocessor
The preprocessor handles directives and macro replacement as part of translating C source. A directive normally begins with # after any leading whitespace.
Use #include <stdio.h> for the standard input/output declarations. Quoted inclusion, such as #include "settings.h", is commonly used for project headers. The implementation defines the precise search rules. Including a header is not the same as copying the compiled implementation of every library function into the program.
The sample defines LIMIT as 3. During preprocessing, uses of the macro name are replaced by its replacement tokens. The resulting loop prints 1, 2 and 3. The macro is not an ordinary int variable and does not have a separate object storing 3.
Headers support shared declarations. Macros can name configuration values, and conditional compilation can choose platform or debug code. These operations affect the translated source; an ordinary runtime if instead makes a decision while the program is running.
Do not put a semicolon after a simple numeric macro unless a semicolon is intentionally part of the replacement. Macros are not checked like typed function parameters. Inspect expanded expressions carefully, especially when arithmetic operators or repeated arguments are involved.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
#define LIMIT 3
int main(void)
{
for (int i = 1; i <= LIMIT; ++i) { printf("%d\n", i); }
return 0;
}This example uses values already written in the program.
1
2
3Related questions in the preprocessor category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
What is the use of preprocessor directives? Explain.
Paper P01 · page 1Differentiate #undef and #ifndef.
Paper P02 · page 1QUESTION 33 · Qualifiers and Preprocessor
Parentheses help preserve the intended grouping after token replacement.
QUESTION 34 · Qualifiers and Preprocessor
A macro is a name with replacement tokens processed by the preprocessor. It may be object-like or function-like.
#define LIMIT 100#define SQUARE(x) ((x) * (x))SQUARE(2 + 3) expands to ((2 + 3) * (2 + 3)), giving 25. Without the parameter parentheses, an expansion such as 2 + 3 * 2 + 3 would give 11. The outer parentheses also protect the full result when it is placed inside another expression.
The parameter x occurs twice in SQUARE. Therefore its argument expression also appears twice after replacement. Do not write SQUARE(i++): the resulting expression modifies i without the ordering required by C and has undefined behaviour. Parentheses do not solve that problem. A typed function such as int square(int x) evaluates an argument once before using its parameter.
A function has a declared interface, parameter objects and a return type. A macro is token replacement and does not provide the same parameter type checking. A compiler may inline a real function, so do not assume a macro must be faster. Prefer a function for ordinary calculations unless a macro is specifically useful.
There must be no space between a function-like macro name and the opening parenthesis in its definition. #undef SQUARE removes the definition for later source. Avoid an accidental trailing semicolon in a simple expression macro.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main(void)
{
printf("Square = %d\n", SQUARE(2 + 3));
return 0;
}This example uses values already written in the program.
Square = 25Related questions in the preprocessor category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
What is the use of preprocessor directives? Explain.
Paper P01 · page 1Differentiate #undef and #ifndef.
Paper P02 · page 1QUESTION 35 · Qualifiers and Preprocessor
#if selects source text during preprocessing. An ordinary if selects a path during program execution.
QUESTION 36 · Qualifiers and Preprocessor
Conditional compilation includes or excludes source text according to preprocessing conditions.
The sample sets DEBUG to 1. #if DEBUG includes the debug message in the translated source, followed by the Ready message. If DEBUG were defined as 0, that debug line would be excluded. In contrast, #ifdef DEBUG would still succeed because the macro would remain defined.
#ifndef CODEBHAVYA_SETTINGS_H
#define CODEBHAVYA_SETTINGS_H
/* declarations */
#endifThe first inclusion defines the guard macro and includes the guarded contents. If the same header is included again in that translation unit, the macro already exists, so the contents are skipped. This prevents many repeated declarations or definitions from being processed incorrectly. It does not make an ordinary shared object definition safe to place in every source file; use suitable extern declarations.
Conditional compilation can select debug messages, optional features or platform-specific code. Use meaningful project-prefixed macro names and correctly pair each group with #endif. Do not use a runtime variable as though its value were available during preprocessing. A C const int object is not automatically a preprocessing macro or a permitted #if value.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
#define DEBUG 1
int main(void)
{
#if DEBUG
puts("Debug enabled");
#endif
puts("Ready");
return 0;
}This example uses values already written in the program.
Debug enabled
ReadyRelated questions in the preprocessor category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
What is the use of preprocessor directives? Explain.
Paper P01 · page 1Differentiate #undef and #ifndef.
Paper P02 · page 1QUESTION 37 · Recursion
A base case supplies an answer without another recursive call; a recursive case reduces the problem towards that base case.
QUESTION 38 · Recursion
Recursion occurs when a function calls itself directly or through other functions. A useful recursive solution solves a smaller related problem and eventually reaches a base case.
The base case is a condition whose answer is known without another recursive call. In a countdown, n <= 0 can be the stopping case. In factorial, n <= 1 returns 1 for the supported non-negative inputs.
The recursive case calls the function with a smaller or otherwise simpler input. countdown(n - 1) moves a positive integer closer to zero. Merely writing a self-call is not enough: it must move towards termination for every supported input.
countdown(3) prints 3 and calls countdown(2). That call prints 2 and calls countdown(1). The next call prints 1 and calls countdown(0). At zero the function returns immediately. The earlier calls then finish in reverse order. Each call has its own parameter object.
For a countdown from n, there are n printing calls and one base-case call. Time is O(n). With the usual model of one active call record per unfinished call, auxiliary space is O(n). C does not guarantee tail-call optimisation, so do not assume it removes the call depth.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
void countdown(int n)
{
if (n <= 0) { return; }
printf("%d\n", n);
countdown(n - 1);
}
int main(void)
{
countdown(3);
return 0;
}This example uses values already written in the program.
3
2
1Related questions in the recursion category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Explain recursion with an example program.
Paper P01 · page 1What is recursion? State its advantages and disadvantages.
Paper P02 · page 2QUESTION 39 · Recursion
For non-negative n, factorial(0) = 1 and factorial(n) = n × factorial(n - 1) when n > 0.
QUESTION 40 · Recursion
Recursive factorial uses the relationship n! = n × (n - 1)!, with 0! = 1.
For n = 4, the calls ask for factorial(4), factorial(3), factorial(2) and factorial(1). The final call returns 1. The pending multiplications then produce 2 × 1 = 2, 3 × 2 = 6 and 4 × 6 = 24. The original call returns 24 to main.
Every recursive call decreases a supported positive n by one. It eventually reaches 1, which is a base case. Input zero is also handled by the base case. main rejects negative input before converting it to unsigned, preventing an unintended very large unsigned value.
The result uses unsigned long long and the matching output format %llu. The supported limit 20 ensures that 20! fits the minimum range guaranteed for that type. A wider integer still has a finite range, so recursion cannot calculate arbitrary factorials accurately with this fixed type.
There is one smaller recursive call per level, with constant work apart from the call. The number of levels grows in proportion to n, giving O(n) time in the fixed-width model.
Pending calls wait for smaller results before multiplying. There are O(n) active calls in the usual call-record model, so auxiliary space is O(n). An iterative factorial can perform the same number of multiplications with O(1) auxiliary space.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
unsigned long long factorial(unsigned int n)
{
if (n <= 1U) { return 1ULL; }
return n * factorial(n - 1U);
}
int main(void)
{
int n;
if (scanf("%d", &n) != 1 || n < 0 || n > 20) {
puts("Unsupported input"); return 1;
}
printf("Factorial = %llu\n", factorial((unsigned int)n));
return 0;
}4Factorial = 24Related questions in the recursion category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Explain recursion with an example program.
Paper P01 · page 1What is recursion? State its advantages and disadvantages.
Paper P02 · page 2QUESTION 41 · Recursion
When b is zero, return a.
QUESTION 42 · Recursion
Euclid’s method finds the greatest common divisor by repeatedly replacing a pair with the second value and the remainder.
gcd(a, b) = a when b == 0
gcd(a, b) = gcd(b, a % b) otherwiseFor 48 and 18, the first remainder is 12, so the next pair is (18, 12). The next remainder is 6, giving (12, 6). The next remainder is zero, giving (6, 0). The base case returns 6. Earlier calls return the same value, so the greatest common divisor is 6.
Replacing a by a - q × b does not change the common divisors of a and b. The remainder a % b is exactly that difference for the integer quotient q. Thus the common divisors remain the same while the values become smaller. For positive b, the non-negative remainder is less than b, ensuring progress.
gcd(a, 0) returns a for positive a; gcd(0, b) returns b for positive b. This program rejects (0, 0) rather than assigning it an elementary greatest-positive-divisor result.
For positive inputs, Euclid’s algorithm uses O(log min(a, b)) remainder steps; more precisely the boundary cases can be expressed using 1 + min(a, b). Each one or two steps substantially reduces the smaller positive value. Recursive auxiliary space follows the number of active calls. Zero-input cases finish in constant work. This analysis treats fixed-width arithmetic operations as constant time.
/* CodeBhavya | PPS AR25 | Learning example */
#include <stdio.h>
unsigned int gcd(unsigned int a, unsigned int b)
{
if (b == 0U) { return a; }
return gcd(b, a % b);
}
int main(void)
{
int a, b;
if (scanf("%d%d", &a, &b) != 2 || a < 0 || b < 0 ||
a > 10000 || b > 10000 || (a == 0 && b == 0)) {
puts("Unsupported input"); return 1;
}
printf("GCD = %u\n", gcd((unsigned int)a, (unsigned int)b));
return 0;
}48 18GCD = 6Related questions in the recursion category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Explain recursion with an example program.
Paper P01 · page 1What is recursion? State its advantages and disadvantages.
Paper P02 · page 2QUESTION 43 · Recursion
Recursion repeats through function calls; iteration repeats through loops.
QUESTION 44 · Recursion
Recursion solves repeated work through calls to smaller problems. Iteration performs repeated work using a loop.
Recursive factorial returns 1 at its base case and otherwise returns n × factorial(n - 1). Each active call waits for the smaller result. The definition closely follows the mathematical relationship. With n levels it takes O(n) time and O(n) auxiliary space in the usual call-record model.
Iterative factorial starts result at 1 and multiplies it by each value from 2 through n. There is no chain of pending recursive calls. It also takes O(n) time, because the number of multiplications grows linearly. Only a counter and result are needed, giving O(1) auxiliary space.
For a simple factorial, iteration usually avoids unnecessary call depth. For naturally recursive structures, recursion can be clearer. Neither form is always faster or always better. Count the actual work and stored state. C does not guarantee tail-call optimisation, so it cannot be assumed to reduce every recursive function to constant extra space.
Both forms must handle 0! = 1, reject unsupported negative input and avoid overflowing the result type. Changing recursion to a loop does not remove arithmetic limits.
| Feature | Recursion | Iteration |
|---|---|---|
| Repetition | Smaller function calls | Loop iterations |
| Stopping | Base case | Loop condition |
| Time | O(n) | O(n) |
| Auxiliary space | O(n) active calls | O(1) variables |
Related questions in the recursion category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.
Explain recursion with an example program.
Paper P01 · page 1What is recursion? State its advantages and disadvantages.
Paper P02 · page 2