C Language
Contents
Command-Line Arguments (argc and argv)
In C, command-line arguments are passed to main() through two parameters:
int main(int argc, char **argv)
-
**argc**(Argument Count): The total number of command-line arguments, including the program name. -
**argv**(Argument Vector): An array of strings containing the arguments.argv[0]→ Program name or path.argv[1]→ First user-provided argument.argv[2]→ Second user-provided argument.
Example:
./fib 10
| Variable | Value |
|---|---|
argc |
2 |
argv[0] |
"./fib" |
argv[1] |
"10" |
To ensure exactly one user-provided argument:
if (argc != 2) {
printf("Invalid number of arguments!\n");
return EXIT_FAILURE;
}
Function Declaration vs. Function Definition in C
In C, a function can be declared before main() and defined after main(). This allows the compiler to recognize a function before encountering its implementation.
1. Function Declaration (Prototype)
A function declaration introduces a function to the compiler without providing its implementation.
unsigned long fib(unsigned long n);
It specifies:
- Return type:
unsigned long - Function name:
fib - Parameter:
unsigned long n - Semicolon (
;): Indicates that this is only a declaration.
The compiler uses this information to check whether function calls have the correct argument types and return type.
2. Function Definition (Implementation)
A function definition provides the actual implementation of the function.
unsigned long fib(unsigned long n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
- Contains the executable code inside
{ }. - Defines what the function actually does.
- Also serves as a declaration.
3. Why Separate Declaration and Definition?
C requires a function to be declared before it is called.
A declaration allows a function to be called even when its definition appears later in the source file.
Example:
#include <stdio.h>
// 1. Function Declaration
unsigned long fib(unsigned long n);
int main(void) {
// 2. Function Call
unsigned long result = fib(5);
printf("%lu\n", result);
return 0;
}
// 3. Function Definition
unsigned long fib(unsigned long n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
Source code order:
- Declaration: Tells the compiler that
fib()exists and specifies its interface. - Function call:
main()callsfib(5). - Definition: Provides the implementation of
fib().
This represents the order in the source code, not the runtime execution order.
4. Is a Separate Declaration Always Necessary?
No. If a function is fully defined before its first use, a separate declaration is unnecessary.
#include <stdio.h>
// Definition comes first
unsigned long fib(unsigned long n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
int main(void) {
printf("%lu\n", fib(5));
return 0;
}
The compiler already knows fib() when it encounters the function call inside main().
Declarations in Larger Projects
In larger C projects, declarations and definitions are commonly separated into different files.
| File | Purpose |
|---|---|
.h (Header file) |
Contains function declarations (prototypes). |
.c (Source file) |
Contains function definitions (implementations). |
This allows multiple source files to use the same function interface without duplicating its implementation.
Key Takeaways
- Declaration: Describes a function's interface (what it accepts and returns).
- Definition: Provides the actual implementation (what it does).
- A function must be declared before it is called.
- A definition also counts as a declaration.
- A separate prototype is unnecessary if the function is already defined before its first use.
- In larger projects, prototypes are typically placed in
.hfiles and implementations in.cfiles.
Converting Strings to Numbers (strtoul)
Command-line arguments are always received as strings, even when they represent numbers.
The strtoul() function, provided by <stdlib.h>, converts a string into an unsigned long integer.
Syntax:
strtoul(nptr, endptr, base);
| Parameter | Description |
|---|---|
nptr |
String to convert |
endptr |
Pointer used to identify where conversion stopped; NULL if unused |
base |
Number system (10 = decimal, 16 = hexadecimal) |
Example:
unsigned long val = strtoul(argv[1], NULL, 10);
This converts the first user-provided argument from a decimal string into an unsigned long.
For ./fib 10:
argv[1]contains"10"(string).strtoul()converts"10"into10(number).valstores the resulting numeric value.
Important: strtoul() does not automatically guarantee valid input. For robust validation, use endptr and errno to detect invalid input and conversion errors.