2015-08-06 3 views
2
#include <iostream> 
#include <string> 

using namespace std; 

int main() { 
    string s = "hello"; 

    cout << s[5] << endl; 
    return 0; 
} 

В приведенном выше коде, если я печатаю s[5], он правильно печатает NULL характер. Но если изменить код следующим образом:Null поведение персонажа C++

#include <iostream> 
#include <string> 

using namespace std; 

int main() { 
    char[] s = {'a','b','c','d','e'}; 

    cout << s[5] << endl; 
    return 0; 
} 

Он не печатает NULL характер, но что-то случайное. Если я сохраню строку как string или как char*, то поведение будет соответствовать тому, что я ожидаю.

Но если я явно объявляю массив символов, как компилятор знает, когда заканчивается массив? Сохраняется ли размер массива во время компиляции?

+5

'char [] s = {'a', 'b', 'c', 'd', 'e'};' Эта конструкция хранит только указанные вами символы и ничего больше; нет нулевого ограничителя. –

+0

компилятор смотрит на количество статических символов, которые вы предоставили, и узнает его размер. естественно, если статические символы не были объявлены, вам нужно будет указать размер – mangusta

+2

Это должно быть 'char s []', а не 'char [] s'. –

ответ

0

Строки имеют нулевой конец и const char* обрабатываются так же, как и строки. Когда вы объявляете массив с размером, он помещается в стек, а компилятор не знает размер. Во время компиляции не задаются исключения из массива вне пределов.

+1

Компилятор _does_ знает размер массива. Это просто не делает проверку за вас. –

0

Когда вы сделаете char[] s = {'a','b','c','d','e'};, в нем будут сохранены упомянутые символы и ничего больше.

Если я явно объявляю массив символов, как компилятор знает, когда заканчивается массив?

Размер определяется по количеству предоставленных вам персонажей.

Сохраняется ли размер массива во время компиляции?

no, размер массива определяется выделенными ему блоками памяти. (Он не хранится отдельно в памяти, если это то, что вы имели в виду)

И когда вы используете это string s = "hello";, строки всегда имеют нулевое завершение.

+0

Если вы объявляете массив как 'char s [] = {'a', 'b', 'c', 'd', 'e'};' тогда размер 's' сохраняется во время компиляции. Если это часть типа 's'. См. Например ['std :: extent'] (http://en.cppreference.com/w/cpp/types/extent) –

+0

Он спрашивает о том, хранится ли он. – Nishant

+0

Что вы подразумеваете под« сохраненным »? Вы можете получить размер от типа, так что да, он «хранится». например, вы можете написать цикл, основанный на диапазоне: 'for (char c: s) {...}' –

0

класс string в C++ имеет конструктор, который сам по себе добавляет нулевой символ к переданной ему строке, если явно не добавлен. Но при использовании char он сохраняет только содержимое, переданное ему (например, если вы хотите иметь нулевой символ, который вы должны явно добавить в объявление или определение этого символа).

0

Ваш код char s[] = {'a','b','c','d','e'};, поэтому он не ставит \0 в конце вашего char array. Это поставит \0 с тремя методами ниже:

1. char s[] = {'a','b','c','d','e', '\0'}; 
2. char s[] = "abcde"; 
3. string s = "abcde"; 

Так что, если вы используете какой-либо из этих трех, вы получите NULL характер.

2

String литералы и std::string s магазин null завершение строки.

Но массив 5 char объявлен как:

char s[] = {'a','b','c','d','e'}; 

содержит только 5 char, не нуль-терминатор.

Но компилятор делает знает размер s.Это часть типа s. Он не имеет удобный .size() функции, как std::string, std::vector или std::array делает, но вы можете получить его, выполнив:

sizeof(s)/sizeof(s[0]) 

или более безопасно в C++ 11:

std::extent<decltype(s)>::value 

Или в C++ 17 :

std::size(s) 

(demo)

У массивов есть привычка к разложению указателям, хотя и тогда нет способа получить размер, вы должны сами отслеживать это. Именно поэтому std::string, std::vector или std::array является предпочтительным в C++.

0

«Как компилятор знает, когда заканчивается массив?»: Компилятор знает, сколько элементов имеет массив из его объявления, и эта информация доступна через оператор sizeof.

В любом случае массивы C-стиля практически не имеют размера, поскольку они неявно обращаются к указателям при передаче в качестве аргументов, а их длина отбрасывается (IMO - главный недостаток в дизайне языка C). Предотвращение переполнения - ваша ответственность.

По этой причине вы не должны использовать инструкцию cout < <, если ваша строка не имеет нулевой последовательности.