Chapter 01

Introduction, Data Structures & Arrays

This chapter builds the first foundations of the course: what data and information are, why we organise data with data structures, and a close look at the simplest linear data structure, the array, including how array elements are addressed in memory for both 1D and 2D arrays. (Course logistics — syllabus, textbook, assessment, and timetable — are on the home page.)

1.2Data and Information

Definition · Data Any fact that can be recorded or stored. Examples: a number, image, video, audio.
Definition · Information Processed data — data with meaning added to it. Example: "5 years" (the unit turns the raw number 5 into information).

1.3Organising Information: Field, Record, File

Information is organised hierarchically:

LevelMeaningExample
FieldA single element of informationAge
RecordA collection of field valuesAn employee of a company (name, age, dept.)
FileA collection of recordsAll the employees of a company

1.4What is a Data Structure?

Files can be very large, and we need to perform many operations on them efficiently:

  • Insertion
  • Deletion
  • Updation
  • Searching
  • Viewing (traversing)
  • Queries such as finding the employee with the maximum salary
  • Many more…

Doing these efficiently requires organising the data in computer memory in a deliberate way — that organisation is the data structure.

Definition · Data structure A data structure refers to the way of organising and storing data in computer memory following some logical or mathematical model.

Where does a data structure live?

In this definition, computer memory normally means main memory (RAM) while a program is running. For example, when Python executes A = [10, 20, 30, 40], the list and the information needed to manage it exist in the program's memory, backed primarily by RAM.

When the program endsThe linked list normally disappears from memory.
What remainsThe saved students.txt file stays on the SSD/HDD.
Fig 1.1 · Persistent data is read from secondary storage into RAM, where a running program can organise and process it as a data structure.
In short RAM is the program's temporary working area; an SSD or HDD keeps files for later use. To preserve changes made to an in-memory data structure, the program must write or save them back to persistent storage.

Classification

CategoryExamples
SequentialArray
Non-sequentialLinked lists
HierarchicalTrees, Heaps
GraphicalGraphs

1.5Why Data Structures Matter

The choice of data structure decides how fast each operation can be. The same four operations cost very differently across structures:

OperationInsertSearchFind MinDelete Min
Unsorted arrayO(1)O(n)O(n)O(n)
Sorted arrayO(n)O(log n)O(1)O(n)
Linked listO(1)O(n)O(n)O(n)
Min heapO(log n)O(n)O(1)O(log n)

No single structure wins everywhere — each trades speed in one operation for speed in another, which is why we study many of them.

1.6Arrays

The array is the simplest linear data structure. It is:

  • Stored in a contiguous block of memory,
  • Made of elements of the same data type, and
  • Supports random access — any element can be reached directly by its index.
int arr[5] = {10, 20, 30, 40, 50};
Contiguous memory, step by step

Ready to place the five integers in contiguous memory.

10 20 30 40 50 index 0 index 1 index 2 index 3 index 4 1000 1004 1008 1012 1016 int arr[5] = {10, 20, 30, 40, 50}; one contiguous block · each int = 4 bytes · address of arr[i] = 1000 + 4 × i
Fig 1.2 · The array from the code above, laid out in memory: five ints in one contiguous block. With base address 1000 and 4 bytes per int, arr[i] sits at 1000 + 4 × i — index 3 → 1012.

1.7Array Indexing (Offset or Position)

For int arr[5] = {10, 20, 30, 40, 50}; there are two indexing conventions:

0-based indexing — most common in programming languages

Value1020304050
Index01234

1-based indexing — used only in theory

Value1020304050
Index12345

1.8Array Operations

Traversal — iterating through elements

for (int i = 0; i < n; i++) {
    printf("%d ", A[i]);
}

Insertion — adding an element at a specific index

A[index] = 5;

Deletion — removing an element at a specific index (requires shifting)

for (int i = index; i < n - 1; i++) {
    A[i] = A[i + 1];
}
n--;
Worked example — insert 25 at index 2 (making room)shifts: 3
Before:            [10, 20, 30, 40, 50]        n = 5
Shift right from the end:
  A[5] = A[4] →    [10, 20, 30, 40, 50, 50]
  A[4] = A[3] →    [10, 20, 30, 40, 40, 50]
  A[3] = A[2] →    [10, 20, 30, 30, 40, 50]
Place:  A[2] = 25 →[10, 20, 25, 30, 40, 50]    n = 6

Inserting in the middle needs every element from the index onward shifted right — here 3 shifts. Inserting at the front of an n-element array costs n shifts; inserting at the end costs none.

Worked example — delete the element at index 1shifts: 3
Before:            [10, 20, 30, 40, 50]        n = 5
  A[1] = A[2] →    [10, 30, 30, 40, 50]
  A[2] = A[3] →    [10, 30, 40, 40, 50]
  A[3] = A[4] →    [10, 30, 40, 50, 50]
Shrink: n-- →      [10, 30, 40, 50]             n = 4

Deletion closes the gap by shifting everything after the index one place left; the last slot becomes stale and n shrinks. Like insertion, the cost depends on the position — worst at the front, free at the end.

Step by step: insertion and deletion
Use the exact worked examples above and watch each required shift happen one position at a time.

Search — finding an element

Linear search or binary search (binary search needs the array to be sorted).

Update — modifying an element

Assign a new value at the given index, e.g. A[index] = new_value;

1.9Strengths and Limitations

StrengthsLimitations
Fast access to elements via index Fixed size — resizing requires creating a new array
Easy to implement and use Costly insertions and deletions (due to shifting)

1.10Array Addressing

Because arrays are contiguous, the memory address of any element can be computed directly from its index.

0-based indexing Address of the element at index i = Base_address + data_size × i
1-based indexing Address of the element at index i = Base_address + data_size × (i − 1)
Example — 0-based, int array

An int array (4 bytes each) starts at base address 2000. What is the address of arr[7]?

show answer
Ans: 2028

Address = 2000 + 4 × 7 = 2028.

Example — 1-based, char array

A char array (1 byte each) starts at base address 500. What is the address of arr[9]?

show answer
Ans: 508

Address = 500 + 1 × (9 − 1) = 508. Note the (i − 1): in 1-based indexing the first element sits at the base address itself.

address_array.c
#include <stdio.h>

int main(void) {
    int arr[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i < 5; i++) {
        printf("&arr[%d] = %p\n", i, (void *)&arr[i]);
    }
    return 0;
}
Terminal output

Ready to compile and run.

Fig 1.3 · Run the program: printing &arr[i] for an int array shows consecutive addresses exactly 4 bytes apart, confirming the contiguous layout behind the addressing formula.

1.112-Dimensional (2D) Arrays

A 2D array is an array of arrays, representing data in rows and columns (matrix format). Elements are accessed using two indices — a row index and a column index, e.g. A[i][j].

int arr[3][4] = {
    {1,  2,  3,  4},
    {5,  6,  7,  8},
    {9, 10, 11, 12}
};

1.122D Arrays: Memory Representation

Memory is one-dimensional, so a 3 × 4 matrix must be flattened into a line. Two conventions exist:

OrderIdeaLayout of the 3 × 4 example
Row-major Elements of a row are stored sequentially 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
Column-major Elements of a column are stored sequentially 1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12

1.132D Array Addressing (0-based)

Row-major order Address = Base Address + ((i × Number of Columns) + j) × Size of Data Type
Column-major order Address = Base Address + ((j × Number of Rows) + i) × Size of Data Type

Example: for the 3 × 4 array above, the element arr[i=2][j=2] in row-major order sits at Base_address + ((2 × 4) + 2) × size.

Try it: 2D array addressing explorer
The 3 × 4 array from above (0-based indices). Click any cell, pick the storage order and element size, and watch the address formula compute itself — the memory strip below shows exactly where that element lands.
base address = 100

1.14Worked Question

Question — 2D addressing with 1-based indices

A character array A[1…10][1…15] is stored in computer memory following row-major order. The base address of the array is 100. What is the address of the element A[i][j]?

show answer
Ans: 15i + j + 84

Solution: the array has 15 columns and indices start at 1, so Address = 100 + ((i − 1) × 15 + (j − 1)) × 1 = 100 + 15i − 15 + j − 1 = 15i + j + 84 (a char takes 1 byte, so the data size is 1).

One more — column-major, 0-based, int array

An int array A[0…9][0…14] (10 rows × 15 columns) is stored in column-major order with base address 5000. What is the address of A[3][5]?

show answer
Ans: 5212

Column-major: Address = 5000 + ((j × Rows) + i) × 4 = 5000 + ((5 × 10) + 3) × 4 = 5000 + 53 × 4 = 5212. Verify it yourself in the explorer above by switching the order to column-major.

Try these yourselfpractice
  • For the same array A[1…10][1…15] of chars (base 100), derive the address formula in column-major order and simplify it like the worked question.
  • An int array B[0…7][0…7] starts at base 4000. Find the address of B[6][2] in both row-major and column-major order — and explain why only the diagonal elements get the same address in both.
  • If a 1D char array’s element arr[12] (0-based) lives at address 712, what is the base address?

1.15Observations: Why "Same Data Type"?

Section 1.6 said an array holds elements of the same data type. What actually happens if we cheat? Two experiments from the lecture:

Experiment 1 — a char and a float in an int array

int arr[5] = {1, 2, 3, 'A', 5.5};
printf("arr[3] is %d, and arr[4] is %d \n", arr[3], arr[4]);
printf("Char in arr[3] is %c", arr[3]);
coercion.c
#include <stdio.h>

int main(void) {
    int arr[5] = {1, 2, 3, 'A', 5.5};

    printf("arr[3] as int  = %d\n", arr[3]);
    printf("arr[3] as char = %c\n", arr[3]);
    printf("arr[4]         = %d\n", arr[4]);
    return 0;
}
Compiler and program output

Ready to compile and run.

Fig 1.4 · Run the program: 'A' is stored as its ASCII code 65 (and still prints back as A with %c), while 5.5 is truncated to the int 5. The array stays all-ints — the values are coerced to fit.

Experiment 2 — a string in an int array

int arr[5] = {1, 2, 3, "hello", 5.5};   // ERROR?!
type_error.c
#include <stdio.h>

int main(void) {
    int arr[5] = {1, 2, 3, "hello", 5.5};
    printf("%d\n", arr[3]);
    return 0;
}
Compiler output

Ready to compile.

Fig 1.5 · Compile the program: a string is a char * pointer, and turning a pointer into an int is rejected ("makes integer from pointer without a cast"). Same-type storage is enforced, not just recommended.
Takeaway "Same data type" is what makes the addressing formulas of this chapter possible: every element occupies exactly the same number of bytes, so the position of element i is pure arithmetic.