Array,Structure,and Pointer in C++


Illustration of pointer and array

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.

In memory, arrays are represented as continuous memory blocks. A 2D array is represented as adjacent blocks, while a 3D array is a collection of 2D arrays in continuous memory. In the case of Static Array,Memory is allocated at compile-time and Stored in the stack; size is fixed and cannot be changed during runtime.

Consider the following simple 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];
    }
    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.

In a dynamic array, the size can be modified at runtime using new, and memory is deallocated using delete. The array is stored in the heap

Take a look at the example below:

 
#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

Array Address Calculation in C++

For the case of a single-dimensional array, we need to consider the base address, the size (width) of each element in memory, the index for which we want to find the address, and the lower bound of the index.

Example: To find the address of a[1]

int a[1] = {1, 2, 3}; ← Given array
Address = BA + W × (I - LB) Note → BA = 1000, LB = 0, W = 4, I = 2
Result: 1000 + 4 × (1 - 0) = 1004

In a two-dimensional array, elements can be arranged in memory using either row-major order or column-major order. In row-major order, the elements of each row are stored in contiguous memory locations. In column-major order, the elements of each column are stored in contiguous memory locations.

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,LC = 0, W = 1, I,J = 1
Result = 100+1 x ((1 - 0) x 2 + (1 - 0)) =104

There are two main types of arrays based on their dimensions:

  1. Single-Dimensional Array: stores elements in a linear sequence. Each element is identified by a single index, which represents its position in the sequence.
    • Syntax:data_type array_name[array_size];
    • Initialization:char letters[4] = {'a', 'b', 'c'};
  2. Multi-Dimensional Array: extends the concept of linear arrays to multiple dimensions, commonly two-dimensional arrays that can be visualized as tables or matrices consisting of rows and columns, or even three-dimensional arrays representing data in layers.
    • 2D Array Syntax:data_type array_name[size1][size2];
    • 2D array intialization :int m[2][2] = {{1, 2},{5, 6}};
    • 3D Array Syntax:data_type array_name[block][row][column];
    • 3D intialization :int c[2][2][2] = {{{1, 2},{5, 6}},{{1, 2},{5, 6}}};

Structure in c++

A structure is a user-defined data type that groups variables of different types, along with member functions, under a single name. It’s quite similar to a class both are containers for holding a mix of data types. However, structures are particularly useful when you want to organize related data efficiently.

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

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

Note: No memory is allocated when defining a structure. It serves as a blueprint essentially creating a new data type. After defining the structure, you can create structure variables just like any other variable and use the dot operator (.) to access or modify members of a structure variable:

Example:Sample Program Demonstrating Structures


#include <iostream>
using namespace std;
struct Person {
    string name;
    int age;
};
int main() {
    Person p1;   //object
    p1.name = "abebe"; //intialization
	p1.age = 12;
	cout<<"Name:"<<p1.name;
	cout<<"Name:"<<p1.age;
    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:


#include <iostream>
using namespace std;
struct Person {
    string name;
    int age;
    void display_info(string n,int a) {
    cout<<"Name:"<<n;
	cout<<"Name:"<<a;
    }
};
int main() {
    Person p1;  //Object
    p1.name = "abebe"; //intialization
	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.
  • 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 Value


#include <iostream>
#include <string>

struct Student {
    string name;
    int age;
};
void introduce(Student s) {   //Function that takes a Person structure by value
    cout << "Name: " << s.name;
    cout <<"Age: " << s.age;
    s.age = 100;  //Modifying the copy inside the function
    cout <<"Modified age inside function: " <<s.age;
}
int main() {
    Student s = {"Abebe", 25};
    introduce(s);
    cout << "Age after function call: " << s.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.

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;
    cout << "Age: " << s.age;
    s.age = 100;  ← Modifying the original object inside the function
    cout << "Modified age inside function: " << s.age;
}
int main() {
    Student s = {"Abebe", 25};
    introduce(s); //function call
    cout << "Age after function call: " << s.age;   //Now reflects the modified age
    return 0;
}

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.

Consider the following 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 pointer that has been declared but not initialized. Since it points to a random memory location, using it may cause unpredictable behavior or a segmentation fault.
    Example: int* ptr;
  • NULL Pointer: A pointer that explicitly points to nothing (no valid memory). It is used to indicate that the pointer does not currently point to any object.
    Example: int* ptr = NULL;
  • Void Pointer: A generic pointer that can point to any data type but cannot be dereferenced directly without casting.
    Example: void* ptr;
  • Dangling Pointer: A pointer that points to a memory location that has been freed or is no longer valid. Using dangling pointers can cause serious bugs or crashes.

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 : entails using the * operator to access the value that is stored at the memory location that the pointer points to.
    Example:int a = 90;
    int* a = &a;
    cout <<*a; ← will display the value of a
  • Pointer Arithmetic:we can perform arithmetic operations such as increment (++), decrement (--), addition (+), and subtraction (-) on pointers, especially with arrays.The size of the data type affects pointer arithmetic.
    Example: int b[] = {1,2};
    int* p = b;
    cout << *(p + 1); → Outputs: 2
  • Comparing Pointers: To determine whether two pointers point to the same place or to manage iteration, you can compare them using relational operators like ==,!=, <, and >.
    Example: if (ptr == &x) {
    cout << "ptr points to x";
    }
  • Assigning Pointers: If two pointers are of the same type, we can assign them to each 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 :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

Yilma Goshime

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

LetUsLearn