Консультация № 191147
13.06.2017, 18:33
0.00 руб.
0 12 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:
Читаю учебник по С++, встретила следующее выражение:
while( *p1++ = *p2++ ){}.
Я читаю это так:
- берем значение по адресу, на которое указывает p2
- увеличиваем на единицу
- присваиваем полученное вместо значения по адресу p1
- p1 увеличиваем на единицу...
Сомневаюсь, что я права. Посмотрите, пожалуйста!

Обсуждение

давно
Посетитель
7438
7205
13.06.2017, 18:59
общий
это ответ
Здравствуйте, pNod!
- берем значение по адресу, на которое указывает p2
- увеличиваем на единицу указатель p2
- присваиваем полученное вместо значения по адресу p1
- p1 увеличиваем на единицу...
- продолжаем копировать байты, пока записанный байт не будет равен 0x00,
т.о., мы скопируем строку вместе с завершающим нулем.
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401172
78
13.06.2017, 19:32
общий
13.06.2017, 19:33
Игорь Витальевич, спасибо, можно на примере для понимания?:
char FI[2] = { a, b };
char *p1, *p2;
p1 = NULL;
p2 = FIO;
while( *p1++ = *p2++ )
{
cout << p1;
}

Получается:
- берем адрес a
- записываем в указатель p1
- печатаем a
- p2 увеличиваем на единицу, т.е. сдвигаем на один char и он сейчас указывает на b
- p1 также увеличиваем на единицу, т.е. сдвигаем на один char... в этот момент здесь пусто или мусор?
- берем b
- записываем в указатель p1
- печатаем b
- p2 увеличиваем на единицу, т.е. сдвигаем на один char и он сейчас указывает на завершающий ноль
- цикл завершен когда в p1 запишется завершающий ноль?
давно
Посетитель
7438
7205
13.06.2017, 19:56
общий
14.06.2017, 10:29
Адресаты:
char FI[3] = { 'a', 'b', 0 }; //во-первых, если a и b - символы, а не define-ы, то надо брать в кавычки,
//во-вторых, мы хотим копировать строку, а не массив байт, в конце нужен 0
char s[256];
char *p1, *p2;
p1 = s; //просто NULL нельзя, памяти-то нет, будет вылет. Надо дать либо адрес массива символов, либо запросить динамическую память
p2 = FI; //теперь p2 - указатель на массив FI
//можно было записать и так:
p2 = "ab"; //без массива FI

/* так писать нельзя, копируем побайтно, и пытаемся вывести всю строку (у которой предполагается в конце 0!)
while( *p1++ = *p2++ )
{
cout << p1;
}
*/
//делаем так:
while( *p1++ = *p2++ ); //сначала скопируем всю строку
cout << s; //затем строку выводим

Получается:
- берем символ по адресу p2
- записываем по адресу, куда указывает указатель p1
- p2 увеличиваем на единицу, т.е. сдвигаем на один char и он сейчас указывает на b
- p1 также увеличиваем на единицу, т.е. сдвигаем на один char... в этот момент здесь пусто или мусор? (считаем, что мусор)
- проверяем символ на 0, если не 0, то продолжаем копировать
- цикл будет завершен, когда копируемый символ будет равен ноль
- выводим всю строку
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401172
78
13.06.2017, 20:08
общий
Теперь все ясно, спасибо! Столько ошибок понаделала в таком маленьком примере, стыдно
давно
Посетитель
7438
7205
13.06.2017, 20:13
общий
Адресаты:
Стыдно не хотеть учиться. Ошибки - дело поправимое.
Обращайтесь, если что
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401172
78
13.06.2017, 20:14
общий
Спасибо!
давно
Посетитель
7438
7205
14.06.2017, 10:33
общий
Адресаты:
Небольшая неточность во фрагменте:
Код:
while( *p1++ = *p2++ ); //сначала скопируем всю строку
cout << p1; //затем строку выводим
Дело в том, что указатель p1 в конце копирования строки будет указывать
на завершающий 0. Чтобы вывести полученную строку, надо указать начальный адрес строки, т.е. s
Код:
cout << s;
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401172
78
14.06.2017, 16:40
общий
Да, точно, указатель же сдвинулся при копировании до завершающего нуля!

Игорь Витальевич, а вот по поводу этого фрагмента:

Цитата: Лысков Игорь Витальевич
/* так писать нельзя, копируем побайтно, и пытаемся вывести всю строку (у которой предполагается в конце 0!)
while( *p1++ = *p2++ )
{
cout << p1;
}


интересно в Си можно было бы так побайтно символы вывести:

while( *p1++ = *p2++ )
{
printf("%с\n", p1);
}

скопировал - напечатал...?
давно
Посетитель
7438
7205
14.06.2017, 16:49
общий
14.06.2017, 16:50
Адресаты:
Да все можно. Только не надо забывать, что p1 после сохранения очередного байта указывает на следующий символ
Код:
	while( *p1++ = *p2++ )
{
printf("%c", *(p1-1));
}
Ну или так:
Код:
cout << *(p1-1);
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Академик
20764
1861
14.06.2017, 17:00
общий
Строго говоря, это не совсем так. Гарантируется только то, что адреса значений источника и приёмника будут вычислены до того, как будут подвинуты указатели. Но компилятор все остальные действия волен задавать в любом порядке. Например, сначала будет присвоено, а уже потом подвинуты оба указателя.
В данном случае это несущественно, но всякие трюки (например, когда в обеих частях один и тот же указатель) могут плохо кончится.
давно
Посетитель
7438
7205
14.06.2017, 17:05
общий
Адресаты:
В трюкачество вдаваться не будем...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401172
78
14.06.2017, 17:28
общий
Аааа...понятно, использовать такой вариант не буду, раз нет уверенности в том, что находится в данный момент по адресу и что думает по этому поводу конкретный компилятор.
Лучше проще, но лучше!
Форма ответа