Еще один вопрос с указателем C - PullRequest
1 голос
/ 02 сентября 2010

Я подумал, что действительно начинаю понимать, как работают указатели, и затем я наткнулся на это упражнение. Я пытался воссоздать кусок кода, который я нашел в своей книге «Learn C», и я сделал это, и это работало, и я думал, что все было здорово:

void PrintWords( char *line ) {

    bool inWord = false;

    while (*line != kByteZero) {

        if (! isspace(*line)) {

            if (inWord == false) {
                putchar('\n');
                inWord = true;

            }
            putchar(*line);
        } else {
            inWord = false; 
        }
        *line++;
    }
}

Это простая функция, которая отображает слова массива в отдельных строках. Когда я сравнил его с кодом в книге, я увидел одно явное отличие. Последняя строка в коде книги была «line ++» вместо «* line ++».

Я думал, что использование 'line ++' является ТОЧНОЙ противоположностью того, что мы пытаемся здесь сделать. Я пытаюсь увеличить, где указатель указывает, а также манипулировать файлами, хранящимися по этому адресу памяти. 'line ++' кажется ОЧЕНЬ странным для меня, потому что я даже не уверен, что он говорит коду? Перейти от строки [i] к строке [i + 1] ?? Это кажется странным, потому что тогда сама «строка», кажется, просто действует как указатель - и если это так, почему я не могу заменить каждый экземпляр * строки просто «строкой»?

Ответы [ 5 ]

9 голосов
/ 02 сентября 2010

В этом случае *line++ и line++ абсолютно одинаковы. Постфикс ++ имеет более высокий приоритет, чем *. Вы можете заменить свой код на:

*(line++)

То, что довольно легко увидеть, не нужно. Программа, которую вы показываете здесь, делает именно то, что вы говорите - она ​​хочет увеличить указатель, чтобы он указывал на следующий символ, чтобы затем проверить его и напечатать или новую строку. Вы хотите, чтобы line ссылался на указатель, а *line на разыменовывал указатель и получал все, на что он указывает.

Я только что провел быстрый тест с вашим кодом. Я получаю предупреждение от gcc "вычисленное значение не используется" с *.

3 голосов
/ 02 сентября 2010

Перейти от строки [i] к строке [i + 1] ??

Да, это именно то, что line++; означает в примере.
Смотрите, указательэто не что иное, как переменная, значение которой используется для обозначения позиции в памяти.Скажем, у вас есть это в памяти:

position | value 
    0    |   H
    1    |   e
    2    |   l
    3    |   l
    4    |   o

Теперь скажите, что у нас есть line = 0;
Тогда *line будет H.
Если мы сделаем line++;, lineтеперь 1, что означает *line сейчас e.Если сейчас мы сделаем (*line)++, то вы фактически измените значения в памяти, которые будут:

position | value 
    0    |   H
    1    |   f
    2    |   l
    3    |   l
    4    |   o
2 голосов
/ 02 сентября 2010

line - указатель.line++ будет увеличивать указатель, т.е. сдвигать его к следующему символу.Как вы правильно сказали, он переместит указатель с line[i] на line[i + 1] (в термах с исходным значением line, переданным функции PrintWords).

What "манипулирует файламихранится в этом адресе памяти "должен означать, полностью вне меня.О каких «файлах» вы говорите?

Значение вашего слова «заменить каждый экземпляр * строки просто« строкой »» мне также неясно.Мы используем line, когда хотим работать с указателем line.Мы используем *line, когда хотим работать с символьным указателем, на который указывает line.Это так просто.

Наконец, как утверждение *line++ точно эквивалентно line++.В обоих случаях указатель line увеличивается.В первом случае вы также разыменовываете указатель, но поскольку вы игнорируете результат этого разыменования, это не имеет значения.

2 голосов
/ 02 сентября 2010

line - это указатель.

line в этом случае будет какое-то число, например 0x80b34560.

*line будет что-то вроде 'c'.

Итак, line содержит адрес ячейки памяти, которая содержит (скажем,) 'c'.

Когда вы хотите, чтобы line указывал на следующее местоположение, вы говорите line++, и это будет следующее число (например, 0x80b34561, которое является ячейкой памяти, содержащей 'd').

Ваша путаница здесь связана с приоритетом оператора при игре в *line++. Это эквивалентно *(line++), потому что ++ имеет более высокий приоритет, чем *. Итак, вы получаете значение, сохраненное в указателе, а затем выбрасываете его, что бесполезно.

Вот схема:

+-------------------------------+
|  var     |  address |  value  |
+-------------------------------+
| line     | 80b34560 |  'a'    |
| (line+1) | 80b34561 |  'b'    |
| line[2]  | 80b34562 |  ' '    |
| etc...   |          |         |
+-------------------------------+

Обратите внимание, что для доступа к адресам я использовал две разные нотации - line+1 и line[2]. Ваш вопрос "Перейти от строки [i] к строке [i + 1] ??" правильно, но переосмыслите свое заключение.

1 голос
/ 02 сентября 2010

Выражение line++ увеличивает указатель, что вы и пытаетесь сделать.

Выражение *line++ увеличивает указатель и возвращает значение символа по новому адресу.Однако вы ничего не делаете со значением.

Оператор постфикса ++ имеет более высокий приоритет, чем оператор *.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...