Przechowywanie ciągu znaków w tablicy znaków bez znaku pustego

Czytam C ++ Primer Plus autorstwa Stephena Praty. Podaje ten przykład:

char dog[8] = { 'b', 'e', 'a', 'u', 'x', ' ', 'I', 'I'}; // not a string!
char cat[8] = {'f', 'a', 't', 'e', 's', 's', 'a', '\0'}; // a string!

z komentarzem, że:

Obie te tablice są tablicami znaków, ale tylko druga jest łańcuchem. Znak zerowy odgrywa podstawową rolę w ciągach w stylu C. Na przykład C ++ ma wiele funkcji, które obsługują ciągi znaków, w tym te używane przez cout. Wszystkie działają, przetwarzając ciąg znaków po znaku, aż osiągną znak pusty. Jeśli poprosisz couta o wyświetlenie ładnego ciągu takiego jak cat w poprzednim przykładzie, wyświetla pierwsze siedem znaków, wykrywa znak pusty i zatrzymuje się. Ale jeśli jesteś na tyle niewdzięczny, aby powiedzieć coutowi, aby wyświetlał tablicę psów z poprzedniego przykładu, który nie jest ciągiem znaków, cout wypisuje osiem liter w tablicy, a następnie kontynuuje marsz przez bajt po bajcie, interpretując każdy bajt jako znak do wydrukowania, dopóki nie osiągnie znaku zerowego. Ponieważ znaki zerowe, które naprawdę są bajtami ustawionymi na zero, mają tendencję do bycia powszechnymi w pamięci, uszkodzenia są zwykle szybko zawarte; nie należy jednak traktować tablic znaków niestringowych jako ciągów znaków.

Teraz, jeśli zadeklaruję moje zmienne globalnie, tak:

#include <iostream>
using namespace std;

char a[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
char b[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};

int main(void)
{
    cout << a << endl;
    cout << b << endl;

    return 0;
}

wyjście będzie:

abcdefgh12345678
12345678

Rzeczywiście, cout "przechodzi przez pamięć bajt po bajcie", ale tylko do końca drugiej tablicy znaków. To samo dzieje się z dowolną kombinacją tablicy znaków. Myślę, że wszystkie inne adresy są zainicjowane na 0 i dlatego zatrzymują cout. Czy to prawda? Jeśli zrobię coś takiego:

for (int i = 0; i < 100; ++i)
{
    cout << *(&a + i) << endl;
}

Na wyjściu dostaję głównie pustą przestrzeń (być może 95%), ale nie wszędzie.

Jeśli jednak zadeklaruję moje tablice char trochę krótsze, jak:

char a[3] = {'a', 'b', 'c'};
char b[3] = {'1', '2', '3'};

Trzymając wszystkie inne rzeczy tak samo, otrzymuję następujące dane wyjściowe:

abc
123

Teraz cout nie przeszedł nawet pierwszej tablicy char, nie wspominając o drugiej. Dlaczego to się dzieje? Sprawdziłem adresy pamięci i są one sekwencyjne, tak jak w pierwszym scenariuszu. Na przykład,

cout << &a << endl;
cout << &b << endl;

daje

003B903C
003B9040

Dlaczego w tym przypadku zachowanie jest inne? Dlaczego nie czyta poza pierwszą tablicą znaków?

I na koniec, jeśli zadeklaruję moje zmienne wewnątrz main, otrzymam zachowanie sugerowane przez Pratę, a mianowicie, dużo śmieci zostanie wydrukowanych wcześniej, gdzie osiągnięty zostanie znak null.

Zgaduję, że w pierwszym przypadku tablica char jest zadeklarowana na stercie i że jest zainicjowana na 0 (ale nie wszędzie, dlaczego?), A cout zachowuje się inaczej na podstawie długości tablicy char (dlaczego?)

Korzystam z Visual Studio 2010 dla tych przykładów.

questionAnswers(4)

yourAnswerToTheQuestion