본문으로 건너뛰기

Strings, Vectors, and Arrays

Built-in Type: A type defined directly by the C++ language.

Library Type: A type provided by the C++ standard library.

string: A variable-length sequence of characters.

vector: A variable-length sequence of objects of the same type.

Array: A built-in fixed-size sequence of elements.


3.1 Namespace using Declarations​

Namespace: A scope used to organize names.

std Namespace: Contains the names defined by the C++ standard library.

Scope Operator ::: Accesses a name inside a scope.

std::cout << "Hello\n";

Here, cout is accessed from the std namespace.

using Declaration​

using Declaration: Makes one namespace member directly accessible without repeatedly writing the namespace name.

Syntax:

using namespace_name::name;

Example:

#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
int a = 0;
int b = 0;

cin >> a >> b;

cout << a + b << endl;
}

Each using declaration introduces one name.

using std::cin;
using std::cout;
using std::endl;

Headers and using​

Headers should ordinarily not contain using declarations because every source file that includes the header would also receive those declarations.

Prefer qualified names in headers:

std::string name;

rather than introducing standard-library names globally.

Required Headers​

Each library feature requires its corresponding header.

#include <iostream>
#include <string>
#include <vector>

3.2 Library string Type​

std::string: A standard-library type representing a variable-length sequence of characters.

Required header:

#include <string>

1) Defining and Initializing strings​

A string can be initialized in several ways.

#include <string>

std::string s1;
std::string s2 = "hello";
std::string s3(s2);
std::string s4(5, 'a');

The resulting values are:

s1 = ""
s2 = "hello"
s3 = "hello"
s4 = "aaaaa"

Copy Initialization​

Copy Initialization: Uses = when initializing an object.

std::string s = "hello";

Direct Initialization​

Direct Initialization: Initializes the object directly using parentheses.

std::string s("hello");

Multiple constructor arguments require direct initialization.

std::string s(5, 'x');

This creates:

xxxxx

2) Operations on strings​

Important string operations include:

OperationMeaning
os << sWrites s
is >> sReads one whitespace-separated word
getline(is, s)Reads an entire line
s.empty()Tests whether s is empty
s.size()Returns the number of characters
s[n]Accesses character n
s1 + s2Concatenates strings
s1 = s2Assigns one string to another
s1 == s2Tests equality
s1 != s2Tests inequality

Reading a string​

The input operator reads until whitespace.

#include <iostream>
#include <string>

int main()
{
std::string word;

std::cin >> word;

std::cout << word << '\n';
}

Input:

Hello World

Result:

Hello

Only the first word is read.

Reading Multiple Strings​

A stream can be used as a loop condition.

std::string word;

while (std::cin >> word)
{
std::cout << word << '\n';
}

The loop continues while input succeeds.

getline​

getline reads an entire line, including spaces.

std::string line;

while (std::getline(std::cin, line))
{
std::cout << line << '\n';
}

Input:

Hello C++ World

The complete line is stored in line.

empty() and size()​

std::string s = "hello";

if (!s.empty())
{
std::cout << s.size() << '\n';
}

Output:

5

string::size_type​

size() returns string::size_type, an unsigned type suitable for representing string sizes.

std::string s = "hello";

std::string::size_type length = s.size();

auto is commonly used instead.

auto length = s.size();

Avoid unnecessary signed/unsigned mixing when working with size().


Comparing strings​

Strings can be compared directly.

std::string s1 = "hello";
std::string s2 = "world";

if (s1 != s2)
{
std::cout << "different\n";
}

Relational operators compare strings in lexicographical order.

std::string a = "apple";
std::string b = "banana";

if (a < b)
{
std::cout << "apple comes first\n";
}

String Assignment​

std::string s1 = "hello";
std::string s2 = "world";

s1 = s2;

After the assignment:

s1 = "world"

String Concatenation​

Strings can be joined using +.

std::string first = "Hello";
std::string second = "World";

std::string result = first + " " + second;

Result:

Hello World

A string can also be extended with +=.

std::string s = "Hello";

s += " World";

Literals and string​

At least one operand of each + operation must be a string.

Valid:

std::string s = "Hello";

std::string result = s + " World";

Invalid:

// "Hello " + "World"

Both operands above are string literals, not std::string objects.


3) Dealing with the Characters in a string​

Individual characters can be processed using iteration or subscripting.

Range-Based for​

Range-Based for: Iterates through every element of a sequence.

std::string s = "Hello";

for (auto c : s)
{
std::cout << c << '\n';
}

The loop variable c receives a copy of each character.

Counting Characters​

The <cctype> header provides character classification functions.

#include <cctype>
#include <string>

std::string s = "Hello, World!";

decltype(s.size()) punct_count = 0;

for (auto c : s)
{
if (std::ispunct(c))
{
++punct_count;
}
}

Important functions include:

FunctionMeaning
isalnum(c)Letter or digit
isalpha(c)Letter
isdigit(c)Digit
islower(c)Lowercase letter
isupper(c)Uppercase letter
isspace(c)Whitespace
ispunct(c)Punctuation
tolower(c)Converts to lowercase
toupper(c)Converts to uppercase

Modifying Characters​

A reference loop variable allows modification of the original string.

std::string s = "hello";

for (auto& c : s)
{
c = std::toupper(c);
}

After the loop:

HELLO

Without &, only a copy of each character would be modified.


String Subscript​

The [] operator accesses a character at a particular position.

std::string s = "hello";

char first = s[0];

first contains:

h

String indexing begins at zero.

A valid index satisfies:

0 <= index < s.size()

Modifying with a Subscript​

std::string s = "hello";

s[0] = 'H';

Result:

Hello

Checking Before Subscripting​

std::string s = "hello";

if (!s.empty())
{
s[0] = 'H';
}

Subscripting outside the valid range results in undefined behavior.


3.3 Library vector Type​

vector: A variable-length collection of objects of the same type.

Container: An object that contains other objects.

Class Template: A template from which specific class types are generated.

Required header:

#include <vector>

A vector type includes its element type.

std::vector<int> numbers;
std::vector<std::string> words;

vector itself is a template, not a complete type.

std::vector<int>

is a specific type generated from the template.

Vectors can contain other vectors.

std::vector<std::vector<int>> matrix;

A vector cannot contain references because references are not objects.


1) Defining and Initializing vectors​

Empty Vector​

std::vector<int> values;

values initially contains no elements.

Copying a Vector​

std::vector<int> v1{1, 2, 3};

std::vector<int> v2(v1);
std::vector<int> v3 = v1;

Both v2 and v3 contain:

1 2 3

List Initialization​

std::vector<int> values{1, 2, 3, 4, 5};

Each value becomes an element.

Specified Number of Elements​

std::vector<int> values(10);

This creates ten int elements value-initialized to zero.

Count and Value​

std::vector<int> values(10, 5);

This creates ten elements, each with value 5.

Parentheses vs. Braces​

These definitions have different meanings.

std::vector<int> v1(10);
std::vector<int> v2{10};

v1 contains ten zeros.

v2 contains one element:

10

Likewise:

std::vector<int> v1(10, 1);
std::vector<int> v2{10, 1};

v1:

1 1 1 1 1 1 1 1 1 1

v2:

10 1

2) Adding Elements to a vector​

push_back(): Adds an element to the end of a vector.

std::vector<int> values;

values.push_back(10);
values.push_back(20);
values.push_back(30);

Result:

10 20 30

Building a Vector at Run Time​

When values are not known beforehand, an empty vector can be filled dynamically.

std::vector<int> values;

for (int i = 0; i != 10; ++i)
{
values.push_back(i);
}

The vector becomes:

0 1 2 3 4 5 6 7 8 9

Reading Values into a Vector​

std::vector<int> values;
int value = 0;

while (std::cin >> value)
{
values.push_back(value);
}

Do Not Change Size During Range for​

Do not add elements to a vector while a range-based for is iterating over that same vector.

Avoid:

for (auto value : values)
{
// values.push_back(value);
}

Changing the vector size can invalidate the loop's internal iterators.


3) Other vector Operations​

Important operations include:

OperationMeaning
v.empty()Tests whether the vector is empty
v.size()Number of elements
v.push_back(t)Adds t
v[n]Accesses element n
v1 = v2Copies elements
v1 == v2Tests equality
v1 != v2Tests inequality

Range-Based for​

std::vector<int> values{1, 2, 3};

for (auto value : values)
{
std::cout << value << '\n';
}

Modifying Elements​

Use a reference when modifying the original elements.

std::vector<int> values{1, 2, 3};

for (auto& value : values)
{
value *= 2;
}

Result:

2 4 6

vector::size_type​

A vector provides a type suitable for representing its size.

std::vector<int> values{1, 2, 3};

std::vector<int>::size_type size = values.size();

Usually:

auto size = values.size();

is simpler.


Computing a Vector Index​

A vector subscript accesses an existing element.

std::vector<int> values{10, 20, 30};

std::cout << values[1];

Output:

20

The valid range is:

0 <= index < values.size()

Grade Counter Example​

A computed index can select an element.

std::vector<unsigned> scores(11, 0);

unsigned grade = 0;

while (std::cin >> grade)
{
if (grade <= 100)
{
++scores[grade / 10];
}
}

The eleven vector elements count grades in these groups:

0-9
10-19
20-29
...
90-99
100

For example:

grade = 65
65 / 10 = 6

Therefore:

++scores[6];

increments the appropriate counter.

Subscripting Does Not Add Elements​

This is invalid:

std::vector<int> values;

values[0] = 10;

The vector is empty, so element 0 does not exist.

Use push_back():

std::vector<int> values;

values.push_back(10);

3.4 Introducing Iterators​

Iterator: An object used to access elements of a container or characters of a string indirectly.

An iterator conceptually behaves somewhat like a pointer.

1) Using Iterators​

begin()​

Returns an iterator to the first element.

auto begin = values.begin();

end()​

Returns an iterator one position past the last element.

auto end = values.end();

end() does not refer to an actual element and must not be dereferenced.

Iterator Loop​

std::vector<int> values{10, 20, 30};

for (auto it = values.begin(); it != values.end(); ++it)
{
std::cout << *it << '\n';
}

*it accesses the element referred to by the iterator.

Empty Container​

For an empty container:

values.begin() == values.end()

Iterator Operations​

OperationMeaning
*iterAccess element
iter->memberAccess member of element
++iterMove to next element
--iterMove to previous element
iter1 == iter2Compare positions
iter1 != iter2Compare positions

Modifying Through an Iterator​

std::vector<int> values{1, 2, 3};

for (auto it = values.begin(); it != values.end(); ++it)
{
*it *= 2;
}

Result:

2 4 6

Iterator Types​

A non-const container provides a modifiable iterator.

std::vector<int>::iterator it;

A const_iterator can read but not modify elements.

std::vector<int>::const_iterator it;

cbegin() and cend()​

These functions always return const iterators.

for (auto it = values.cbegin();
it != values.cend();
++it)
{
std::cout << *it << '\n';
}

Arrow Operator ->​

For a container of objects, -> accesses a member of the current element.

std::vector<std::string> words{"hello", "world"};

for (auto it = words.begin(); it != words.end(); ++it)
{
std::cout << it->size() << '\n';
}

This:

it->size()

is equivalent to:

(*it).size()

Iterator Invalidation​

Operations that change a vector's size may invalidate existing iterators.

std::vector<int> values{1, 2, 3};

auto it = values.begin();

values.push_back(4);

After push_back(), it may no longer be valid.

Do not continue using an iterator after an operation that may invalidate it.


2) Iterator Arithmetic​

vector and string iterators support arithmetic operations.

std::vector<int> values{10, 20, 30, 40};

auto it = values.begin();

auto third = it + 2;

third refers to:

30

Iterator Difference​

auto first = values.begin();
auto last = values.end();

auto distance = last - first;

The result is the number of elements between the two iterators.

Midpoint​

auto mid =
values.begin() +
values.size() / 2;

Iterator Arithmetic Operations​

OperationMeaning
iter + nMove forward n elements
iter - nMove backward n elements
iter += nAdvance iterator
iter -= nMove iterator backward
iter1 - iter2Distance between iterators
<, <=, >, >=Compare positions

Iterator arithmetic must involve positions belonging to the same sequence.


3.5 Arrays​

Array: A fixed-size sequence of objects of the same type.

Unlike a vector, the number of array elements cannot change after the array is defined.

1) Defining and Initializing Built-in Arrays​

Array syntax:

type name[size];

Example:

int values[10];

This defines an array containing ten int elements.

The dimension must be a constant expression.

constexpr unsigned size = 10;

int values[size];

List Initialization​

int values[5] = {1, 2, 3, 4, 5};

The dimension can be omitted when an initializer list is present.

int values[] = {1, 2, 3, 4, 5};

The compiler determines the size.

Partial Initialization​

int values[5] = {1, 2};

The remaining elements are value initialized.

Conceptually:

1 2 0 0 0

Arrays Cannot Contain References​

Invalid:

// int& refs[10];

Character Arrays​

A character array can be initialized from a string literal.

char text[] = "hello";

The array contains:

h e l l o \0

The terminating null character is part of the array.

Therefore:

char text[6] = "hello";

is valid.


No Array Copy or Assignment​

Built-in arrays cannot be copied directly.

int a[] = {1, 2, 3};
int b[3];

// Invalid
// b = a;

Likewise, one array cannot be initialized by directly copying another built-in array.


Complicated Array Declarations​

Array of Pointers​

int* pointers[10];

pointers is an array containing ten pointers to int.

Pointer to Array​

int values[10];

int (*p)[10] = &values;

p is a pointer to an array of ten ints.

Reference to Array​

int values[10];

int (&ref)[10] = values;

ref is a reference to the entire array.


2) Accessing Array Elements​

Array subscripts begin at zero.

int values[] = {10, 20, 30};

std::cout << values[0];

Output:

10

Range-Based for​

int values[] = {10, 20, 30};

for (auto value : values)
{
std::cout << value << '\n';
}

Use a reference to modify the original elements.

for (auto& value : values)
{
value *= 2;
}

Bounds​

For an array of size N, valid indices are:

0 ... N - 1

Access outside the valid range is undefined behavior.

int values[3] = {1, 2, 3};

// Invalid access
// values[3]

3) Pointers and Arrays​

In most expressions, an array is converted to a pointer to its first element.

int values[] = {10, 20, 30};

int* p = values;

This is equivalent to:

int* p = &values[0];

auto and Arrays​

int values[10];

auto p = values;

p is deduced as:

int*

decltype and Arrays​

decltype preserves the array type.

int values[10];

decltype(values) copy = {};

copy is another array of ten ints.


Pointers Are Iterators​

Pointers can move through an array.

int values[] = {10, 20, 30};

int* p = values;

++p;

p now points to:

values[1]

Library begin() and end()​

The standard library provides functions for obtaining array boundaries.

#include <iterator>

int values[] = {10, 20, 30};

int* first = std::begin(values);
int* last = std::end(values);

first points to the first element.

last points one position past the final element.

Array traversal:

for (auto p = std::begin(values);
p != std::end(values);
++p)
{
std::cout << *p << '\n';
}

Pointer Arithmetic​

Adding to a pointer moves it by elements, not bytes.

int values[] = {10, 20, 30, 40};

int* p = values;

p += 2;

p now points to:

values[2]

Pointer Difference​

auto first = std::begin(values);
auto last = std::end(values);

auto count = last - first;

For a four-element array:

count = 4

Pointer Dereference and Arithmetic​

int values[] = {10, 20, 30};

int* p = values;

std::cout << *(p + 1);

Output:

20

Therefore:

values[1]

and

*(values + 1)

access the same element.


4) C-Style Character Strings​

C-Style String: A null-terminated character array.

char text[] = "hello";

The terminating '\0' marks the end of the string.

<cstring>​

The <cstring> header provides C-style string functions.

#include <cstring>

Important functions include:

FunctionMeaning
strlen(p)Length excluding '\0'
strcmp(p1, p2)Compare strings
strcpy(p1, p2)Copy string
strcat(p1, p2)Append string

strlen​

char text[] = "hello";

std::cout << std::strlen(text);

Output:

5

Comparing C-Style Strings​

Do not compare their contents with ordinary pointer comparison.

Use:

const char a[] = "hello";
const char b[] = "hello";

if (std::strcmp(a, b) == 0)
{
std::cout << "equal\n";
}

Destination Size​

Functions such as strcpy and strcat require sufficient destination storage.

char destination[20] = "Hello ";
const char source[] = "World";

std::strcat(destination, source);

The destination must have enough space for all characters and the final null terminator.

Prefer std::string​

For normal C++ text handling, prefer:

std::string text = "hello";

over manually managing C-style character arrays.


5) Interfacing to Older Code​

Modern C++ sometimes needs to interact with APIs that use arrays or C-style strings.

C-Style String to std::string​

const char text[] = "hello";

std::string s = text;

string::c_str()​

c_str() provides a pointer to a null-terminated representation of a string.

std::string s = "hello";

const char* p = s.c_str();

The returned pointer should not be assumed to remain valid after operations that modify s.


Array to vector​

An array range can initialize a vector.

int values[] = {0, 1, 2, 3, 4, 5};

std::vector<int> v(
std::begin(values),
std::end(values)
);

The vector contains:

0 1 2 3 4 5

A partial range can also be copied.

std::vector<int> v(values + 1, values + 4);

Result:

1 2 3

Library Type Preference​

For general C++ programming, prefer:

std::vector over built-in arrays
iterators over raw pointer traversal
std::string over C-style strings

unless low-level array or pointer behavior is specifically required.


3.6 Multidimensional Arrays​

Multidimensional Array: An array whose elements are themselves arrays.

Strictly speaking, C++ multidimensional arrays are arrays of arrays.

Example:

int matrix[3][4];

This means:

3 rows
4 integers per row
12 integers total

Initializing Multidimensional Arrays​

Nested braces make the row structure explicit.

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

Partial Initialization​

int matrix[3][4] =
{
{0},
{4},
{8}
};

The remaining elements are value initialized.

The rows become conceptually:

0 0 0 0
4 0 0 0
8 0 0 0

Subscripting a Multidimensional Array​

One subscript is used for each dimension.

int value = matrix[1][2];

This accesses row 1, column 2.

Partial Subscript​

matrix[1]

refers to the entire second row.

A reference can bind to that row.

int (&row)[4] = matrix[1];

Iterating with Nested for Loops​

constexpr std::size_t row_count = 3;
constexpr std::size_t column_count = 4;

int matrix[row_count][column_count];

for (std::size_t row = 0;
row != row_count;
++row)
{
for (std::size_t column = 0;
column != column_count;
++column)
{
matrix[row][column] =
row * column_count + column;
}
}

The resulting values are:

0 1 2 3
4 5 6 7
8 9 10 11

Range-Based for​

When iterating over multidimensional arrays, the outer loop variable must be a reference so that the inner array does not decay into a pointer.

for (auto& row : matrix)
{
for (auto value : row)
{
std::cout << value << ' ';
}

std::cout << '\n';
}

To modify the elements:

for (auto& row : matrix)
{
for (auto& value : row)
{
value = 0;
}
}

Pointers and Multidimensional Arrays​

For:

int matrix[3][4];

matrix is an array whose elements are arrays of four ints.

In most expressions it converts to:

int (*)[4]

A pointer can therefore be declared as:

int (*p)[4] = matrix;

p points to one row.

Incrementing p moves to the next row.

++p;

Now p points to:

matrix[1]

Array of Pointers vs. Pointer to Array​

These declarations are different:

int* p1[4];
int (*p2)[4];

p1:

array of four pointers to int

p2:

pointer to an array of four int

The parentheses are essential.


Iterating with Pointers​

for (auto p = std::begin(matrix);
p != std::end(matrix);
++p)
{
for (auto q = std::begin(*p);
q != std::end(*p);
++q)
{
std::cout << *q << ' ';
}

std::cout << '\n';
}

p moves through rows.

q moves through the elements of each row.


Type Aliases​

A type alias can simplify array declarations.

using int_array = int[4];

int matrix[3][4];

int_array* p = matrix;

This:

int_array* p;

is equivalent to:

int (*p)[4];

The alias makes the relationship between the pointer and each row easier to read.


Essential Study Checklist​

  1. std::string represents variable-length character sequences.
  2. std::vector<T> represents variable-length collections of T.
  3. using declarations introduce individual namespace members.
  4. Headers should generally avoid using declarations.
  5. string >> reads one whitespace-separated word.
  6. getline() reads an entire line.
  7. string::size() returns an unsigned size type.
  8. Range-based for is useful for processing every element.
  9. Use auto& when a range-based loop must modify the original element.
  10. vector::push_back() adds elements.
  11. vector[n] accesses only an element that already exists.
  12. Vector subscripting does not create elements.
  13. begin() refers to the first element.
  14. end() refers to one position past the last element.
  15. An iterator must not dereference end().
  16. Vector size changes may invalidate iterators.
  17. Iterator arithmetic is supported by vector and string iterators.
  18. Built-in arrays have a fixed size.
  19. Array indices begin at zero.
  20. Arrays normally convert to pointers to their first elements.
  21. std::begin() and std::end() can safely obtain array bounds.
  22. Pointer arithmetic moves by elements.
  23. C-style strings end with '\0'.
  24. Prefer std::string over C-style strings for normal text handling.
  25. An array range can initialize a vector.
  26. A multidimensional array is actually an array of arrays.
  27. int (*p)[4] is a pointer to an array of four ints.
  28. int* p[4] is an array of four pointers.
  29. Outer range-for variables over multidimensional arrays should be references.
  30. Type aliases can simplify complicated array types.