2009-10-17 1 views
4

const char * src = "hello";Выделить номер для символа с нулевым завершающим символом при копировании строк в C?

Вызов strlen(src); возвращает размер 5 ...

Теперь говорят, что я это сделать:

char* dest = new char[strlen(src)]; 
strcpy(dest, src); 

Это не кажется, что это должно работать, но когда я все выводится это выглядит правильно. Кажется, я не выделяю пространство для нулевого терминатора на конце ... это правильно? Спасибо

ответ

13

Вы правы, что вы не занимаете место для терминатора, однако отказ сделать это не обязательно приведет к сбою вашей программы. Вы можете переписывать следующую информацию о куче, или ваш менеджер кучи будет округлять размер выделения до кратного 16 байтов или что-то в этом роде, так что вы не обязательно увидите какой-либо видимый эффект этой ошибки.

Если вы запустите свою программу под номером Valgrind или другим отладчиком кучи, вы можете обнаружить эту проблему раньше.

+1

haha ​​спасибо, мне, должно быть, повезло ... это не показалось правильным, когда я это делал. – Polaris878

+1

Я бы сказал, что вам не повезло. В идеале это woudl ВСЕГДА вызывает ошибку, но, к сожалению, в реальном мире некоторые ошибки не появляются сразу. – Dolphin

11

Да, вы должны выделить не менее strlen (src) +1 символов.

7

Это не похоже, что он должен работать, но когда я выводю все, все выглядит правильно.

Добро пожаловать в мир Undefined Behavior. Когда вы это сделаете, все может случиться. Ваша программа может потерпеть крах, ваш компьютер может потерпеть крах, ваш компьютер может взорваться, demons can fly out of your nose.

И, что самое страшное, ваша программа может работать просто отлично, незаметно выглядит так, как будто она работает правильно, пока в один прекрасный день она не начнет выплескивать мусор, поскольку она переписывает важные данные где-то из-за того, что где-то кто-то выделил слишком мало символов для их массивы, и теперь вы испортили кучу, и вы получаете segfault в какой-то момент на расстоянии в миллион миль, или еще хуже, ваша программа с удовольствием сочетается с поврежденной кучей, и ваши функции работают на поврежденных номерах кредитных карт, и вы получаете огромные проблемы.

Даже если это похоже на работу, это не так. Это неопределенное поведение. Избегайте этого, потому что вы никогда не можете быть уверены, что он будет делать, и даже когда то, что он делает, когда вы попробуете, все в порядке, на другой платформе это может быть нехорошо.

+0

+1 только для ссылки на файл жаргонов ... ahh ... memories –

1

В качестве альтернативы вы также можете использовать dest = strdup (src), который выделяет достаточное количество памяти для строки + 1 для нулевого терминатора (+1 для ответа Джулиано).

+3

И еще раз я делаю «Обратите внимание, что' strdup() 'является нестандартной функцией и может не быть доступной на какой-либо данной платформе» комментарий , –

+0

Спасибо, Крис, отличный момент. – Paradigm

3

Лучшее описание я прочитал (был на StackOverflow) и пошел, как это:

Если ограничение скорости 50 и вы едете на 60. Вы можете получить повезло и не получить билет, но в один прекрасный день может быть не сегодня, может быть, не завтра, а в один прекрасный день этот полицейский будет ждать вас. В тот день вы заплатите, и вы заплатите дорого.

Если кто-то может найти оригинал, я бы скорее упомянул, что они были гораздо более красноречивыми, чем мои объяснения.

+0

По крайней мере, в этом случае вы знаете __why__ вы платите дорого. В случае C вы можете увидеть «случайные» сбои или изменения в логике, и первопричина не всегда легко найти. –

1

Вот почему вы всегда должны всегда запускать valgrind в любой программе на C, которая, кажется, работает.

1

Да, все накрыли главный пункт; вы не можете потерпеть неудачу. Дело в том, что нулевой ограничитель обычно равен 0, а 0 - довольно распространенное значение для сидения в любом конкретном адресе памяти. Так что это просто сработает. Вы можете протестировать это, взяв набор памяти, наложив на него кучу мусора, а затем напишите эту строку и попытайтесь с ней работать.

Во всяком случае, главная проблема, которую я вижу в том, что вы говорите о C, но у вас есть эта строка кода:

char* dest = new char[strlen(src)]; 

Это не будет компилировать в любом стандартном C компилятором. Нет ключевого слова new в C. Это C++. В C вы должны использовать одну из функций выделения памяти, обычно malloc. Я знаю, что это кажется nitpicy, но на самом деле это не так.

+0

Нет, его вопрос также четко обозначен C++. Это просто его вопрос, который упоминает C (также тот факт, что 'strlen()' и 'strcpy()' являются функциями C). Распределение не важно - важной частью является некорректная длина размещения и неопределенное поведение. –

+0

@ Крис Лутц, я не уверен, что вы имеете в виду ... Название вопроса: «Выделить номер для нулевого завершающего символа при копировании строк в C?» Сегодня я видел пару вопросов о том, как использовать «новый» в C, поэтому я просто подумал, что хочу указать на это, чтобы избежать путаницы для тех, кто читает этот поток SO, который может быть новым для языка программирования C. – BobbyShaftoe

+0

Я думаю, что многие люди говорят о C и C++ взаимозаменяемо, потому что существует так много перекрытий между языками. Я знаю, что я был виновен в ссылке на C, когда я действительно имел в виду C++. Эти два дополнительных слога просто нужно сказать. –

2

strcpy скопирует нулевой завершающий символ, а также все остальные символы.

Таким образом, вы копируете длину hello + 1, которая 6 в размер буфера, который 5.

У вас есть переполнение буфера, хотя здесь и overwiting память, которая не ваша, будет иметь неопределенные результаты.