Nexus

C Language

4 min

Contents

Command-Line Arguments (argc and argv)

In C, command-line arguments are passed to main() through two parameters:

Code
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:

Code
./fib 10
Variable Value
argc 2
argv[0] "./fib"
argv[1] "10"

To ensure exactly one user-provided argument:

Code
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.

c
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.

c
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:

c
#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:

  1. Declaration: Tells the compiler that fib() exists and specifies its interface.
  2. Function call: main() calls fib(5).
  3. 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.

c
#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 .h files and implementations in .c files.

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:

Code
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:

Code
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" into 10 (number).
  • val stores 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.

Local graph 0 backlinks