Струнда сходит с ума, если я не дам ему немного дополнительной комнаты. Может ли кто-нибудь объяснить, что здесь происходит?
Во-первых, я хотел бы сказать, что я новичок в C/С++, я изначально являюсь разработчиком PHP, поэтому меня разводят, чтобы злоупотреблять переменными любым способом, который мне нравится.
C - строгая страна, компиляторы мне не очень нравятся, я привык нарушать правила, чтобы все было сделано.
Во всяком случае, это мой простой кусок кода:
char IP[15] = "192.168.2.1";
char separator[2] = "||";
puts( separator );
Вывод:
||192.168.2.1
Но если я изменил определение separator
на:
char separator[3] = "||";
Я получаю желаемый результат:
||
Итак, почему мне нужно было дать человеку дополнительное пространство, чтобы он не спал с человеком перед ним?
Ответы
Ответ 1
Это потому, что вы получаете строку с нулевым завершением, когда длина separator
принудительно равна 2.
Всегда помните, чтобы выделить дополнительный символ для нулевого терминатора. Для строки длины N
вам нужны символы N+1
.
Как только вы нарушите это требование, любой код, который ожидает строки с нулевым завершением (включенная функция puts()
), будет работать в undefined.
Лучше всего не форсировать определенную длину:
char separator[] = "||";
выделит массив точно соответствующего размера.
Ответ 2
Строки в C заканчиваются NUL. Это означает, что для строки из двух символов требуются три байта (два для символов и третий для нулевого байта, обозначающий конец строки).
В вашем примере можно опустить размер массива, и компилятор выделит правильную сумму хранения:
char IP[] = "192.168.2.1";
char separator[] = "||";
Наконец, если вы кодируете С++, а не C, вам лучше использовать std::string
.
Ответ 3
Если вы все равно используете С++, я бы рекомендовал использовать класс std::string вместо строк C - намного проще и менее подвержен ошибкам IMHO, особенно для людей с языком сценариев.
Ответ 4
В конце каждой строки есть скрытый нулевой символ '\ 0'. Вы должны оставить для этого пространство.
Если вы делаете
char seperator[] = "||";
вы получите строку размера 3, а не размер 2.
Ответ 5
Потому что в строках C nul завершается (их конец помечен 0 байтом). Если вы объявляете разделитель как массив из двух символов и даете им оба ненулевых значения, то нет терминатора! Поэтому, когда вы puts
массив почти все можно было бы привязать к концу (что бы ни случилось, когда он сидит в памяти за концом массива), в этом случае кажется, что это массив IP
).
Изменить: это неверно. См. комментарии ниже.
Когда вы создаете длину массива 3, у дополнительного байта в нем есть 0, что завершает строку. Однако вы, вероятно, не можете полагаться на это поведение - если значение не инициализировано, оно может действительно содержать что-либо.
Ответ 6
В строках C заканчивается специальный символ '\0'
, поэтому ваш разделительный литерал "||"
на самом деле один символ длиннее. Функция puts
просто печатает каждый символ, пока не встретит '\0'
- в вашем случае один после строки IP.
Ответ 7
В 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';
Ответ 8
Поскольку никто не указал на это до сих пор: если вы объявите свою переменную как это, строки будут автоматически завершаться нулями, и вам не нужно будет вмешиваться в размеры массива:
const char* IP = "192.168.2.1";
const char* seperator = "||";
Обратите внимание, однако, что я предполагаю, что вы не собираетесь изменять эти строки.
Но, как уже упоминалось, безопасный способ в С++ будет использовать класс std::string.
Ответ 9
A C "String" всегда заканчивается в NULL, но вы просто не передаете его в строку, если вы пишете
char разделитель [2] = "||". И puts ожидает, что этот \0 на ned в первом случае он пишет до тех пор, пока не найдет \0, и здесь вы можете увидеть, где он находится в конце IP-адреса. Интересный enoiugh вы даже можете увидеть, как локальные переменные выкладываются в стеке.
Ответ 10
Линия: char seperator[2] = "||"
; должен получить вам поведение undefined, так как длина этого массива символов (включая нуль в конце) будет равна 3.
Кроме того, с компилятором вы скомпилировали вышеуказанный код? Я скомпилировал с g++, и он отметил указанную выше строку как ошибку.
Ответ 11
String в C\С++ завершают нуль, т.е. имеют скрытый нуль в конце.
Итак, ваша строка разделителя будет:
{'|', '|', '\0'} = "||"