Problem Solving: Array and Functions

Learn to write programs using arrays and functions, with a focus on reusability.

We have seen that we may sometimes need to perform a similar kind of work repeatedly. For that, we used functions as a remedy to avoid the redundancies of the code.

Similarly, we may need to perform similar work on arrays of different sizes. How can we avoid re-writing the same or similar code?

Yes! Using functions is the answer.

Let us see how arrays can be passed as arguments into a function and how a function can use arrays as parameters in a generalized manner.

Arrays and functions

Arrays, in general, can be of different sizes; if we write a function that works on a specific size of the input, it would be problematic regarding reusability and scalability.

For example, if we want to write a function printArray() that prints the array (let’s say of size = 10) and then later, we need to print a different-sized array, (say of size = 15), the above function will be useless if it only works for size = 10.

This is one of the core reasons why arrays are not physically passed to functions. Instead, what we pass is the base address of the array and, along with that, we pass a second parameter to the function that is the size of the array; the size will dictate the function as to how much memory, from the base address onwards, the function needs to access. Look at the following example.

#include <iostream>
using namespace std;

// This function prints the array of any size, it expects the array
// (actually - the base address of array and the maximum size of 
// the array).
void printArray(int Base[], int size)
{               // Base will be set to the address 
                // of the first memory location of any array passed here, 
                // 2nd parameter is the size dictating how much
                // as offset of Base one can access i.e. Base[0...size-1]
    cout << "{";
    for(int i=0; i<size; i++) // offset i will iterate from 0 ... size-1
    {
        cout << Base[i];
        if(i!=size-1)    // this check is to follow this format
            cout <<",";  // {1,2,3} after the last element there shd
    }                    // be no comma ','
    cout << "}";
}

int main()
{
    const int capacity=100;
    int A[capacity]={};
    int size;
    cout<<"Size: ";
    cin>>size;  // Use only size many entries... the rest will be wasted
    cout<<"Enter "<<size<<" values: ";
    for(int i=0; i<size; i++)
        cin>>A[i];
        
    printArray(A, size);
    
    return 0;
}




Printing the array using the printArray(int Base[], int size) function

  • Line 7–20: we have a function declaration called printArray() that has two parameters, int Base[] and int size. Here, in the function definition, we’ve included the square brackets (without any mention of size in the array declaration as a parameter). These brackets notify the compiler that the array being passed is a one-dimensional array. The loop iterates through offset i=0 to size-1, hence accessing Base[0] to Base[size-1].

  • Line 33: When we are calling the function, we only pass the name of the array as an argument (remember, the name of the array is equivalent to the base address of the array that is the address of the first memory location), along with the size (how much of the array should be processed).

Arrays passed by reference, value, or something else?

In the above program, we are taking input from the user (through the console); the input should be taken inside the function. Why? Think about this for a while.

This loading data (in an array) step should be performed by the function because this initialization can be needed anywhere, and we do not want to rewrite the same code.

For writing the initArray() function, we need to again pass an array (note that we are not actually passing an array but the base address of the array) and the size of the array. Here is the prototype of the function:

void initArray(int Base[], int &size)

On receiving the parameter list, int Base[] is a way to declare a receiving variable for the base address passed as an argument.

Remember, when variables are passed by reference, it gives the effect that the variable from the called position is actually passed. Here on the receiving end, the same memory/variable has been given a new alias and accessing or changing it means that we are actually accessing the original argument passed to the function.

So basically, when the array is passed to a function, a copy of the base address is made and passed by value to the corresponding parameter.

When an array is passed to a function, the function receives the address of the array’s first element in memory. When the function accesses the array using an offset, such as Base[0] or Base[1], it is actually accessing the original memory of the array. This can give the impression that the memory has been passed by reference, although, technically, only the address of the array has been passed. Some literature may refer to arrays as being passed by reference, but it is more accurate to say that the base address of the array is passed to the function.


Hence, from now onwards, we will simply say that the array is being passed (instead of calling it the base address and explaining the reasoning behind it again and again) and we are accessing/changing the original array, as passed in the argument.

Instruction: Take a look at the following code and modify the playground above with this function and its call in the main.

Press + to interact
.
.
.
void initArray(int Base[], int &size)
{
cout<<"Size: ";
cin>>size; // Use only size many entries... the rest will be wasted
cout<<"Enter "<<size<<" values: ";
for(int i=0; i<size; i++)
cin>>Base[i];
}
int main()
{
const int capacity=100;
int A[capacity]={};
int size;
initArray(A, size);
printArray(A, size);
return 0;
}

Passing an element of an array to a function

To pass certain elements of an array, we can easily pass them like we pass variables. For example, we have the following:

Press + to interact
// function definition
void printElement(int val1, int val2)
{
cout << "First element " << val1 << endl;
cout << "Second element " << val2 << endl;
}

The function can then be called like this:

Press + to interact
int A[5]={10,20,30,40,50};
printElement(A[0], A[1]); // this will print 10 and 20
printElement(A[1], A[3]); // this will print 20 and 40

Keep in mind that whenever we are accessing the arrayName[i], it does not mean we are accessing the entire array, but rather the ith element of the array. Hence, on the parameter list of the function, the data type must be the data type of an element of the array because we are receiving just one element.

Take a look at the following example and carefully understand the output of every instruction:


#include <iostream>
using namespace std;

void printArray( int Base[], int size)
{
    cout << "{ ";
    for(int i=0; i<size; i++)
    {
        cout << Base[i]<<" "<<flush;
    }
    cout << "}"<<endl;
}

// Print: It first receive the Msg followed by the array and size
void printArray( const char Msg[], int Base[], int size)
{
    cout << Msg << " { ";  // Msg will be printed till the '\0'
    for(int i=0; i<size; i++)
    {
        cout << Base[i]<<" ";
    }
    cout << "}";
}
// Passing to function
void printArrayElement(int a_value)
{
    cout << "One value received is:" << a_value << endl;
}

// Passing to function
void printArrayElements(int a_value, int b_value)
{
    cout << "The first value received is:"  << a_value << endl;
    cout << "The second value received is:" << b_value << endl;
}

// receiving an int memory by refernce
void modifyElement(int &a_value)
{
    a_value+=10;
}

// Passing to function
void modifyElements(int &a_value, int &b_value)
{
    a_value+=5;
    b_value+=10;
}

int main()
{
    int A[] = {2, 7, 8 ,9}, size=4;
    
    cout<<"The address of A is: "<<A<<endl;
    printArray(A, size);    
    cout << endl;
    printArray( "A:", A , 4);  // means: ({'A', ':', '\0'}, 0x7f110, 4) is passed
    cout << endl;
    
    // Printing any individual array element based on the index    
    printArrayElement(A[0]); 
    printArrayElement(A[1]); 
    printArrayElement(A[2]); 
    cout << "The Entire array using loop: {";
    for(int i=0; i<size; i++)
        cout << A[i] << " ";
    cout << "}"<<endl;
    // Printing two elements     
    printArrayElements(A[0],A[2]); 
    cout << endl;
    
    modifyElement(A[0]);
    modifyElement(A[0]);
    modifyElement(A[1]);
    printArray("The updated array is:",A, size);
               // "The updated array is:" is a null ternimated cstring
               // passed as a character array.

    // Exercise: Call for modify elements and update the A[0] by adding 5 and
    // A[3] by adding 10. Add the required call by calling 
    // modifyElements with indices A[0] and A[3] as arguments and 
    // see the effect on the output.

    // modify______(____, ____);  // complete the code
    // print_______(_____, ____, _____)

    
    return 0;
}

Array elements

Exercise 1: Dry runworking through each line of code manually to trace the value of variables or expressions the code, look at all the value changes happening inside the array, and understand each and every output of the program. You should look at the slides below and go through each line and specifically look at the directions which are guided by the slides.

Exercise 2: Call functions for modifying the elements and update the A[0] by adding 5 and A[3] by adding 10. Add the required call by calling modifyElements() with indexes A[0] and A[3] as arguments and see the effect on the output.

    // complete the code
    modify______(____, ____);  
    print_______(_____, ____, _____)