Струна сходит с ума, если я не дам ему немного больше места. Кто-нибудь может объяснить, что здесь происходит? - PullRequest
36 голосов
/ 04 мая 2011

Во-первых, я хотел бы сказать, что я новичок в C / C ++, изначально я разработчик PHP, поэтому меня заставляют злоупотреблять переменными так, как мне нравится.

C - строгая страна, мне здесь не очень нравятся компиляторы, я привык нарушать правила, чтобы добиться цели.

Во всяком случае, это мой простой кусок кода:

char IP[15] = "192.168.2.1";
char separator[2] = "||";   

puts( separator );

Выход:

||192.168.2.1

Но если я изменю определение separator на:

char separator[3] = "||";

Я получаю желаемый вывод:

||

Так почему мне нужно дать человеку дополнительное пространство, чтобы он не спал с человеком перед ним?

Ответы [ 11 ]

45 голосов
/ 04 мая 2011

Это потому, что вы получаете строку с нулевым символом в конце, когда длина separator равна 2.

Всегда не забывайте выделять дополнительный символ для нулевого терминатора. Для строки длиной N вам нужно N+1 символов.

Если вы нарушите это требование, любой код, ожидающий строки с нулевым символом в конце (включая функцию puts()), будет работать с неопределенным поведением.

Лучше всего не устанавливать конкретную длину:

char separator[] = "||";

выделит массив точно правильного размера.

22 голосов
/ 04 мая 2011

Строки в C заканчиваются NUL. Это означает, что строке из двух символов требуется три байта (два для символов и третий для нулевого байта, обозначающего конец строки).

В вашем примере можно опустить размер массива, и компилятор выделит правильный объем памяти:

char IP[] = "192.168.2.1";
char separator[] = "||";

Наконец, если вы кодируете на C ++, а не на C, вам лучше использовать std::string.

13 голосов
/ 04 мая 2011

Если вы все равно используете C ++, я бы порекомендовал использовать класс std :: string вместо строк C - гораздо проще и менее подвержен ошибкам IMHO, особенно для людей с фоном языка сценариев.

4 голосов
/ 04 мая 2011

В конце каждой строки есть скрытый нулевой символ '\ 0'. Вы должны оставить место для этого.

Если вы делаете

char seperator[] = "||";    

вы получите строку размера 3, а не размера 2.

3 голосов
/ 04 мая 2011

Потому что в C строки nul заканчиваются (их конец отмечен 0 байтом). Если вы объявляете разделитель массивом из двух символов и задаете им оба ненулевых значения, тогда терминатора нет! Поэтому, когда вы puts массиве почти все может быть прикреплено к концу (что бы ни находилось в памяти после конца массива - в этом случае, кажется, что это массив IP).

Редактировать: это следующее неверно. См. Комментарии ниже.

Когда вы делаете массив длиной 3, в дополнительном байте оказывается 0, что завершает строку. Однако вы, вероятно, не можете полагаться на это поведение - если значение неинициализировано, оно может действительно содержать что угодно.

2 голосов
/ 04 мая 2011

Поскольку до сих пор никто не указал на это: если вы объявите свою переменную таким образом, строки будут автоматически заканчиваться нулем, и вам не придется возиться с размерами массива:

const char* IP = "192.168.2.1"; 
const char* seperator = "||";

Обратите внимание, что я предполагаю, что вы не собираетесь изменять эти строки.

Но, как уже упоминалось, безопасным способом в C ++ было бы использование класса std :: string.

2 голосов
/ 04 мая 2011

В C строки содержат (невидимый) нулевой байт в конце. Вы должны учитывать этот нулевой байт.

char ip[15] = "1.2.3.4";

в коде выше, ip имеет достаточно места для 15 символов. 14 «обычных символов» и нулевой байт. Это слишком коротко: должно быть char ip[16] = "1.2.3.4";

ip[0] == '1';
ip[1] == '.';
/* ... */
ip[6] == '4';
ip[7] == '\0';
2 голосов
/ 04 мая 2011

В C строки заканчиваются специальным символом '\0', поэтому ваш литерал-разделитель "||" фактически на один символ длиннее. puts Функция просто печатает каждый символ, пока не встретит '\0' - в вашем случае один после строки IP.

1 голос
/ 04 мая 2011

Строка в C \ C ++ заканчивается нулем, то есть имеет скрытый ноль в конце.

Итак, ваша строка-разделитель будет:

{'|', '|', '\0'} = "||"
1 голос
/ 04 мая 2011

Линия: char seperator[2] = "||"; должно привести к неопределенному поведению, поскольку длина этого массива символов (включая ноль в конце) будет 3.

Кроме того, с каким компилятором вы скомпилировали приведенный выше код? Я скомпилировал с помощью g ++, и он пометил вышеуказанную строку как ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...