Chapter 6 of 23

Arrays and Strings

Master 1D and 2D arrays, array-to-pointer decay, std::array, C-strings, std::string methods, and type conversions — with a palindrome worked example.

Meritshot9 min read
C++ArraysStringsstd::stringstd::array
All C++ Chapters

Arrays in C++

An array is a fixed-size, contiguous block of memory that stores elements of the same type. Arrays are one of the most fundamental data structures in C++ and are the backbone of competitive programming problems on platforms like Codeforces, LeetCode, and HackerRank — all popular with students preparing for FAANG interviews in India.

Declaring and Initialising a 1D Array

int marks[5];                        // uninitialized — garbage values
int scores[5] = {90, 85, 78, 92, 88}; // fully initialised
int grades[5] = {70, 75};            // remaining elements set to 0
int zeros[5] = {};                   // all elements zero-initialised

Arrays in C++ are zero-indexed: the first element is at index 0, and the last is at index n - 1.

#include <iostream>
using namespace std;

int main() {
    int scores[5] = {90, 85, 78, 92, 88};

    // Access individual elements
    cout << "First score: " << scores[0] << endl;  // 90
    cout << "Last score:  " << scores[4] << endl;  // 88

    // Iterate with a for loop
    int total = 0;
    for (int i = 0; i < 5; i++) {
        total += scores[i];
    }
    cout << "Average: " << total / 5.0 << endl;    // 86.6

    return 0;
}

Range-Based For Loop (C++11)

C++11 introduced a cleaner way to iterate:

for (int score : scores) {
    cout << score << " ";
}

2D Arrays

A 2D array is essentially an array of arrays — useful for representing matrices, grids, and game boards.

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

// Access element at row 1, column 2
cout << matrix[1][2]; // 7

Traversing a 2D Array

#include <iostream>
using namespace std;

int main() {
    int grid[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    for (int row = 0; row < 3; row++) {
        for (int col = 0; col < 3; col++) {
            cout << grid[row][col] << "\t";
        }
        cout << "\n";
    }
    return 0;
}

Array Decay to Pointer

When you pass a C-style array to a function, it decays to a pointer to its first element. The size information is lost, which is why you must pass the size separately.

#include <iostream>
using namespace std;

void printArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << "\n";
}

int main() {
    int data[5] = {10, 20, 30, 40, 50};
    printArray(data, 5);   // 'data' decays to int*
    return 0;
}

This is a common source of bugs — always pair a raw array with its size.


std::array (C++11)

std::array is a safer, more expressive alternative to raw arrays. It lives in the <array> header and does not decay to a pointer, preserving its size at all times.

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

int main() {
    array<int, 5> scores = {90, 85, 78, 92, 88};

    cout << "Size: " << scores.size() << "\n";  // 5
    cout << "Front: " << scores.front() << "\n"; // 90
    cout << "Back:  " << scores.back()  << "\n"; // 88

    // Range-based for loop works perfectly
    for (int s : scores) {
        cout << s << " ";
    }
    return 0;
}

Raw Array vs std::array

FeatureRaw Arraystd::array
Size known at compile timeYesYes
Decays to pointerYesNo
.size() methodNoYes
Bounds checking (.at())NoYes
Pass to function without size paramNoYes
STL algorithm compatiblePartiallyFully

Prefer std::array over raw arrays in modern C++ whenever the size is fixed at compile time.


C-Strings (Character Arrays)

Before std::string existed, C++ (inheriting from C) used null-terminated character arrays to represent text.

char name[10] = "Priya";
// Stored as: {'P','r','i','y','a','\0', ?, ?, ?, ?}

The \0 (null character) marks the end of the string. Functions from <cstring> work with C-strings:

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

int main() {
    char city[20] = "Bengaluru";

    cout << strlen(city)  << "\n";   // 9

    char dest[20];
    strcpy(dest, city);              // copy
    strcat(dest, " City");           // concatenate
    cout << dest << "\n";            // Bengaluru City

    cout << strcmp("abc", "abc") << "\n"; // 0 (equal)
    return 0;
}

C-strings are error-prone because overflow is not automatically detected. Modern C++ strongly prefers std::string.


std::string

std::string is a full-featured string class from the <string> header. It manages its own memory, grows dynamically, and provides a rich set of methods.

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

int main() {
    string company = "Infosys";
    string city    = "Pune";
    string full    = company + " - " + city;  // concatenation with +

    cout << full << "\n";           // Infosys - Pune
    cout << full.length() << "\n";  // 15
    return 0;
}

Common std::string Methods

MethodWhat It DoesExample
.length() / .size()Number of characterss.length()
.substr(pos, len)Extract substrings.substr(0, 3)
.find(str)First occurrence indexs.find("abc")
.replace(pos, len, str)Replace portions.replace(0, 3, "xyz")
.append(str)Append to ends.append(" Ltd")
.compare(str)Lexicographic compares.compare("hello")
.empty()True if length is 0s.empty()
.clear()Remove all characterss.clear()
.at(i)Element with bounds checks.at(2)
s[i]Element without bounds checks[0]
#include <iostream>
#include <string>
using namespace std;

int main() {
    string email = "rohit.sharma@tcs.com";

    // find the @ symbol
    size_t atPos = email.find('@');
    cout << "Username: " << email.substr(0, atPos) << "\n"; // rohit.sharma
    cout << "Domain:   " << email.substr(atPos + 1) << "\n"; // tcs.com

    // replace domain
    email.replace(atPos + 1, string::npos, "infosys.com");
    cout << "Updated:  " << email << "\n"; // rohit.sharma@infosys.com

    return 0;
}

String-to-Number Conversions

C++11 added clean conversion functions in <string>:

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

int main() {
    // String to number
    string salaryStr = "1500000";
    int salary = stoi(salaryStr);           // string to int
    double rate  = stod("8.75");            // string to double
    long long big = stoll("9876543210");    // string to long long

    cout << salary + 100000 << "\n";        // 1600000

    // Number to string
    int ctc = 2000000;
    string ctcStr = to_string(ctc);
    cout << "CTC: Rs. " + ctcStr + "\n";    // CTC: Rs. 2000000

    return 0;
}

Conversion Functions at a Glance

FunctionConverts ToHeader
stoi(s)int<string>
stol(s)long<string>
stoll(s)long long<string>
stof(s)float<string>
stod(s)double<string>
to_string(n)std::string<string>

Worked Example: Reverse a String and Check Palindrome

A palindrome is a string that reads the same forwards and backwards — "madam", "racecar", "level". Palindrome checks appear frequently in competitive programming and tech interviews at companies like Google India, Amazon, and Microsoft.

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

// Reverse a string and return it
string reverseString(string s) {
    int left = 0, right = (int)s.length() - 1;
    while (left < right) {
        swap(s[left], s[right]);
        left++;
        right--;
    }
    return s;
}

// Check if a string is a palindrome (case-insensitive)
bool isPalindrome(string s) {
    // Convert to lowercase
    for (char& c : s) {
        c = tolower(c);
    }
    string rev = reverseString(s);
    return s == rev;
}

int main() {
    string words[] = {"Madam", "Racecar", "Meritshot", "Level", "OpenAI"};

    for (const string& word : words) {
        cout << word << " -> ";
        if (isPalindrome(word)) {
            cout << "Palindrome\n";
        } else {
            cout << "Not a palindrome (reversed: " << reverseString(word) << ")\n";
        }
    }

    return 0;
}

Output:

Madam -> Palindrome
Racecar -> Palindrome
Meritshot -> Not a palindrome (reversed: tohstireM)
Level -> Palindrome
OpenAI -> Not a palindrome (reversed: IAnepO)

Common Pitfalls

  • Off-by-one errors: The valid index range for an array of size n is 0 to n - 1. Accessing index n is undefined behaviour — your program might crash or silently corrupt data.
  • Array decay hides the size: Passing a raw array to a function loses size information. Prefer std::array or pass the size explicitly.
  • string::npos comparisons: find() returns string::npos (a very large number) when the substring is not found. Always compare the return value against string::npos before using it as an index.
  • stoi throws on invalid input: If the string does not contain a valid number, stoi throws std::invalid_argument. Wrap conversions in a try/catch in production code.
  • C-string buffer overflow: Never use strcpy without ensuring the destination is large enough. Prefer std::string.
  • Mixing char and int with tolower: Cast to unsigned char before calling tolower or toupper to avoid undefined behaviour with characters outside the ASCII range.

Practice Exercises

  1. Write a program that reads 10 student marks into an array, then prints the highest mark, lowest mark, and class average.
  2. Declare a 3×3 integer matrix, populate it with values 1–9, and print its transpose.
  3. Write a function that takes a std::string and returns the count of vowels in it.
  4. Given a string like "2026-07-02", extract the year, month, and day as separate integers using substr and stoi.
  5. Write a function countWords(string s) that returns the number of words in a sentence (words separated by spaces).
  6. Check whether a given number (read as a string) is a palindrome — for example, "1221" is a palindrome.

Summary

  • A 1D array stores elements contiguously; access via zero-based index.
  • A 2D array is an array of arrays, useful for matrices and grids.
  • Raw arrays decay to pointers when passed to functions, losing their size — always pass size explicitly or use std::array.
  • std::array (C++11) is a safer fixed-size container that retains size and works with STL algorithms.
  • C-strings are null-terminated char arrays inherited from C; avoid them in favour of std::string.
  • std::string provides rich methods: length, substr, find, replace, append, compare, and more.
  • Conversion functions stoi, stod, and to_string convert between strings and numeric types cleanly.
  • The palindrome example demonstrated two-pointer reversal and case-insensitive comparison — patterns that recur constantly in competitive programming and technical interviews.