2012-02-07 3 views
2
for(int i=0;i<10;i++) 
{ 
    cout << i+"passs" << "\n"; 
} 

Это производит вывод следующим образом:Почему это ИНТ и конкатенация дать этот вывод в C++

passs 
asss 
sss 
ss 
s 

Теперь мое мышление является то, что мы видим манипуляции указателя, где счетчик я добавляется к проходит мимо char pointer, и мы видим вывод из указателя «passs» + 0, «passs» pointer + 1 и т. д.

Вопрос: почему он не останавливается, когда он достигает нулевого символа, поскольку он печатает 5 пустых строк.

Далее cout << "passs"+i << "\n"; печатает то же самое. Я думал, что это должно было напечатать все пустые строки со второй позиции, так как на этот раз указатель проходов должен был быть, вероятно, из последней позиции. При чтении того, что я написал здесь, вероятно, имеет смысл увидеть, что выход для второго cout будет таким, каким он есть.

Я хотел знать, правильно ли я думаю, и если есть еще что-то, что я не понял?

+0

Как вы поняли, это не «конкатенация». Таким образом, заголовок вопроса заставляет вас выглядеть более смущенными, чем вы на самом деле ;-) –

+0

@Steve lol, должно быть правильно написано – gizgok

ответ

2

Ваши первоначальные рассуждения верны. Вы делаете арифметику указателей здесь, поэтому первые шесть строк (шестой - \0\n) вывода хороши. Но вы попадаете в неприятности, когда вы уходите от конца строки. В вашем for-loop ничего нет, чтобы остановить итерацию, поэтому ваша программа теоретически могла бы что-либо сделать с "passs" + 6, 7, 8 и 9. Давайте рассмотрим, почему.

Напомним, что строковый литерал имеет тип const char *. На каком-то месте в памяти определяется компилятором, то есть:

| p | a | s | s | s | \0 | * | * | * | * | 

В * символы представляют собой ничейную землю по неопределенному памяти мимо конца вашей строки. Когда ваш цикл работает, он начинается с p и идет вперед. Поскольку мы обращаемся к const char *, каждый шаг будет одним байтом. На каждом шаге cout пытается напечатать столько, сколько может, пока не достигнет нулевого символа (как вы видите на выходе). Но вам не разрешают ничего печатать на ничейной земле. Результатом этого является неопределенное поведение. В вашем случае эта память содержит непечатаемые символы.

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

+0

«вам не разрешено печатать что-либо из ничейной земли. Это приводит к неопределенному поведению. " - просто * создание указателя * приводит к неопределенному поведению. Мотивация для этого состоит в том, что (1) память для «проходов» может просто оказаться в самом конце адресного пространства, так что добавление 6 к ней приводит к переполнению, и (2) C++ стремится разрешить древние и своеобразные архитектуры, на которых переполнение указателя приводит к аппаратной ошибке (хотя и не unsigned int overflow, которая должна обернуться). Итак, '6 +" проходит "' это UB, печатаете ли вы его или нет. –

+0

Я думал, что вы гарантированно сможете адресовать (но не разыгрывать) один конец прошлого, чтобы поддерживать стандартные библиотечные алгоритмы. Таким образом, наличие указателя на +6 в этом случае в порядке, но с точностью до +7 до +9. Во всяком случае, это хороший момент, спасибо за то, что он поднял его. –

+0

Извините, вы правы, я должен был сказать 7 вместо 6 в двух местах в моем комментарии. Это означает, что, как вы говорите, «первый» UB в цикле опроса является разыменованием «6 +» passs ». «следующий» UB вычисляет «7 +» passs ». –

2

Это потому, что строковый литерал рассматривается как указатель (указатель арифметика): добавление целое в указатель перемещается вперед указатель:

"passs" + 1 = "asss" 
"passs" + 2 = "sss" 
"passs" + 3 = "ss" 

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

cout << i << "passs" << "\n"; 
2

Вы правы, и pointer + integer, и integer + pointer работают с указателем арифметики и дают новый указатель, и, следовательно, выход «нормальный».

4

Вы правы.

Строковый литерал интерпретируется как указатель на начало строки. Добавление int к этому - увеличение указателя.

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

Смежные вопросы