Functions in the C and C ++ programming language
Programs in the c / c ++ programming language can have a large number of commands, and if they were written one after the other in a single file, developers would find it difficult to navigate in such a code, i.e. it would be difficult to maintain it. On the other hand, it often happens that one algorithm, part of the commands that solves a small or large problem inside an application, repeats itself many times. It can be concluded that it would be much better to extract this set of commands (part of the program) as one whole only once as a subroutine or function, and then call this function as necessary whenever necessary. Subprograms are a mechanism for breaking up complex problems into subproblems.
The programming language C knows only one type of routines called functions.
The programming language C knows only one type of routines called functions.
There are two things to distinguish about functions:
- Defining Functions
- Call functions
Defining Functions
Defining means that these commands that make up the function and who need to specify a specific task in an application (program) are written somewhere in the program, to sort them in some way, give a name and determine which data should be delivered to the function as input parameters and what kind of data the function returns back as a return value. So the definition of a function should include:
- Functions of the function
- function header
- body function
There are two words in the header of the method.
The first, in this case int, is a type of return data. This method, which counts a larger number between two integers, returns that integer type. This is the type of return value.
The second one is the name of the method that the programmer chooses himself and who should suggest the purpose of the method.
The body of the method is represented by curly braces. The body contains function commands.
In the header of the function (s), after the name, the parameters (arguments) of the function are written within ordinary brackets. These are the data to be delivered to the function so that it can complete the task set. In the previous example, the task that the function needs to perform is to determine the maximum between the two integers, and the data that the function needs to deliver through the parameter are the two numbers, in this case marked as a and b. The following figure shows more detailed this method.
The first, in this case int, is a type of return data. This method, which counts a larger number between two integers, returns that integer type. This is the type of return value.
The second one is the name of the method that the programmer chooses himself and who should suggest the purpose of the method.
The body of the method is represented by curly braces. The body contains function commands.
In the header of the function (s), after the name, the parameters (arguments) of the function are written within ordinary brackets. These are the data to be delivered to the function so that it can complete the task set. In the previous example, the task that the function needs to perform is to determine the maximum between the two integers, and the data that the function needs to deliver through the parameter are the two numbers, in this case marked as a and b. The following figure shows more detailed this method.
The function parameter can be no one or more. If the function does not require input data then the bracket in the header of the function will remain blank.
If the method does not return the value, it will not have the return statement in the body, but it can only have a return. In this case the word void is written as the type of return value.
The program must have at least one function and this is the main function. An example of the main function of the previous example is shown in the picture below.
If the method does not return the value, it will not have the return statement in the body, but it can only have a return. In this case the word void is written as the type of return value.
The program must have at least one function and this is the main function. An example of the main function of the previous example is shown in the picture below.
Within the main function, two integers are loaded first, and then the maximum is determined. Maximizing commands are isolated as a special method called max (see Figure 3). In the main function, use the cout command to print this value. At the point where the print data is expected, there is a call of the max function. Data as A and B are transmitted as parameters, in fact copies of these values. The max function determines a higher value and returns it back as a return value. This vegetable value will be printed along with the text "The larger number is" at the exit. After starting and setting the values eg 5 and 10 for A and B, the output will display:
Calling an functions in c or c++
The only feature that is automatically called, when starting the application is the main function. The commands in the main are executed from bottom to bottom and when the last command ends the program ends. If we have defined a function in the project, they will not be done by ourselves. In order for a program from the main to continue execution in another function, one of the commands in the main must be the call of another.
In the example in Figure 3, the max function is called:
cout<<"Greather number is "<<max(A,B);
The declaration calls methods, in general, it looks like:
name_of_function(parameter1,parameter2,....);
The parameters that are forwarded to the function are copied in order in the parameters defined in the defined method (see Figure 2). In the definition of a method, a data type is placed in front of the parameter name.
int max(int a, int b)
In fact, a new memory marked with a and b, which receives copies of the parameter values from the function call, is actually reserved:
max(A , B);
The call does not put the data type in front of the parameter.
Copying a parameter is shown in Figure 5.
In the example in Figure 3, the max function is called:
cout<<"Greather number is "<<max(A,B);
The declaration calls methods, in general, it looks like:
name_of_function(parameter1,parameter2,....);
The parameters that are forwarded to the function are copied in order in the parameters defined in the defined method (see Figure 2). In the definition of a method, a data type is placed in front of the parameter name.
int max(int a, int b)
In fact, a new memory marked with a and b, which receives copies of the parameter values from the function call, is actually reserved:
max(A , B);
The call does not put the data type in front of the parameter.
Copying a parameter is shown in Figure 5.
Function for determining the maximum of numbers a and b in c
Task: Create a function that determines the maximum of two integers that are passed as function parameters.
Enter two integers and determine their maximum using the previously defined function.
Enter two integers and determine their maximum using the previously defined function.
Forwarding a parameter by value and by reference
In the previous example, the parameter is forwarded by value. Since the parameters in the second function represent a new memory that obtains copies of the values from the memory of the main function only, any possible change in values within the other function will not affect the data defined in the first one.
This can be illustrated by the following example:
This can be illustrated by the following example:
Example 2: Replace data values
Set the integer value to 20, then make a method that changes this value to 100.
Let's create a function that will change the value of the data sent to:
Let's create a function that will change the value of the data sent to:
When we launch this program at the exit we get
We see that in the main function this value has not changed and if at first glance it seems that the code is all right.
This value is changed within the function change_vr, but this change does not reflect the data in the main function.
In order for this to be correct, the parameters must be transmitted by reference.
This value is changed within the function change_vr, but this change does not reflect the data in the main function.
In order for this to be correct, the parameters must be transmitted by reference.
Transfer function parameters by reference
Unlike transfer by value, when transferring by reference, no new memory is created for the parameters in the second "change_ref" function, but those parameters are actually references (another name) for the same memory occupied by the data parameters in the main function. This will cause changes to parameter values in the second function to be reflected in the first.
Let's modify the previous example by substituting a function that now passes parameters by reference. Parameters are now not actually data but pointers to that data.
For more on pointers, see the Pointers in C/C++ lesson.
The previous example now looks like Figure 9:
Parameters are now not data but data references. The previous example now looks like Figure 9
Let's modify the previous example by substituting a function that now passes parameters by reference. Parameters are now not actually data but pointers to that data.
For more on pointers, see the Pointers in C/C++ lesson.
The previous example now looks like Figure 9:
Parameters are now not data but data references. The previous example now looks like Figure 9
After starting, we get the output:
Transfer function parameters by pointer
Instead of references, pointers to data can also be used. The effect is similar to passing by reference, which means that changes made inside that function to data accessed via pointers will be reflected in the original data defined in the main function. This is because the pointers point to the original data, not to some new one, which just has the same value as the original.
For more on pointers, see the Pointers in C lesson.
The previous example now looks like Figure 10:
For more on pointers, see the Pointers in C lesson.
The previous example now looks like Figure 10:
After starting, we get the output:
Function declaration
Under the declaration of a data or function in programming it is called determining the identifier and describing the properties of the data or function, without allocating a memory space for storing data or function. In the case of a function, the type of function values and the number and types of arguments are determined. In general, the declaration looks like:
label_type function_name (array_argument);
The function declaration is also called the function prototype as well as the signature of the function.
If the function is located in the file above the main function, as in the previous examples then it is not necessary to specify the declaration separately. On the contrary, the declaration should be written above the main function. For example. the prototype of the max function would be:
int max (int a, int b); or only
int max (int, int);
The prototype of change_ref looks like:
void change_ref (int *);
label_type function_name (array_argument);
The function declaration is also called the function prototype as well as the signature of the function.
If the function is located in the file above the main function, as in the previous examples then it is not necessary to specify the declaration separately. On the contrary, the declaration should be written above the main function. For example. the prototype of the max function would be:
int max (int a, int b); or only
int max (int, int);
The prototype of change_ref looks like:
void change_ref (int *);
Advanced Topics for Experienced Users
1. How Arrays Interact with Functions
Arrays can be passed to functions in C and C++ in multiple ways, each with different implications for memory and functionality.
Passing Arrays by Pointer:
Arrays are typically passed to functions as pointers, allowing the function to access and modify the original array elements.
Example:
Passing Arrays by Pointer:
Arrays are typically passed to functions as pointers, allowing the function to access and modify the original array elements.
Example:
#include <iostream>
void modifyArray(int *arr, int size) {
for (int i = 0; i < size; ++i) {
arr[i] *= 2; // Modify original array
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
modifyArray(numbers, 5);
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
void modifyArray(int *arr, int size) {
for (int i = 0; i < size; ++i) {
arr[i] *= 2; // Modify original array
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
modifyArray(numbers, 5);
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
Key Point: Since the array decays into a pointer, its size must be explicitly passed as an argument.
Passing Arrays by Reference (C++ Only):
C++ supports passing entire arrays by reference, preserving their type and size.
Example
Example
void modifyArray(int (&arr)[5]) {
for (int &num : arr) {
num += 1;
}
}
for (int &num : arr) {
num += 1;
}
}
2. Difference Between Pointers and Arrays
While arrays and pointers are closely related in C and C++, they are not the same. Understanding the distinction is crucial.
Aspect | Pointers | Arrays |
---|---|---|
Definition | A variable that stores the memory address of another variable. | A collection of elements stored in contiguous memory locations. |
Memory Allocation | Memory is dynamically allocated using functions like malloc or new . |
Memory is statically or dynamically allocated when the array is defined. |
Flexibility | Can point to any data type or dynamically allocated memory. | Fixed size; cannot resize after declaration. |
Arithmetic Operations | Pointer arithmetic is possible (e.g., ptr + 1 ). |
Direct arithmetic operations are not allowed. |
Passing to Functions | Can pass the pointer directly to access or modify data. | Passed as a pointer to the first element of the array. |
Relation | Can be used to iterate through or manipulate arrays. | An array's name acts as a pointer to its first element. |
Null Handling | A pointer can be assigned NULL . |
An array name cannot be null. |
Modification of Base Address | The base address can be changed to point to another memory location. | The base address of an array is constant and cannot be modified. |
Example of Confusion:
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
// Access is similar:
std::cout << arr[0] << " " << ptr[0] << std::endl;
// But operations differ:
std::cout << sizeof(arr) << " " << sizeof(ptr) << std::endl; // Outputs: 20 8
int *ptr = arr;
// Access is similar:
std::cout << arr[0] << " " << ptr[0] << std::endl;
// But operations differ:
std::cout << sizeof(arr) << " " << sizeof(ptr) << std::endl; // Outputs: 20 8
3. Working with Constant Arrays
Using the const keyword enhances safety and clarity when working with arrays.
Read-Only Arrays:
Declaring an array or pointer as const prevents modification of its elements.
Example
Read-Only Arrays:
Declaring an array or pointer as const prevents modification of its elements.
Example
void printArray(const int *arr, int size) {
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
}
int main() {
const int numbers[] = {1, 2, 3, 4, 5};
printArray(numbers, 5);
return 0;
}
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
}
int main() {
const int numbers[] = {1, 2, 3, 4, 5};
printArray(numbers, 5);
return 0;
}
Constant Arrays with References:
In C++, arrays can also be passed as const references to prevent copying and modification:
void printArray(const int (&arr)[5]) {
for (int num : arr) {
std::cout << num << " ";
}
}
for (int num : arr) {
std::cout << num << " ";
}
}
Pointers to Const vs. Const Pointers:
- const int *ptr: Pointer to a constant integer (value cannot change, pointer can).
- int *const ptr: Constant pointer to an integer (pointer cannot change, value can).
Conclusion
Including these advanced topics can deepen the understanding of arrays for experienced users, helping them write safer, more efficient, and modern code. This section will also bridge knowledge gaps for those transitioning between C and C++ or seeking to master best practices.
Differences in Defining and Using Functions in C and C++ Languages
1. Member Functions
In C++, functions can be defined as members of classes, allowing them to operate on data specific to an instance of the class (methods). This supports object-oriented programming, which is not available in C.
2. Function Overloading
C++ allows function overloading (the same name for multiple functions with different parameters), whereas C requires unique names for every function.
3. Standard Library
C++ includes an extended standard library with functions for objects, strings, and collections, while C focuses on procedural functions.
In C++, functions can be defined as members of classes, allowing them to operate on data specific to an instance of the class (methods). This supports object-oriented programming, which is not available in C.
2. Function Overloading
C++ allows function overloading (the same name for multiple functions with different parameters), whereas C requires unique names for every function.
3. Standard Library
C++ includes an extended standard library with functions for objects, strings, and collections, while C focuses on procedural functions.
Detailed Explanation of Parameter Passing in C and C++
In C and C++, the way parameters are passed to functions significantly impacts performance and behavior. There are three main methods: pass-by-value, pass-by-reference, and pass-by-pointer.
1. Pass-by-ValueWhen parameters are passed by value:
1. Pass-by-ValueWhen parameters are passed by value:
- The function gets a copy of the original data.
- Changes made within the function do not affect the original variables in the caller.
- Advantages: Data safety, as the original variables remain unaffected.
- Disadvantages: Higher memory and CPU usage for large data structures.
Example:
void increment(int x) {
x++; // Modifies the copy, not the original variable
}
int main() {
int a = 5;
increment(a);
// a remains 5
return 0;
}
x++; // Modifies the copy, not the original variable
}
int main() {
int a = 5;
increment(a);
// a remains 5
return 0;
}
2. Pass-by-ReferenceWhen parameters are passed by reference:
- The function gets a reference to the original data.
- Changes made inside the function directly affect the original variable.
- Advantages: Efficient for large data, no copying required.
- Disadvantages: Can unintentionally modify original data, requiring careful handling.
Example:
void increment(int &x) {
x++; // Modifies the original variable
}
int main() {
int a = 5;
increment(a);
// a is now 6
return 0;
}
x++; // Modifies the original variable
}
int main() {
int a = 5;
increment(a);
// a is now 6
return 0;
}
3. Pass-by-PointerWhen parameters are passed by pointer:
- The function gets a memory address (pointer) of the original data.
- Useful for working with dynamically allocated memory or arrays.
- Advantages: Allows direct manipulation of original data with additional flexibility.
- Disadvantages: Requires more careful management to avoid null pointers or segmentation faults.
Example:
void increment(int *x) {
(*x)++; // Dereference the pointer to modify the original variable
}
int main() {
int a = 5;
increment(&a); // Pass the address of the variable
// a is now 6
return 0;
}
(*x)++; // Dereference the pointer to modify the original variable
}
int main() {
int a = 5;
increment(&a); // Pass the address of the variable
// a is now 6
return 0;
}
Performance Considerations
Pass-by-Value: Safer but can be slower for large objects or arrays due to copying.
Pass-by-Reference and Pass-by-Pointer: Faster as no copying occurs, but more prone to errors like unintended modifications or dangling references.
Pass-by-Reference and Pass-by-Pointer: Faster as no copying occurs, but more prone to errors like unintended modifications or dangling references.
Advanced Topics to Explore
To enrich the understanding of parameter passing, consider including:
- Const References: Use of const with references or pointers to prevent modification of the original data.
- R-value References: Used in modern C++ (from C++11 onwards) for temporary object optimization.
- Move Semantics: Ensures efficient resource management for temporary objects.
Example: Modularization and Libraries in C++
Below is an example demonstrating how functions can be used for modularizing code and creating custom libraries. It includes separate files for a custom library (math_utils) and a main program that uses it.
Step 1: Create the Custom Library
File: math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
// Function prototypes
int add(int a, int b);
int subtract(int a, int b);
#endif
#define MATH_UTILS_H
// Function prototypes
int add(int a, int b);
int subtract(int a, int b);
#endif
File: math_utils.cpp
#include "math_utils.h"
// Function definitions
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
// Function definitions
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
Step 2: Create the Main Program
File: main.cpp
#include <iostream>
#include "math_utils.h"
int main() {
int x = 10, y = 5;
std::cout << "Addition of " << x << " and " << y << ": " << add(x, y) << std::endl;
std::cout << "Subtraction of " << x << " and " << y << ": " << subtract(x, y) << std::endl;
return 0;
}
#include "math_utils.h"
int main() {
int x = 10, y = 5;
std::cout << "Addition of " << x << " and " << y << ": " << add(x, y) << std::endl;
std::cout << "Subtraction of " << x << " and " << y << ": " << subtract(x, y) << std::endl;
return 0;
}
Step 3: Compile and Run
To compile and run the program:
g++ main.cpp math_utils.cpp -o modular_program
./modular_program
./modular_program
Output:
Addition of 10 and 5: 15
Subtraction of 10 and 5: 5
Subtraction of 10 and 5: 5
Explanation:
- Header File (math_utils.h): Contains function prototypes, allowing other files to include and use the functions.
- Implementation File (math_utils.cpp): Contains the actual implementation of the functions.
- Main Program (main.cpp): Uses the library functions by including the header file.
- Promotes code reuse by isolating functionality in reusable components.
- Simplifies maintenance, as changes to library code do not require modifications in the main program.
- Enables team collaboration, as multiple developers can work on different modules independently.
Extension
You can enhance this library by:
- Adding more utility functions (e.g., multiplication, division, trigonometric operations).
- Using namespaces to avoid name collisions.
- Compiling the library into a static (.a) or dynamic (.so/.dll) library for broader use in projects.
Advanced Examples: Exploring Functions with Pointers, Structures, and Classes
1. Using Pointers in Functions
Pointers are essential in C/C++ for passing large data structures efficiently or for enabling functions to modify variables in the calling function. Here's an example that demonstrates using pointers to swap two integers:
#include <iostream>
// Function to swap two numbers using pointers
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
// Calling swap function
swap(&x, &y);
std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
return 0;
}
// Function to swap two numbers using pointers
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
// Calling swap function
swap(&x, &y);
std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
return 0;
}
Explanation: The swap function uses pointers to directly modify the values of x and y in the main function, demonstrating efficient memory usage.
2. Passing Structures to Functions
Structures are commonly used for grouping related data, and functions can manipulate these structures effectively.
#include <iostream>
#include <string>
// Define a structure to hold student data
struct Student {
std::string name;
int age;
float grade;
};
// Function to display student details
void displayStudent(const Student& student) {
std::cout << "Student Name: " << student.name << std::endl;
std::cout << "Age: " << student.age << std::endl;
std::cout << "Grade: " << student.grade << std::endl;
}
int main() {
// Create a Student instance
Student s1 = {"Alice", 20, 89.5};
// Call the function to display details
displayStudent(s1);
return 0;
}
#include <string>
// Define a structure to hold student data
struct Student {
std::string name;
int age;
float grade;
};
// Function to display student details
void displayStudent(const Student& student) {
std::cout << "Student Name: " << student.name << std::endl;
std::cout << "Age: " << student.age << std::endl;
std::cout << "Grade: " << student.grade << std::endl;
}
int main() {
// Create a Student instance
Student s1 = {"Alice", 20, 89.5};
// Call the function to display details
displayStudent(s1);
return 0;
}
Explanation:
- The structure Student groups related data such as name, age, and grade.
- The function displayStudent takes a Student structure as a constant reference to avoid copying large data structures while ensuring that the function does not modify the structure's data.
- The main function demonstrates creating a structure instance and passing it to the function for processing.