Array, Structure, and Pointer in C++

Understanding Arrays in C++


Array is a collection of identically typed elements stored in consecutive memory locations. Arrays allow accessing any element directly using its index. They can store primitive types like int,float, double, char, and even derived types like pointers and structures.

All of the array's elements are arranged next to one another without any spaces between them since arrays are stored in memory as continuous blocks of memory. Because the memory location of any element can be immediately determined using a formula based on the base address and the size of each element, this arrangement enables effective access to array elements using their index.
For instance, the second element will be stored at 1004, the third at 1008, and so on if an integer array begins at memory location 1000 and each integer takes up 4 bytes. Because of their contiguous memory layout, arrays are quick and effective for accessing indexed data.

Example

#include <iostream>
using namespace std;

int main() {
    int num[3] = {1, 20, 3}; ← Declaration and initialization of a static array
    for(int i = 0; i < 3; i++) {
        cout << "Element: " << num[i] << endl;
    }
    return 0;
}

      

Note: In the above example, the array num is static because its size is fixed at compile time and cannot be changed during runtime.

This is a classification of C++ arrays according to various parameters, such as data type, dimensions, and memory allocation:

Based on Memory Allocation

Static Array

Arrays that have a predetermined size that is decided at compile time are called static arrays. This implies that the maximum number of elements that an array can contain must be defined prior to the program running and cannot be altered while it is running. The stack, a unique area of memory used for controlling function calls and local variables, is where the memory for static arrays is allocated. Static arrays provide effective performance due to their fast access times and automatic stack memory management. However, they lack flexibility and are unable to provide dynamic resizing based on runtime conditions because their size is defined and allocated at compile time. Because of this, static arrays are appropriate in scenarios where the data size is predetermined and stays that way while the application runs.
Example → int arr[5];

Dynamic Array

An array whose size is decided while the program is running, as opposed to when it is being compiled, is said to be dynamic. Dynamic arrays are appropriate for scenarios where the number of elements may change or is unknown in advance because of their flexibility, which enables the software to precisely allocate the amount of memory required based on runtime conditions.

Dynamic arrays are allocated on the heap, a section of memory used for dynamic memory management, in contrast to static arrays. The new operator, which reserves a block of memory of the required size on the heap and returns a reference to the first element, is commonly used in C++ for dynamic memory allocation. Heap memory must be explicitly deallocated using delete in order to prevent memory leaks because it is manually managed.

Example→Dynamic Array

#include <iostream>
using namespace std;

int main() {
    int element;
    cout << "Enter the number: "; // we can enter any number as array size
    cin >> element;
    int* num = new int[element];   // Create a dynamic array using new
    cout << "Enter " << element << " number:";
    for (int i = 0; i < element; i++) {
        cin >> num[i];
    }
    cout << "You entered: ";
    for (int i = 0; i < element; i++) {
        cout << num[i];
    }
    cout << endl;
    delete[] num; // Free the dynamically allocated memory
    return 0;
}

      

Note: In the above example, the array is dynamic, allowing its size to be determined and modified at runtime. It allocates memory on the heap using new and releases it with delete ketword.

Based on Dimensions

One-Dimensional Array

A list of elements of the same data type can be stored in a One-Dimensional Array, a straightforward, linear data structure. It displays a single row or line of values, each of which can be accessed by means of a distinct index.

Example → int arr[5] = {1, 2, 3, 4, 5};

Two-Dimensional Array

An array of arrays arranged in a matrix structure with rows and columns is called a two-dimensional array (2D array). It is frequently used to display tabular data in the form of a mathematical matrix, gaming board, or grid.

Example → int matrix[2][3] = {{1, 8, 3}, {4, 9, 6}};

Multi-Dimensional Array

A Multi-Dimensional Array in C++ extends beyond two dimensions to represent data in three or more dimensions. In essence, it is an array collection, with each array member being a multi-dimensional array. Higher-dimensional arrays take this idea a step further. For instance, a 3D array can be viewed as a group of 2D arrays layered on top of one another.

Example → int c[2][2][2];

Array Address Calculation in C++

Formula

Address = BA + W × (I - LB)

Where:
  • BA = Base Address
  • W = Width (size) of each element
  • I = Index
  • LB = Lower bound (usually 0)
Example →To find the address of a[1]

Given array: int a[3] = {1, 2, 3};
Address = BA + W × (I - LB)
Where BA = 1000 (base address), LB = 0 (lower bound), W = 4 (size of int), and I = 1 (index)

Address of a[1] = 1000 + 4 × (1 - 0) = 1004

In a two-dimensional array, elements can be stored in memory either by row-major or column-major order. In row-major order, all elements of a row are placed consecutively in memory, while in column-major order, all elements of a column are stored next to each other.

To calculate the address of a particular element in a 2D array, you need to consider the same factors as for a one-dimensional array, plus additional parameters: the lower bounds of the row (LR) and column (LC), as well as the total number of columns (N) in the array.

To find the address of a specific element in a two-dimensional array, we need to consider all the requirements listed for a single-dimensional array, along with the following additional values: LR (lower bound of the row), LC (lower bound of the column), and N (number of columns in the array).

Example →To find the address of a[1][1] using row-major order:

int letter[2][2] = {{'a', 'b'}, {'c', 'd'}};   // Given array
Address = BA + W × ((I - LR) × N + (J - LC))
Note → BA = 100, LR = 0, LC = 0, W = 1, I = 1, J = 1
Result = 100 + 1 × ((1 - 0) × 2 + (1 - 0)) = 104

Structure in C++

A structure in programming is a user-defined data type that enables you to combine variables of various types under a single name. Structures can bundle several related pieces of data, which can be of different types like integers, floats, characters, or even other structures, in contrast to simple variables that can only hold one piece of data. Because of this, structures are very helpful when it comes to representing complicated real-world items in a program.

To represent a student, for instance, you could combine their name (a string), age (an integer), and grade (a character) into a single structure named Student. This makes the code clearer and easier to handle in addition to keeping the relevant data organized.

In object-oriented programming, structures are comparable to classes because both act as data containers and have the ability to contain member functions (methods) for working with the data. However, classes in C++ integrate data and activity, while structures (in some languages, like C) generally just carry data and not functions. Nevertheless, just like classes, member functions can be a part of contemporary C++ structures.

In conclusion, structures offer a productive means of grouping and modifying related data, which enhances code readability and maintainability, particularly when working with intricate data models.

To declare a structure, use the struct keyword followed by the structure name and its member variables:

Example

#include <iostream>
#include <string>
using namespace std;

struct Person {
    string first_name;
    string last_name;
    int age;
    float salary;
};

int main() {
    Person p1;

    p1.first_name = "Yilma";
    p1.last_name = "Goshime";
    p1.age = 30;
    p1.salary = 5000.50;

    cout << "First Name: " << p1.first_name;
    cout << "Last Name: " << p1.last_name;
    cout << "Age: " << p1.age;
    cout << "Salary: $" << p1.salary;

    return 0;
}

      

Note: Memory is not allocated when a structure is defined. In essence, it creates a new data type by serving as a blueprint or template. Only when variables of that structure type are declared does memory get allocated. Once the structure has been defined, you can create structure variables in the same way that you would any other variable, and you can access or change the members of those structure variables using the dot operator (.)

Example

#include <iostream>
using namespace std;

struct Person {
    string name;
    int age;
};

int main() {
    Person p1;              // Object
    p1.name = "abebe";      // Initialization
    p1.age = 12;

    cout << "Name: " << p1.name << endl;
    cout << "Age: " << p1.age << endl;

    return 0;
}

      

Here, the Person structure is declared with two members. Inside main(), a structure variable p1 is created, its members are initialized with values, and then the information is displayed.

In C++, structures can also contain member functions, similar to classes:

Example

#include <iostream>
using namespace std;

struct Person {
    string name;
    int age;

    void display_info(string n, int a) {
        cout << "Name: " << n << endl;
        cout << "Age: " << a << endl;
    }
};

int main() {
    Person p1;               // Object
    p1.name = "abebe";       // Initialization
    p1.age = 12;
    p1.display_info(p1.name, p1.age);
    return 0;
}

      

In C++, structures can be passed to and returned from functions just like basic data types. This allows structured data to be manipulated more effectively within reusable functions. You can pass a structure variable to a function by value or by reference.

  • Passing by value: means a copy of the structure is made and used inside the function, so changes do not affect the original variable.
Example → Passing by Value

#include <iostream>
#include <string>
using namespace std;

struct Student {
    string name;
    int age;
};

void introduce(Student s) {   // Function that takes a Student structure by value
    cout << "Name: " << s.name << endl;
    cout << "Age: " << s.age << endl;
    s.age = 100;  // Modifying the copy inside the function
    cout << "Modified age inside function: " << s.age << endl;
}

int main() {
    Student s = {"Abebe", 25};
    introduce(s);
    cout << "Age after function call: " << s.age << endl;
    return 0;
}

      
  • Passing by reference is generally preferred for performance and to avoid copying large structures, as it allows the function to directly access and modify the original data.
Example → Passing by Reference

#include <iostream>
#include <string>
using namespace std;

struct Student {
    string name;
    int age;
};

void introduce(Student & s) {   // Function that takes a Student structure by reference
    cout << "Name: " << s.name << endl;
    cout << "Age: " << s.age << endl;
    s.age = 100;  // Modifying the original object inside the function
    cout << "Modified age inside function: " << s.age << endl;
}

int main() {
    Student s = {"Abebe", 25};
    introduce(s); // Function call
    cout << "Age after function call: " << s.age << endl;  // Now reflects the modified age
    return 0;
}

      

In the above example introduce function receives a copy of s because it is passed by value. and changes to s.age inside the function do not affect s in main(). This shows how pass-by-value protects the original data from modification.

So, the function parameter was changed from Student s to Student& s to enable pass-by-reference. This means any changes made inside the function directly affect the original structure

In C++, structures can include member functions, and one powerful feature is that these functions can return an object of the same structure type. This is especially useful when you want to perform operations that result in a new structure object such as copying, modifying, or combining values.

Pointer in C++

A pointer is a special variable that holds the memory address of another variable. Pointers can reference any data type, including primitive types like int and char, as well as more complex types such as arrays, classes, and structures.

A pointer is declared using the * symbol along with the data type it points to.
Declaration: data_type* name;

Here, data_type specifies the type of variable the pointer will point to. The asterisk (*) is used to declare a pointer and is also known as the dereference operator, which allows access to the value stored at the memory address held by the pointer.

Example: int* ptr; → declares ptr as a pointer to an integer. Pronounced as pointer to int.

In C++, once a pointer is declared, you can assign it the address of a variable using the address-of operator (&). This links the pointer to that variable’s memory location, allowing indirect access to its value.

Example:
int val = 22;
int* ptr = &val;

This assigns the address of val to the pointer ptr. In this case, the data type of the variable must match the type expected by the pointer. Otherwise, a type mismatch error will occur.

Example

#include <iostream>
using namespace std;

int main() {
    int var = 10;
    int* ptr = &var; // address of var is assigned to ptr
    cout << *ptr;     // will print 10
    return 0;
}

      

From the above example, accessing the value of a variable through a pointer is called dereferencing. Dereferencing a pointer means accessing or modifying the value stored at the memory address held by the pointer.

The size of a pointer that is how many bytes it uses in memory is not determined by the data type it points to, but by the architecture of the system.that means, On a 32-bit system, memory addresses are 32 bits (4 bytes), so pointers are 4 bytes. On a 64-bit system, memory addresses are 64 bits (8 bytes), so pointers are 8 bytes. This applies to all pointer types, whether it’s an int*, char*, or struct*, they all occupy the same size on a given system, because they all store memory addresses.

Types of Pointers in C++

Wild Pointer

A declared pointer that has not been initialized to point to a legitimate memory location. Using a wild pointer can cause crashes or data corruption because it contains a junk address.

Example → int* ptr;

NULL Pointer

A pointer initialized with NULL (or nullptr) to show it points to no valid memory. Always check if it is null before dereferencing.

Example → int* ptr = NULL;

Void Pointer

A generic pointer (void*) that can hold the address of any data type but cannot be dereferenced directly without typecasting.

Example → void* ptr;

Dangling Pointer

A pointer pointing to memory that has been deleted or freed. Using it causes undefined behavior.

Example →
int* ptr = new int(7);
delete ptr;

Valid Pointer Operations in C++

In C++, pointers are powerful tools for working with memory directly. The following are valid operations that can be performed on pointers:

Declaration and Initialization

You can declare a pointer and optionally assign it the address of a variable.

Example:
int x = 6;
int* ptr = &x; // ptr points to x

Dereferencing

Using the * operator to access the value stored at the memory location the pointer points to.

Example:
int a = 90;
int* ptr = &a;
cout << *ptr; // will display the value of a

Pointer Arithmetic

You can perform arithmetic operations such as increment (++), decrement (--), addition (+), and subtraction (-) on pointers, especially with arrays. The data type size affects pointer arithmetic.

Example:
int b[] = {1, 2};
int* p = b;
cout << *(p + 1); // Outputs: 2

Comparing Pointers

Use relational operators like ==, !=, <, and > to compare pointers to determine if they point to the same location or for iteration.

Example:
if (ptr == &x) {
cout << "ptr points to x";
}

Assigning Pointers

If two pointers are of the same type, you can assign one pointer to the other.

Example:
int* p1 = ptr; // Now p1 also points to x

Passing Pointers to Functions

Pointers can be passed to functions to allow direct modification of the original data.

Example:
int x = 30;
void sum(int* a) {
*a = 5;
}
sum(&x); // x becomes 5


Latest Posts


File Handling in Java.

File Handling in Java.

LetUsLearn May 28, 2025
Getting Started with Java GUI.

Getting Started with Java GUI.

LetUsLearn May 28, 2025

Categories

← Previous Post OOP in C++ Tutorial
Next Post → File Handling in C++
Yilma Goshime

I’m committed to providing tailored solutions and always ready to assist if any issue arises.

LetUsLearn
Back to Top