Docs
Parameters and Arguments
Function Parameters and Arguments
š Introduction
Parameters allow functions to receive data from the caller. Understanding how parameters work in C is crucial because C uses pass by value by default, meaning functions receive copies of arguments. This section covers all aspects of function parameters.
šÆ Parameters vs Arguments
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Function Definition: ā
ā ā
ā int add(int a, int b) āāāā Parameters (Formal) ā
ā { - a and b are parameters ā
ā return a + b; - Variables in definition ā
ā } ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Function Call: ā
ā ā
ā int x = 5, y = 10; ā
ā int sum = add(x, y); āāāā Arguments (Actual) ā
ā - x and y are arguments ā
ā - Values passed to function ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š¤ Pass by Value
C passes arguments by value, meaning a copy is made.
How It Works:
void modify(int n) {
n = n * 2; // Modifies COPY, not original
printf("Inside: %d\n", n);
}
int main() {
int x = 10;
modify(x);
printf("Outside: %d\n", x); // Still 10!
return 0;
}
Memory Diagram:
Before call: During call: After call:
āāāāāāāāāāāāāāā āāāāāāāāāāāāāāā āāāāāāāāāāāāāāā
ā main() ā ā main() ā ā main() ā
ā x = 10 ā ā x = 10 ā ā x = 10 ā
āāāāāāāāāāāāāāā āāāāāāāāāāāāāāā āāāāāāāāāāāāāāā
āāāāāāāāāāāāāāā
ā modify() ā
ā n = 10 ā āāŗ n = 20
ā (copy!) ā
āāāāāāāāāāāāāāā
Implications:
| Operation | Original Variable | Local Copy |
|---|---|---|
| Read | Safe | Has same value |
| Modify | Not affected | Only copy changes |
| Return | Unchanged | Destroyed after function |
š Different Parameter Types
1. Basic Types:
void printValues(int i, float f, double d, char c) {
printf("int: %d\n", i);
printf("float: %f\n", f);
printf("double: %lf\n", d);
printf("char: %c\n", c);
}
// Call:
printValues(42, 3.14f, 2.71828, 'A');
2. Array Parameters:
Arrays are special - they decay to pointers!
// These are equivalent:
void printArray(int arr[], int size);
void printArray(int *arr, int size);
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// Call:
int numbers[] = {1, 2, 3, 4, 5};
printArray(numbers, 5);
Important: Modifying array elements affects the original!
void doubleElements(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2; // Modifies original array!
}
}
3. String Parameters:
Strings are char arrays, so they also decay to pointers:
void printString(char str[]) {
printf("%s\n", str);
}
// or equivalently:
void printString(char *str) {
printf("%s\n", str);
}
// Call:
printString("Hello, World!");
4. 2D Array Parameters:
Must specify second dimension:
// Must specify columns
void printMatrix(int matrix[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
// Call:
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
printMatrix(matrix, 2);
š§ const Parameters
Use const to prevent modification:
For Basic Types:
void printNumber(const int n) {
// n = 10; // Error! Cannot modify const
printf("%d\n", n);
}
For Pointers/Arrays:
// Pointer to const data - cannot modify what it points to
void printArray(const int arr[], int size) {
for (int i = 0; i < size; i++) {
// arr[i] = 0; // Error! Cannot modify
printf("%d ", arr[i]);
}
}
// Const pointer to const data - cannot modify pointer or data
void printString(const char *const str) {
// *str = 'X'; // Error!
// str = NULL; // Error!
printf("%s\n", str);
}
š„ Default Values
C does NOT support default parameter values like C++!
// This does NOT work in C:
// void greet(char* name = "World") { ... }
// Workaround using wrapper function:
void greetWithName(char* name) {
printf("Hello, %s!\n", name);
}
void greet() {
greetWithName("World"); // Default
}
š¢ Variable Number of Arguments
C supports variadic functions using <stdarg.h>:
Basic Structure:
#include <stdarg.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
// Call:
int result = sum(4, 10, 20, 30, 40); // result = 100
Key Macros:
| Macro | Purpose |
|---|---|
va_list | Type for argument list |
va_start(ap, last) | Initialize argument list |
va_arg(ap, type) | Get next argument of type |
va_end(ap) | Clean up |
Example - printf-like function:
#include <stdarg.h>
void customPrint(const char *format, ...) {
va_list args;
va_start(args, format);
while (*format != '\0') {
if (*format == '%') {
format++;
switch (*format) {
case 'd':
printf("%d", va_arg(args, int));
break;
case 'f':
printf("%f", va_arg(args, double));
break;
case 's':
printf("%s", va_arg(args, char*));
break;
case '%':
printf("%%");
break;
}
} else {
putchar(*format);
}
format++;
}
va_end(args);
}
š Parameter Passing Summary
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā PARAMETER PASSING IN C ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā Basic Types (int, float, char) ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Pass by Value: COPY is made ā ā
ā ā Original cannot be modified ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā
ā Arrays ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Decay to pointers: ADDRESS is passed ā ā
ā ā Elements CAN be modified ā ā
ā ā Size NOT passed automatically ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā
ā Pointers ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Pass by Value (of address) ā ā
ā ā Can modify what pointer points to ā ā
ā ā Cannot change original pointer itself ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā
ā Structs ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Pass by Value: Entire struct COPIED ā ā
ā ā Expensive for large structs ā ā
ā ā Pass pointer for efficiency ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š Simulating Pass by Reference
To modify the original variable, pass its address:
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Before: x=%d, y=%d\n", x, y);
swap(&x, &y); // Pass addresses
printf("After: x=%d, y=%d\n", x, y);
return 0;
}
// Output:
// Before: x=10, y=20
// After: x=20, y=10
š Parameter Order Best Practices
Recommended Order:
- ā¢Output parameters first (pointers to results)
- ā¢Input parameters next
- ā¢Optional/configuration parameters last
// Example following convention:
int readData(
int *result, // Output
const char *filename, // Input
int maxSize // Configuration
);
Naming Conventions:
// Good - descriptive names
void copyString(char *destination, const char *source, int maxLength);
// Bad - unclear abbreviations
void cpyStr(char *d, const char *s, int m);
ā ļø Common Mistakes
1. Forgetting Array Size:
// Wrong - no way to know array size
void processArray(int arr[]) {
// How many elements?
}
// Correct - pass size
void processArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
// process arr[i]
}
}
2. Returning Pointer to Local:
// WRONG! Undefined behavior
int* createNumber() {
int n = 42;
return &n; // n is destroyed after return!
}
// Correct - use dynamic allocation
int* createNumber() {
int *n = malloc(sizeof(int));
*n = 42;
return n; // Caller must free()
}
3. Type Mismatch:
void printDouble(double d) {
printf("%f\n", d);
}
int main() {
int x = 10;
printDouble(x); // OK - implicit conversion
// But be careful with pointers:
int *pi = &x;
// printDouble(*pi); // This works
// printDouble(pi); // Warning! Wrong type
return 0;
}
š Key Takeaways
- ā¢C uses pass by value - copies are made
- ā¢Arrays decay to pointers - elements can be modified
- ā¢Use const for read-only parameters
- ā¢Pass pointers to modify original variables
- ā¢Always pass array size as separate parameter
- ā¢Structs are copied entirely - use pointers for large ones
- ā¢Use stdarg.h for variable arguments
āļø Next Topic
Continue to Recursion to learn about functions that call themselves.