Back to C Programming
2026-07-126 min read

User-defined function

Learn User-defined function step by step with clear examples and exercises.

Why This Matters

In this tutorial, we will delve into the importance of user-defined functions (UDFs) in C programming, focusing on their relevance for coding interviews, real-world projects, and debugging common mistakes. We'll cover the prerequisites, core concept, worked examples, common pitfalls, practice questions, and frequently asked questions to help you master UDFs in C.

Prerequisites

Before diving into user-defined functions, you should have a solid understanding of:

  1. Basic C syntax: variables, data types, operators, and control structures (if-else, for, while)
  2. Arrays and pointers
  3. Functions provided by the standard library (such as printf, scanf)
  4. Understanding of recursion (optional but recommended)
  5. Familiarity with data structures like linked lists or trees (for advanced examples)

Core Concept

A user-defined function is a block of code that performs a specific task, which can be called multiple times throughout your program. To create a UDF in C, you define its prototype and implementation. The prototype declares the function's name, return type, and parameters, while the implementation provides the actual code to execute when the function is called.

// Function prototype
return_type function_name(parameters);

// Function implementation
return_type function_name(parameters) {
// Code to be executed when the function is called
}

Example: A UDF to calculate the factorial of a number

Let's create a user-defined function called factorial() that calculates the factorial of a given integer.

#include <stdio.h>

// Function prototype
long long int factorial(int n);

// Function implementation
long long int factorial(int n) {
if (n <= 1)
return 1;
else
return n * factorial(n - 1);
}

int main() {
int num;

printf("Enter a positive integer: ");
scanf("%d", &num);

printf("Factorial of %d is %lld\n", num, factorial(num));

return 0;
}

In this example, we defined a user-defined function factorial() with an integer parameter n. The implementation uses recursion to calculate the factorial of the input number. In the main function, we call the factorial() function and pass an integer value as an argument.

Example: A UDF to reverse an array

Let's create another user-defined function called reverseArray(), which reverses the order of elements in an array.

#include <stdio.h>

// Function prototype
void reverseArray(int arr[], int length);

// Function implementation
void reverseArray(int arr[], int length) {
if (length <= 1)
return;

int temp = arr[0];
arr[0] = arr[length - 1];
arr[length - 1] = temp;

reverseArray(arr + 1, length - 1);
}

int main() {
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);

reverseArray(arr, n);

printf("\nReversed array: ");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);

return 0;
}

In this example, we defined a user-defined function reverseArray() that takes an array and its length as parameters. The implementation uses recursion to swap the first and last elements of the array and then calls itself with the updated subarray. In the main function, we create an array, calculate its size, print the original array, reverse it using the reverseArray() function, and print the reversed array.

Worked Example

Let's create a user-defined function called isPrime() that checks whether a given number is prime or not.

#include <stdio.h>

// Function prototype
int isPrime(int num);

// Function implementation
int isPrime(int num) {
if (num <= 1)
return 0; // Not prime

for (int i = 2; i * i <= num; i++) {
if (num % i == 0)
return 0; // Not prime
}

return 1; // Prime
}

int main() {
int num;

printf("Enter a number: ");
scanf("%d", &num);

if (isPrime(num))
printf("%d is a prime number.\n", num);
else
printf("%d is not a prime number.\n", num);

return 0;
}

In this example, we defined a user-defined function isPrime() that checks if the input number is prime by iterating through all numbers up to its square root and checking for divisibility. In the main function, we call the isPrime() function with an integer value as an argument and print whether the number is prime or not.

Common Mistakes

  1. Forgetting to define the return type in the function prototype
  2. Not returning a value from the function when required (e.g., non-void functions)
  3. Using incorrect parameter types or numbers of parameters in the function call
  4. Not initializing local variables before using them
  5. Failing to handle edge cases properly, such as negative numbers or empty arrays
  6. Incorrectly implementing recursive functions, causing stack overflow or infinite loops
  7. Forgetting to include necessary header files (e.g., stdio.h for printf, scanf)
  8. Not properly managing memory when using dynamic memory allocation (e.g., malloc, free)
  9. Overlooking potential security vulnerabilities, such as buffer overflows or format string attacks
  10. Misusing pointers and arrays, leading to unexpected behavior or crashes

Practice Questions

  1. Write a user-defined function that calculates the sum of an array's elements.
  2. Create a UDF that checks if a given number is prime.
  3. Implement a function that finds the maximum and minimum values in an array.
  4. Write a function that sorts an array using bubble sort.
  5. Create a function that finds the Fibonacci sequence up to a given number.
  6. Write a UDF to find the greatest common divisor (GCD) of two numbers.
  7. Implement a function that calculates the factorial of a number using an iterative approach instead of recursion.
  8. Create a function that finds all prime numbers in a given range.
  9. Write a UDF to find the smallest multiple of a number that is greater than another number.
  10. Implement a function that checks if a given string is a palindrome (reads the same forwards and backwards).

FAQ

Why should I use user-defined functions?

User-defined functions help make your code more modular, readable, and efficient by allowing you to create reusable blocks of code that can be called multiple times with different inputs. They also improve maintainability as changes to a function only need to be made in one place.

How do I handle variable numbers of arguments in a user-defined function?

To handle variable numbers of arguments, you can use the va_list and varargs macros provided by C's standard library. This is known as variadic functions.

Can I pass arrays to user-defined functions by value or by reference?

In C, arrays are passed by reference, meaning that changes made within the function will persist in the calling function. However, if you want to explicitly pass an array by value, you can create a struct containing the array and its size, then pass the struct as a parameter.

How do I return multiple values from a user-defined function?

To return multiple values from a function, you can use a struct or an array of structs (also known as a record in some contexts). You can then populate the struct within the function and return it by value. Alternatively, you can create multiple output parameters using the * operator.

How do I manage memory when using dynamic memory allocation in user-defined functions?

When using dynamic memory allocation (e.g., malloc, calloc, realloc) within a UDF, it's important to remember to check for null pointers before attempting to allocate or deallocate memory. Additionally, if the function returns a dynamically allocated memory block, ensure that the caller frees the memory when it is no longer needed.

How do I avoid potential security vulnerabilities in user-defined functions?

To avoid potential security vulnerabilities, such as buffer overflows or format string attacks, always validate and sanitize input data before using it within your UDFs. Additionally, be mindful of how you handle memory allocation and deallocation to prevent memory leaks or double free errors.

How do I test user-defined functions effectively?

To test user-defined functions effectively, create a series of unit tests that exercise different scenarios and edge cases. This can help ensure that your functions are robust and function as intended. Additionally, consider using tools like Valgrind to detect memory leaks or other potential issues.