Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
dima__
0 / 0 / 0
Регистрация: 29.03.2014
Сообщений: 20
#1

Присвоение в условии цикла while

01.07.2014, 12:48. Просмотров 1483. Ответов 13
Метки нет (Все метки)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
void main ()
{
      char a[140],b[140],*pa=a,*pb=b;
      /* -------------------------------- */
      cout << "Enter word..."; gets(a);
      int pr = 2*strlen(a);
      *(pb+pr+1) = '\0';
      while  ((*pb = *pa)!='\0')
      {
         pb++; 
        *pb++ = *pa++;
      }
      cout << "\n Result:"; puts(b);
}

Доброе время суток! Подскажите, каким образом работает while ((*pb = *pa)!='\0') , по типу логического выражения? если можно присвоить указателю pb значение указателя pa, тогда true? И нет разницы писать pb++ или *pb++? Заранее спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.07.2014, 12:48
Ответы с готовыми решениями:

Ошибка в условии цикла
Кароч пишу крестики-нолики и тут на пути появилась непонятная ошибка int...

Операторы в условии выполнения цикла while
do{ m = atof(p); if (i&gt;9) break; }while(p = strchr(p, ','), p++); ...

Логическое ИЛИ в условии цикла while
Доброго времени суток. Комрады, ситуация следующая, цикл должен завершатся...

Битовая инверсия переменной в условии цикла for
Доброго времени суток. Возможно ли ещё как-то использовать/применять...

При любом условии вылетает из цикла
while(str.empty()==false){ cout&lt;&lt;&quot;выберите операцию&quot;&lt;&lt;endl&lt;&lt;&quot;1.Добавить...

13
castaway
Эксперт С++
4929 / 3036 / 453
Регистрация: 10.11.2010
Сообщений: 11,116
Записей в блоге: 10
Завершенные тесты: 1
01.07.2014, 13:03 #2
Значение *pa присваивается *pb, и если оно не равно нулю то цикл продолжается.
0
dima__
0 / 0 / 0
Регистрация: 29.03.2014
Сообщений: 20
03.08.2014, 16:43  [ТС] #3
а если написать просто while (( *pa)!='\0') ведь, насколько я понял, цикл должен работать пока исходная строка не закончится, то почему-то не получается. Какую роль играет присвоение *pb = *pa?
0
sourcerer
Модератор
Эксперт CЭксперт С++
4832 / 2023 / 315
Регистрация: 20.02.2013
Сообщений: 5,443
Записей в блоге: 24
Завершенные тесты: 1
03.08.2014, 16:50 #4
Цитата Сообщение от dima__ Посмотреть сообщение
И нет разницы писать pb++ или *pb++?
Есть, и существенная.
0
GetHelp
60 / 61 / 11
Регистрация: 27.02.2013
Сообщений: 1,112
03.08.2014, 16:52 #5
Цитата Сообщение от dima__ Посмотреть сообщение
И нет разницы писать pb++ или *pb++?
pb++ увеличивает значение указателя (сдвигает его)
*pb++ увеличивает значение переменной записанной по адресу куда указывает указатель
0
sourcerer
Модератор
Эксперт CЭксперт С++
4832 / 2023 / 315
Регистрация: 20.02.2013
Сообщений: 5,443
Записей в блоге: 24
Завершенные тесты: 1
03.08.2014, 17:01 #6
Цитата Сообщение от dima__ Посмотреть сообщение
И нет разницы писать pb++ или *pb++?
Если Вы пишите в коде pb - то это адрес той переменной, на которую указывает указатель pb. А если Вы пишите в коде *pb - то это значение, которое лежит в той переменной, на которую указывает указатель pb. Соответственно, инкремент адреса (то есть запись в коде pb++) даст смещение на одну позицию в массиве (поскольку в Вашем случае изначально указатель ссылается на первый элемент массива), а инкремент значения даст прибавку единицы к тому значению, которое лежит в переменной, на которую указывает указатель.

Добавлено через 5 минут
Чтобы было понятнее, вот Вам простой пример из книги Стивена Праты:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// pointer.срр -- наша первая переменная-указатель
 
#include <iostream> 
int main() 
{ 
    using namespace std;
     
    int updates =6;         // объявление переменной 
    int * p_updates;        // объявление указателя на int 
    p_updates = &updates;   // присвоить адрес int указателю
    
    // Выразить значения двумя способами:
    cout << "Values: updates = " << updates; 
    cout << ", *p_updates = " << *p_updates << endl;
    
    // Выразить адреса двумя способами:
    cout << "Addresses: &updates = " << &updates; 
    cout << ", p_updates = " << p_updates << endl;
    
    // Изменить значение через указатель:
    *p_updates = *p_updates + 1;
     
    cout << "Now updates = " << updates << endl;
     
    return 0;
}
0
Миниатюры
Присвоение в условии цикла while  
sourcerer
Модератор
Эксперт CЭксперт С++
4832 / 2023 / 315
Регистрация: 20.02.2013
Сообщений: 5,443
Записей в блоге: 24
Завершенные тесты: 1
03.08.2014, 17:07 #7
И вот ещё из той же книги про указатели и массивы:
Кликните здесь для просмотра всего текста

Цитата Сообщение от Стивен Прата
Родство указателей и имен массивов происходит из арифметики указателей, а также
того, как язык C++ внутренне работает с массивами. Сначала рассмотрим арифметику
указателей. Добавление единицы к целочисленной переменной увеличивает ее
значение на единицу, но добавление единицы к переменной типа указателя увеличивает ее
значение на количество байт, составляющих размер типа, на который она указывает.
Добавление единицы к указателю на double добавляет 8 байт к числовой величине
указателя на системах с 8-байтным double, в то время как добавление единицы к
указателю на short добавляет к его значению 2 байта. Код в листинге 4.19 доказывает
истинность этого утверждения. Он также демонстрирует еще один важный момент:
C++ интерпретирует имена массивов как адреса.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Листинг 4.19. addpntrs.cpp -- pointer addition
#include <iostream>
int main()
{
    using namespace std;
    double wages[3] = {10000.0, 20000.0, 30000.0};
    short stacks[3] = {3, 2, 1};
 
// Here are two ways to get the address of an array
    double * pw = wages;     // name of an array = address
    short * ps = &stacks[0]; // or use address operator
// with array element
    cout << "pw = " << pw << ", *pw = " << *pw << endl;
    pw = pw + 1;
    cout << "add 1 to the pw pointer:\n";
    cout << "pw = " << pw << ", *pw = " << *pw << "\n\n";
 
    cout << "ps = " << ps << ", *ps = " << *ps << endl;
    ps = ps + 1;
    cout << "add 1 to the ps pointer:\n";
    cout << "ps = " << ps << ", *ps = " << *ps << "\n\n";
 
    cout << "access two elements with array notation\n";
    cout << "stacks[0] = " << stacks[0] 
         << ", stacks[1] = " << stacks[1] << endl;
    cout << "access two elements with pointer notation\n";
    cout << "*stacks = " << *stacks
         << ", *(stacks + 1) =  " << *(stacks + 1) << endl;
 
    cout << sizeof(wages) << " = size of wages array\n";
    cout << sizeof(pw) << " = size of pw pointer\n";
    // cin.get();
    return 0; 
}
0
Mr.X
Эксперт С++
3178 / 1705 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
03.08.2014, 17:52 #8
Цитата Сообщение от GetHelp Посмотреть сообщение
*pb++ увеличивает значение переменной записанной по адресу куда указывает указатель
Цитата Сообщение от gru74ik Посмотреть сообщение
Если Вы пишите в коде pb - то это адрес той переменной, на которую указывает указатель pb. А если Вы пишите в коде *pb - то это значение, которое лежит в той переменной, на которую указывает указатель pb. Соответственно, инкремент адреса (то есть запись в коде pb++) даст смещение на одну позицию в массиве (поскольку в Вашем случае изначально указатель ссылается на первый элемент массива), а инкремент значения даст прибавку единицы к тому значению, которое лежит в переменной, на которую указывает указатель.
Постфиксные операторы имеют приоритет над префиксными, поэтому в выражении *pb++ инкрементируется указатель.
0
GetHelp
60 / 61 / 11
Регистрация: 27.02.2013
Сообщений: 1,112
03.08.2014, 18:10 #9
Цитата Сообщение от Mr.X Посмотреть сообщение
Постфиксные операторы имеют приоритет над префиксными, поэтому в выражении *pb++ инкрементируется указатель.
не думаю, вы же не станете спорить что ++pb выполнится раньше чем pb++?
0
sourcerer
Модератор
Эксперт CЭксперт С++
4832 / 2023 / 315
Регистрация: 20.02.2013
Сообщений: 5,443
Записей в блоге: 24
Завершенные тесты: 1
03.08.2014, 18:27 #10
Вот, попытался разобраться с Вашим кодом:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
 
using namespace std;
int main ()
{
      char a[140], b[140];
 
      char * pa=a;  // указатель pa теперь будет указывать
                    // на первый элемент массива a[]
 
      char * pb=b;  // указатель pb теперь будет указывать
                    // на первый элемент массива b[]
 
      /* -------------------------------- */
      cout << "Enter word: ";
      gets(a);  // функция для чтения строк в стиле C (сишный аналог плюсового cin)
      int pr = 2 * strlen(a);   // узнаём длину строки a[], умножаем её на 2
                                // и присваиваем получившееся значение
                                // переменной pr
      *(pb+pr+1) = '\0';    // массив b теперь будет вдвое длиннее массива а
                            // и последним символом массива b будет символ \0
                            // что сделает его строкой в стиле С
                            
      while  ((*pb = *pa)!='\0')
      // Запись (*pb = *pa)!='\0' означает: сохранить значение, на которое
      // указывает указатель pa в переменную, на которую указывает указатель pb,
      // и если это значение не символ \0, то продолжить цикл
      {
         pb++;  // перейти к следующему элементу массива b[]
         
        *pb++ = *pa++;  // Сперва происходит разыменование указателя pb,
                        // затем инкремент указателя pb - теперь pb будет
                        // указывать на следующий элемент массива b[]. Затем
                        // то же самое происходит с указателем pa: происходит
                        // разыменование указателя pa, затем инкремент указателя 
                        // pa - теперь pa будет указывать на следующий элемент
                        // массива a[]. Затем присваиваем значение, на которое
                        // указывает теперь указатель pa, элементу массива, на
                        // который теперь указывает указатель pb.
                        
      }
      cout << "\n Result: ";
      puts(b);  // Вывести строку b на экран (сишный аналог плюсового cout)
 
      return 0;
}
0
Mr.X
Эксперт С++
3178 / 1705 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
03.08.2014, 19:03 #11
Цитата Сообщение от gru74ik Посмотреть сообщение
*pb++ = *pa++; // Сперва происходит разыменование указателя pb, // затем инкремент указателя pb - теперь pb будет // указывать на следующий элемент массива b[]. Затем // то же самое происходит с указателем pa: происходит // разыменование указателя pa, затем инкремент указателя // pa - теперь pa будет указывать на следующий элемент // массива a[]. Затем присваиваем значение, на которое // указывает теперь указатель pa, элементу массива, на // который теперь указывает указатель pb.
Немножко наоборот. Сначала происходит присваивание значений, а потом инкременты указателей.

Добавлено через 10 минут
Цитата Сообщение от GetHelp Посмотреть сообщение
не думаю
А чего тут думать, учить надо. И первое - это выучить таблицу приоритетов операторов наизусть, так как в C++ их количество сравнимо с количеством ключевых слов, чтобы не ставить лишних скобок и не затрудняться при чтении кода. В Си приоритет операторов неплохо продуман, так что скобки ставить почти не приходится.

Добавлено через 8 минут
Вот все ругаем Страуструпа, а для кого он целую страницу отвел для разбора этого выражения в пункте 6.2.5.?
0
sourcerer
Модератор
Эксперт CЭксперт С++
4832 / 2023 / 315
Регистрация: 20.02.2013
Сообщений: 5,443
Записей в блоге: 24
Завершенные тесты: 1
03.08.2014, 19:07 #12
Цитата Сообщение от Mr.X Посмотреть сообщение
Сначала происходит присваивание значений, а потом инкременты указателей.
А я чё сказал? Я так и сказал - сперва разыменование указателей (разыменование - операция взятия значения, то что со звёздочкой там), потом инкремент, потом присваивание одной части выражения другому.
0
Mr.X
Эксперт С++
3178 / 1705 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
03.08.2014, 19:11 #13
Цитата Сообщение от gru74ik Посмотреть сообщение
А я чё сказал? Я так и сказал - сперва разыменование указателей (разыменование - операция взятия значения, то что со звёздочкой там), потом инкремент, потом присваивание одной части выражения другому.
Ну, если строго, то сначала инкремент, так как он имеет наивысший приоритет, но, так как он постфиксный, то в выражении используются старые значения указателей, затем разыменование и присваивание старых значений.
0
dima__
0 / 0 / 0
Регистрация: 29.03.2014
Сообщений: 20
03.08.2014, 22:36  [ТС] #14
Цитата Сообщение от gru74ik Посмотреть сообщение
while *((*pb = *pa)!='\0')
* * * // Запись (*pb = *pa)!='\0' означает: сохранить значение, на которое
* * * // указывает указатель pa в переменную, на которую указывает указатель pb,
* * * // и если это значение не символ \0, то продолжить цикл
Маленький уточняющий вопрос - выражение while (( *pa)!='\0') вставленное вместо ((*pb = *pa)!='\0') делает код нерабочим. Но почему? Ведь и в первом и во втором случае цикл должен остановиться когда *pa = '\0'?
0
03.08.2014, 22:36
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.08.2014, 22:36

Вычисление арифметических выражений в условии цикла с параметром
Здравствуйте! Объясните, пожалуйста. Уже, вроде, кучу сайтов перечитал, но так...

Нюансы синтаксиса: что значит std::cin в условии цикла while?
do { int v1, v2; cout &lt;&lt; &quot;Please enter two numbers of sum:&quot;; if (cin...

Применение цикла if для определения простых чисел. If внутри цикла for
Доброго времени суток, подскажите пожалуйста, в чем тут дело. С кодом все...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru