Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Arrays in C Language

Tech May 10 3

Array Fundamentals

An array is a collection of elements of the same type stored in contiguous memory locations.

One-Dimensional Array Declaration

// General syntax for array declaration
element_type array_name[array_size];

The declaration requires three components:

  • element_type: the data type of each element
  • array_name: the identifier for the array
  • array_size: a constant expression specifying the number of elements
int values[10];
int data[3 + 2];  // constant expression allowed
char buffer[3];
float measurements[10];
double precision[4];

Varible-Length Arrays (C99 Feature)

Prior to C99, array dimensions had to be constants. C99 introduced variable-length arrays (VLAs), allowing runtime-specified sizes:

int n = 0;
scanf("%d", &n);
int dynamicArr[n];  // valid in C99, but cannot be initialized

Note: Visual Studio does not support VLAs regardless of C standard version.

One-Dimensional Array Initialization

Initialization occurs at declaration time:

int nums[10] = {1, 2, 3};              // partial initialization, rest are zero
int autoSize[] = {10, 20, 30, 40};     // size inferred from initializer
int zeroInit[5] = {0};                 // all elements set to zero
int complete[5] = {1, 2, 3, 4, 5};     // full initialization

char letters[3] = {'x', 97, 'z'};      // ASCII values work in char arrays
char word[] = {'a', 'b', 'c'};         // no null terminator
char text[] = "hello";                // includes '\0' automatically

Accessing and Modifying Array Elements

Elements are accessed via zero-based indices:

#include <stdio.h>

int main() {
    int data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int i = 0;
    
    for (i = 0; i < 10; i++) {
        printf("%d ", data[i]);
    }
    return 0;
}

Modifying elements through index assignment:

#include <stdio.h>

int main() {
    int data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int i = 0;
    
    // Reverse the array
    for (i = 0; i < 10; i++) {
        data[i] = 10 - i;
    }
    
    for (i = 0; i < 10; i++) {
        printf("%d ", data[i]);
    }
    return 0;
}

Calculating Array Size

#include <stdio.h>

int main() {
    int numbers[] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
    int count = sizeof(numbers) / sizeof(numbers[0]);
    
    printf("Total bytes: %zu\n", sizeof(numbers));
    printf("Element size: %zu\n", sizeof(numbers[0]));
    printf("Element count: %d\n", count);
    return 0;
}

For character arrays, sizeof and strlen behave differently:

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "x,y,z";
    
    printf("sizeof counts null terminator: %zu\n", sizeof(str));
    printf("strlen excludes null terminator: %zu\n", strlen(str));
    printf("Character count: %zu\n", sizeof(str) / sizeof(str[0]));
    return 0;
}

Key distinction: sizeof includes the null terminator, while strlen stops at it.

Memory Layout of One-Dimensional Arrays

Arrays occupy contiguous memory locations with addresses increasing sequentially:

#include <stdio.h>

int main() {
    int values[5] = {10, 20, 30, 40, 50};
    int length = sizeof(values) / sizeof(values[0]);
    int k = 0;
    
    for (k = 0; k < length; k++) {
        printf("values[%d] address: %p\n", k, (void*)&values[k]);
    }
    return 0;
}

Observation: addresses increase by 4 bytes (size of int) per element, confirming contiguous storage from low to high memory addresses.

Two-Dimensional Array Declaration

element_type array_name[row_size][column_size];
int matrix[3][4];
char grid[3][5];
double table[2][4];

Two-Dimensional Array Initialization

#include <stdio.h>

int main() {
    int a[3][4] = {1, 2, 3, 4};                    // fills row by row
    int b[3][4] = {{5, 6}, {7, 8}};                 // explicit row grouping
    int c[3][4] = {{1}, {2, 3}, {4, 5, 6}};        // partial row initialization
    int d[][4] = {{9, 8}, {7, 6}};                  // row dimension inferred
    
    return 0;
}

Important rule: when initializing 2D arrays, the row dimension may be omitted, but the column dimension is mandatory.

Accessing Two-Dimensional Array Elements

#include <stdio.h>

int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int row = 0;
    int col = 0;
    
    for (row = 0; row < 2; row++) {
        for (col = 0; col < 3; col++) {
            printf("matrix[%d][%d] = %d\n", row, col, matrix[row][col]);
        }
    }
    return 0;
}

Modifying elements via nested loops:

#include <stdio.h>

int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int row = 0;
    int col = 0;
    
    for (row = 0; row < 2; row++) {
        for (col = 0; col < 3; col++) {
            matrix[row][col] = row * 3 + col + 1;
        }
    }
    return 0;
}

Memory Layout of Two-Dimensional Arrays

2D arrays are stored as contiguous memory, effectively as an array of arrays:

#include <stdio.h>

int main() {
    int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int r = 0;
    int c = 0;
    
    for (r = 0; r < 2; r++) {
        for (c = 0; c < 3; c++) {
            printf("&grid[%d][%d] = %p\n", r, c, (void*)&grid[r][c]);
        }
    }
    return 0;
}

The notation grid[r] represents the r-th row as a 1D array, and grid[r][c] accesses the c-th element within that row.

Array Bounds

Array indices must remain within valid bounds. C does not perform automatic bounds checking:

int arr[5] = {1, 2, 3, 4, 5};
// Valid indices: 0, 1, 2, 3, 4
// arr[5] and arr[-1] are out of bounds but may not trigger immediate errors

Accessing indices below 0 or above size-1 constitutes undefined behavior.

Passing Arrays to Functions

When an array is passed to a function, it decays to a pointer. The array size information is lost:

#include <stdio.h>

void printArray(int arr[], int size) {
    int i = 0;
    for (i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

int main() {
    int data[5] = {1, 2, 3, 4, 5};
    printArray(data, 5);  // size must be passed separately
    return 0;
}

Bubble Sort Implementation

Bubble sort compares and swaps adjacent elements in multiple passes:

#include <stdio.h>

void bubbleSort(int arr[], int size) {
    int pass = 0;
    int j = 0;
    int temp = 0;
    
    for (pass = 0; pass < size - 1; pass++) {
        for (j = 0; j < size - 1 - pass; j++) {
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int numbers[10] = {64, 34, 25, 12, 22, 11, 90, 5, 72, 40};
    int idx = 0;
    int length = sizeof(numbers) / sizeof(numbers[0]);
    
    bubbleSort(numbers, length);
    
    for (idx = 0; idx < length; idx++) {
        printf("%d ", numbers[idx]);
    }
    return 0;
}

Understanding Array Names as Pointers

The array name evaluates to the adress of its first element in most contexts:

#include <stdio.h>

int main() {
    int data[5] = {10, 20, 30, 40, 50};
    
    printf("data points to: %p\n", (void*)data);
    printf("data + 1 points to: %p\n", (void*)(data + 1));
    printf("&data points to: %p\n", (void*)&data);
    printf("&data + 1 points to: %p\n", (void*)(&data + 1));
    printf("sizeof(data) = %zu bytes\n", sizeof(data));
    return 0;
}

Exceptions where array name represents the entire array:

  • sizeof(array_name) returns the total byte size
  • &array_name returns a pointer to the entire array

In all other contexts, the array name behaves as a pointer to its first element.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.