Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

C++ Arrays and the memory size of the data type #199

Open Qingquan-Li opened 2 years ago

Qingquan-Li commented 2 years ago

Reference: Book: Starting Out with C++ from Control Structures to Objects, byTony Gaddis, ninth edition

Contents:

  1. Arrays hold multiple values 1.1 Memory Requirements of Arrays
  2. Accessing Array Elements 2.1 Array Initialization 2.2 Partial Array Initialization 2.3 Implicit Array Sizing
  3. No Bounds Checking in C++


1. Arrays hold multiple values

Concept: An array allows you to store and work with multiple values of the same data type.

An array's size declarator must be a constant integer expression with a value greater than zero. It can be either a literal or a named constant.

const int NUM_DAYS = 6;
int days[NUM_DAYS];

float temperatures[100]; // Array of 100 floats
string names[10];        // Array of 10 string objects
long units[50];          // Array of 50 long integers
double sizes[1200];      // Array of 1200 doubles

1.1 Memory Requirements of Arrays

The amount of memory used by an array depends on the array's data type and the number of elements.

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

int main() {
    // Size of each int element: 1 byte
    char letters[2];
    cout << sizeof(letters) << endl;    // Output: 2

    // Size of each short element: 2 bytes
    short rings[2];
    cout << sizeof(rings) << endl;    // Output: 4

    // Size of each int element: 4 bytes
    int miles[2];
    cout << sizeof(miles) << endl;      // Output: 8

    // Size of each float element: 4 bytes
    float temp[2];
    cout << sizeof(temp) << endl;       // Output: 8

    // Size of each double element: 8 bytes
    double distance[2];
    cout << sizeof(distance) << endl;   // Output: 16

    // Size of each string element: 24 bytes
    string user_names[2];
    cout << sizeof(user_names) << endl; // Output: 48

    return 0;
}


2. Accessing Array Elements

Concept: The individual elements of an array are assigned unique subscripts. These subscripts are used to access the elements.

// Store the number 20 in the first element of array:
hours[0] = 20;

The expression hours[0] is pronounced "hours sub zero". You would read this assignment statements as "hours sub zero is assigned twenty."

Example:

// This program asks a student's letter_grade for 5 courses.
// It stores the values in an array.

#include <iostream>
#include <string>

using namespace std;

int main() {
    const int NUM_COURSES = 5;
    string letter_grades[NUM_COURSES];
    string letter_grade;

    for (int i = 0; i < NUM_COURSES; i++) {
        cout << "Please enter the letter grade of your course #" << i + 1 << ": ";
        cin >> letter_grade;
        letter_grades[i] = letter_grade;
    }

    cout << "Your letter grades in " << NUM_COURSES << " courses are: " << endl;

    // for (int i = 0; i < NUM_COURSES; i++)
    //    cout << letter_grades[i] << " ";

    // Use range-based for loop instead
    // for (string grade : letter_grades)
    //    cout << grade << " ";

    // Loop variable is copied but only used as const reference; consider making it a const reference
    for (string const & grade : letter_grades)
        cout << grade << " ";

    return 0;
}

Output:

Please enter the letter grade of your course #1: A+
Please enter the letter grade of your course #2: C
Please enter the letter grade of your course #3: B-
Please enter the letter grade of your course #4: A
Please enter the letter grade of your course #5: F
Your letter grades in 5 courses are: 
A+ C B- A F


2.1 Array Initialization

Like regular variable, C++ allows you to initialize an array's elements when you create the array. Here is an example:

const int MONTHS = 12;
int days[MONTHS] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Subscripts: 0 1 2 3 4 5 6 7 8 9 10 11
Array values: 31 28 31 30 31 30 31 31 30 31 30 31

Example:

// This program displays the number of days in each month.

#include <iostream>
using namespace std;

int main() {
    const int MONTHS = 12;
    int days[MONTHS] = {31, 28, 31, 30,
                        31, 30, 31, 31,
                        30, 31, 30, 31};
    for (int count = 0; count < MONTHS; count++) {
        cout << "Month " << (count + 1) << " has ";
        cout << days[count] << " days.\n";
    }
    return 0;
}

Output:

Month 1 has 31 days.
Month 2 has 28 days.
Month 3 has 31 days.
Month 4 has 30 days.
Month 5 has 31 days.
Month 6 has 30 days.
Month 7 has 31 days.
Month 8 has 31 days.
Month 9 has 30 days.
Month 10 has 31 days.
Month 11 has 30 days.
Month 12 has 31 days.

2.2 Partial Array Initialization

When an array is being initialized, C++ does not require a value for every element. It's possible to only initialize part of an array, such as:

int numbers[7] = {1, 2, 4, 8};
Subscripts: 0 1 2 3 4 5 6
Array values: 1 2 4 8 0 0 0

If an array is partially initialized, the uninitialized elements will be set to zero.

The uninitialized elements of a string array will contain empty strings.

2.3 Implicit Array Sizing

It's possible to define an array without specifying its size, as long as you provide an initialization list. C++ automatically makes the array large enough to hold all the initialization values.

double ratings[] = {1.0, 1.5, 2.0, 2.5, 3.0};

Because the size declarator is omitted, C++ counts the number of items in the initialization list and gives the array that many elements.

Example:

#include <iostream>
using namespace std;

int main() {
    // Size of each int element: 4 bytes
    int numbers[] = {1, 2, 3};
    cout << sizeof(numbers) << endl; // Output: 12

    // Size of each string element: 24 bytes
    string user_names[] = {"Alice", "Bob"};
    cout << sizeof(user_names) << endl; // Output: 48

    return 0;
}


3. No Bounds Checking in C++

Concept: C++ does not prevent you from overwriting an array's bounds.

Example:

// This program unsafely accesses an area of memory by writing
// values beyond an array's boundary.
// WARNING: If vou compile and run this program, it could crash.

#include <iostream>
using namespace std;

int main() {
    const int SIZE = 3;
    int values[SIZE];
    int count;

    // Attempt to store five numbers in the 3-element array.
    for (count = 0; count < 5; count++)
        values[count] = 100;

    // If the program is still running, display the numbers.
    cout << "If you see this message, it means the program\n";
    cout << "has not crashed! Here are the numbers:\n";
    for (count = 0; count < 5; count++)
        cout << values[count] << endl;

    return 0;
}

Output:

If you see this message, it means the program
has not crashed! Here are the numbers:
100
100
100
100
100

The values arrav has three integer elements, with the subscripts 0, 1, and 2. The loop, however, stores the number 100 in elements 0, 1, 2, 3, and 4. The elements with subscripts 3 and 4 do not exist, but C++ allows the program to write beyond the boundary of the array, as if those elements were there.

The absence of safeguards such as array bounds checking usually proves to be a bad thing.