Разница между * ptr + = 1 и * ptr ++ в C

Я только начал изучать C, и, когда я делал один пример о передаче указателя на указатель в качестве параметра функции, я обнаружил проблему.

Это мой пример кода:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int* allocateIntArray(int* ptr, int size){
    if (ptr != NULL){
        for (int i = 0; i < size; i++){
            ptr[i] = i;
        }
    }
    return ptr;
}

void increasePointer(int** ptr){
    if (ptr != NULL){
        *ptr += 1; /* <----------------------------- This is line 16 */
    }
}

int main()
{
    int* p1 = (int*)malloc(sizeof(int)* 10);
    allocateIntArray(p1, 10);

    for (int i = 0; i < 10; i++){
        printf("%d\n", p1[i]);
    }

    increasePointer(&p1);
    printf("%d\n", *p1);
    p1--;
    free(p1);
    fgets(string, sizeof(string), stdin);
    return 0;
}

Проблема возникает в строке 16, когда я изменяю *ptr+=1 на *ptr++. Ожидаемым результатом должен быть весь массив и номер 1, но когда я использую *ptr++, результат равен 0.

Есть ли разница между +=1 и ++? Я думал, что они оба одинаковы.

Ответ 1

Разница связана с приоритетом оператора.

Оператор post-increment ++ имеет более высокий приоритет, чем оператор разыменования *. Итак, *ptr++ эквивалентно *(ptr++). Другими словами, приращение post изменяет указатель, а не то, на что он указывает.

Оператор присваивания += имеет более низкий приоритет, чем оператор разыменования *, поэтому *ptr+=1 эквивалентен (*ptr)+=1. Другими словами, оператор присваивания изменяет значение, на которое указывает указатель, и не меняет сам указатель.

Ответ 2

Порядок приоритета для трех операторов, участвующих в вашем вопросе, следующий:

post-increment ++ > разыменование * > назначение +=

Подробнее об этом можно узнать на странице .

При анализе выражения оператор, который указан в некоторой строке, будет привязан к его аргументам более жестко (как в скобках), чем к любому оператору, который указан ниже в строке. Например, выражение *p++ анализируется как *(p++), а не как (*p)++.

Короче говоря, чтобы выразить это назначение *ptr+=1 с помощью оператора post-increment, вам нужно добавить скобки к оператору разыменования, чтобы присвоить этому приоритету операции над ++, как в этом (*ptr)++

Ответ 3

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

a + b / c
a + (b/c)

Сделайте это снова с помощью

*ptr   += 1
(*ptr) += 1

И снова с

*ptr++
*(ptr++)
  • В *ptr += 1 мы увеличиваем значение переменной, на которую указывает наш указатель.
  • В *ptr++ мы увеличиваем указатель после завершения всей нашей инструкции (строки кода) и возвращаем ссылку на переменную, на которую указывает наш указатель.

Последнее позволяет вам делать такие вещи, как:

for(int i = 0; i < length; i++)
{
    // Copy value from *src and store it in *dest
    *dest++ = *src++;

    // Keep in mind that the above is equivalent to
    *(dest++) = *(src++);
}

Это общий метод, используемый для копирования массива src в другой массив dest.

Ответ 4

Очень хороший вопрос.

В языке программирования K & R "C" "5.1 Указатели и адреса" мы можем получить ответ для этого.

"Унарные операторы * и и связывают более жестко, чем арифметические операторы"

*ptr += 1      //Increment what ptr points to.

"Унарные операторы, такие как * и ++, ассоциируют справа налево."

*ptr++        //Increment prt instead of what ptr point to.

//Он работает как * (ptr ++).

Правильный способ:

(*ptr)++      //This will work.

Ответ 5

* ptr + = 1: Приращение данных, на которые указывает ptr. * ptr ++: указатель увеличения, указывающий на следующую ячейку памяти вместо данных, на которые указывает указатель.