TeqStudy ยท C++ Track ยท Phase 03

Arrays, Strings & Functions

Storing many values, real text manipulation, and writing your own reusable functions โ€” including the pass-by-value/pass-by-reference distinction that Phase 4's pointers build directly on.

๐Ÿ“š ๐Ÿ“ ๐Ÿท๏ธ ๐Ÿชž ๐Ÿ
Course Progress
0%
MODULE 01

๐Ÿ“š Arrays โ€” Storing Many Values

Every variable so far has held exactly one value. What happens when you need to store 100 test scores, or a whole deck of cards?

๐Ÿ“ฆ๐Ÿ“ฆ๐Ÿ“ฆ A Row of Labeled Boxes

An array is a fixed-size, ordered collection of values of the same type โ€” think of it as several labeled boxes in a row, sharing one overall name, each accessed by its position.

C++
int scores[5] = {85, 92, 78, 95, 88};
std::cout << scores[0];  // prints 85 โ€” the FIRST element
std::cout << scores[2];  // prints 78 โ€” the THIRD element
0๏ธโƒฃ Zero-Indexed โ€” The Single Most Important Rule

C++ arrays start counting positions at 0, not 1. A 5-element array has valid positions 0, 1, 2, 3, and 4 โ€” scores[5] does NOT exist and accessing it is a real, dangerous bug (Module 2 covers exactly why). This trips up nearly every beginner at least once; it's worth deliberately internalizing now.

Position: 0 1 2 3 4 Value: [85] [92] [78] [95] [88]
๐Ÿ” Looping Through an Array

Arrays and for loops (Phase 2) are natural partners:

C++
for (int i = 0; i < 5; i++) {
    std::cout << scores[i] << " ";
}

This is exactly why for loops conventionally start their counter at 0 โ€” it lines up perfectly with an array's own zero-based positions.

๐Ÿง  Quick Check
In a 5-element array, what is the position ("index") of the FIRST element?
MODULE 02

๐Ÿšง Array Bounds & Common Mistakes

This is a genuinely important C++-specific lesson โ€” one of the language's real, well-known sharp edges, worth understanding clearly rather than discovering the hard way.

โš ๏ธ C++ Does NOT Check Array Bounds for You
C++ โ€” this compiles and runs!
int scores[5] = {85, 92, 78, 95, 88};
std::cout << scores[10];  // undefined behavior โ€” NOT a clean error
โš ๏ธ
This is genuinely different from many other languagesSome languages immediately stop your program with a clear error the moment you access an out-of-bounds index. C++ doesn't โ€” it's called undefined behavior, meaning literally anything can happen: garbage data, a crash, or (worst of all) it might appear to "work" some of the time, making the bug intermittent and hard to track down. This isn't a flaw to be scared of โ€” it's a real design tradeoff (checking bounds costs performance) that you now know to work around carefully.
๐Ÿ”ข Getting an Array's Size Safely
C++
int scores[] = {85, 92, 78, 95, 88};
int size = sizeof(scores) / sizeof(scores[0]);
// size is 5 โ€” total bytes divided by one element's byte size

This pattern โ€” total size divided by one element's size โ€” is the classic C-style way to compute an array's length. Phase 7's STL introduces std::vector, which tracks its own size directly and avoids needing this pattern at all โ€” but you'll still see this technique in real C++ code, so it's worth recognizing.

๐Ÿง  Quick Check
What happens when your code accesses an array index that's out of bounds, like index 10 on a 5-element array?
MODULE 03

๐Ÿ”ฒ Multi-Dimensional Arrays

Phase 2's nested loops were building toward exactly this: an array of arrays, for anything genuinely grid-shaped.

๐ŸŽฒ A Grid, Declared Directly
C++
int board[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
std::cout << board[1][2];  // prints 6 โ€” row 1, column 2

Think of a tic-tac-toe board, a chessboard, or a spreadsheet โ€” board[row][col] reads directly as "the value at this row, this column," exactly matching how you'd describe a grid position out loud.

๐Ÿช† Nested Loops Are the Natural Match
C++
for (int row = 0; row < 3; row++) {
    for (int col = 0; col < 3; col++) {
        std::cout << board[row][col] << " ";
    }
    std::cout << std::endl;
}

This is exactly Phase 2 Module 4's nested-loop pattern, now genuinely put to work โ€” walking through every cell of a real 2D grid, row by row.

๐Ÿง  Quick Check
In a 2D array declared as board[row][col], what does the outer loop typically represent?
MODULE 04

๐Ÿ“ std::string in Depth

You've used std::string since Phase 1. Here's what it actually is under the hood, and why it's genuinely easier to work with than it might seem.

๐Ÿ”ค A String Is Basically an Array of Characters

Conceptually, "Hello" is a sequence of individual char values โ€” 'H', 'e', 'l', 'l', 'o' โ€” stored in order. std::string wraps this idea in a convenient, safe package that manages its own size automatically, unlike a raw array which has a fixed size you must track yourself.

๐Ÿ“ Accessing Individual Characters
C++
std::string name = "Alex";
std::cout << name[0];        // prints 'A'
std::cout << name.length();  // prints 4

Strings are zero-indexed exactly like arrays (Module 1) โ€” name[0] is the first character. .length() gives you the string's current size, always accurate, without needing the manual sizeof trick from Module 2.

โž• Combining Strings
C++
std::string firstName = "Alex";
std::string lastName = "Rivera";
std::string fullName = firstName + " " + lastName;
// fullName is "Alex Rivera"

+ concatenates (joins) strings together โ€” this is a genuine, different meaning of + than the arithmetic addition from Phase 1, and C++ figures out which one you mean based on the types involved.

๐Ÿง  Quick Check
What does the .length() method return for a std::string?
MODULE 05

๐Ÿ”ง String Operations & Methods

The handful of std::string operations you'll genuinely reach for constantly, in nearly every real program that handles text.

๐Ÿ› ๏ธ The Core Toolkit
MethodWhat It DoesExample
.substr(start, length)Extracts part of a string"Hello".substr(1, 3) โ†’ "ell"
.find(text)Finds the position of text within a string (or a special "not found" value)"Hello".find("llo") โ†’ 2
== / !=Compares two strings for equalityname == "Alex"
.empty()Checks if a string has zero charactersname.empty()
๐Ÿ” Checking If find() Actually Found Something
C++
std::string sentence = "The quick fox";
if (sentence.find("fox") != std::string::npos) {
    std::cout << "Found it!" << std::endl;
}

std::string::npos is the special value .find() returns when the text isn't found at all โ€” always compare against it explicitly, rather than assuming any returned value means success.

๐Ÿ”ก Uppercase and Lowercase Conversion

C++ doesn't have a single built-in "make this uppercase" string method โ€” instead, you loop through each character and convert it individually with the toupper()/tolower() functions:

C++
std::string text = "hello";
for (int i = 0; i < text.length(); i++) {
    text[i] = toupper(text[i]);
}
// text is now "HELLO"
๐Ÿง  Quick Check
What does .find() return when the text you're searching for isn't present in the string at all?
MODULE 06

๐Ÿท๏ธ Functions โ€” Parameters & Return Values

The Pre-Course covered "named instructions" conceptually, and you've written main() in every program so far. Time to write your own functions properly.

๐Ÿ” Anatomy of a Function
C++
double calculateTax(double price, double rate) {
    return price * rate;
}

int main() {
    double tax = calculateTax(50.00, 0.08);
    std::cout << tax;  // prints 4
    return 0;
}
PartMeaning
double (before the name)The type of value this function RETURNS
calculateTaxThe function's name
(double price, double rate)The parameters โ€” information the function needs, each with its own type
return price * rate;The value handed back to whoever called the function
๐Ÿšซ void โ€” When There's Nothing to Return
C++
void printWelcome(std::string name) {
    std::cout << "Welcome, " << name << "!" << std::endl;
    // no return statement needed
}

Some functions just DO something (print a message, update the screen) without handing back a specific value โ€” void as the return type says exactly that.

๐Ÿง  Quick Check
What does writing void as a function's return type actually mean?
MODULE 07

๐Ÿ“ฎ Pass by Value vs. Pass by Reference

A genuinely important C++ concept with real, practical consequences โ€” worth understanding clearly now, since Phase 4's pointers build directly on this idea.

๐Ÿ“‹ Pass by Value โ€” A Copy Is Made
C++
void doubleIt(int num) {
    num = num * 2;  // only changes the local copy
}

int main() {
    int x = 5;
    doubleIt(x);
    std::cout << x;  // still prints 5 โ€” the original x is unchanged!
}

By default, C++ passes a COPY of the argument into a function โ€” changes made inside the function affect only that local copy, never the original variable back in main().

๐Ÿ”— Pass by Reference โ€” The Real Variable, No Copy
C++
void doubleIt(int& num) {  // note the &
    num = num * 2;
}

int main() {
    int x = 5;
    doubleIt(x);
    std::cout << x;  // prints 10 โ€” the original x actually changed!
}

Adding & after the type in a parameter makes it a reference โ€” the function now works with the ORIGINAL variable directly, not a copy. This is exactly how a function can meaningfully modify a caller's variable.

๐ŸŽฏ When to Use Which
SituationChoice
The function shouldn't change the caller's dataPass by value (the default, safer choice)
The function genuinely needs to modify the original variablePass by reference (&)
Passing a large object where copying would be wasteful, but you don't need to modify itconst reference โ€” best of both: no copy, but protected from changes
๐Ÿง  Quick Check
A function takes a parameter as int num (no &). If the function changes num inside its body, what happens to the original variable back in main()?
MODULE 08

๐ŸŽญ Function Overloading

C++ allows multiple functions to share the exact same name, as long as they can genuinely be told apart.

๐Ÿ‘ฅ Same Name, Different Parameters
C++
int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

int main() {
    std::cout << add(2, 3);        // calls the int version โ†’ 5
    std::cout << add(2.5, 3.5);    // calls the double version โ†’ 6.0
}

C++ picks which version to actually run based on the TYPES of arguments you pass in โ€” this is called overloading. It exists so that conceptually-related operations (like "add two things") can share one intuitive name, instead of needing awkward separate names like addInts and addDoubles.

๐Ÿ”‘ What Makes Two Overloads Different

Overloaded functions must differ in their PARAMETER TYPES or COUNT โ€” not just their return type alone. Two functions with the same name and same exact parameter types, differing only in return type, is a compiler error, since C++ wouldn't be able to tell them apart from the calling code alone.

๐Ÿง  Quick Check
How does C++ decide which overloaded version of a function to actually run when it's called?
MODULE 09

๐Ÿชž Recursion

A function that calls itself. It sounds circular at first, but it's a genuinely powerful, natural way to solve certain problems.

๐Ÿ” The Classic Example โ€” Factorial
C++
int factorial(int n) {
    if (n <= 1) {
        return 1;          // base case โ€” stops the recursion
    }
    return n * factorial(n - 1);  // recursive case
}

factorial(5) is 5 ร— 4 ร— 3 ร— 2 ร— 1. Notice the function calls ITSELF with a smaller number each time โ€” factorial(5) calls factorial(4), which calls factorial(3), and so on, until it hits the base case.

๐Ÿ›‘ Every Recursive Function Needs a Base Case

The base case (if (n <= 1) return 1; above) is the condition that stops the recursion. Without one, a recursive function calls itself forever โ€” this is genuinely the exact same infinite-loop danger from Phase 2, just in recursive form instead of a while loop.

factorial(5) = 5 * factorial(4) = 4 * factorial(3) = 3 * factorial(2) = 2 * factorial(1) = 1 โ† base case reached, stops here
๐Ÿ†š Recursion vs. a Loop

Everything recursion does, a loop can also do โ€” and vice versa. Recursion tends to read more naturally for problems that are themselves naturally recursive (like navigating a tree-shaped folder structure), while loops are usually clearer and more efficient for simple repeated counting. You'll develop a feel for which fits better with experience.

๐Ÿง  Quick Check
What happens if a recursive function is missing its base case?
MODULE 10 ๐Ÿ

๐Ÿ Capstone โ€” Word Analyzer

Every idea from this phase, combined: arrays, strings, functions with real parameters, and pass-by-reference โ€” a program that actually analyzes real text.

๐ŸŽฏ The Goal

Ask the user for a sentence, then report: the total character count, the number of vowels, and the sentence converted to uppercase โ€” using separate, well-named functions for each job.

๐Ÿ’ป A Reference Solution
main.cpp
#include <iostream>

int countVowels(std::string text) {
    int count = 0;
    for (int i = 0; i < text.length(); i++) {
        char c = tolower(text[i]);
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
            count++;
        }
    }
    return count;
}

void toUppercase(std::string& text) {  // pass by reference โ€” modifies the original
    for (int i = 0; i < text.length(); i++) {
        text[i] = toupper(text[i]);
    }
}

int main() {
    std::string sentence;
    std::cout << "Enter a sentence: ";
    std::getline(std::cin, sentence);

    std::cout << "Character count: " << sentence.length() << std::endl;
    std::cout << "Vowel count: " << countVowels(sentence) << std::endl;

    toUppercase(sentence);
    std::cout << "Uppercase: " << sentence << std::endl;

    return 0;
}
๐Ÿ” Why It's Built This Way
  • countVowels passes by VALUE (Module 7) since it only needs to read the sentence, never modify it.
  • toUppercase deliberately passes by REFERENCE, since modifying the original string in place is exactly the point โ€” the whole reason to choose &.
  • Each job (counting, converting) lives in its own clearly-named function, exactly the Pre-Course's "named instructions" idea, now genuinely doing real work.
๐Ÿ Extend It Yourself

Add a Word Count

Write a new function, countWords, that counts how many words are in the sentence (hint: count the spaces, then add one โ€” but watch out for extra spaces at the start/end). Decide for yourself whether it should pass by value or by reference, and be ready to explain why your choice is the right one.

Roadmap