2016-02-10 11 views
120

Właśnie zacząłem studiować C, i kiedy robiąc jeden przykład o przejściu wskaźnika do wskaźnika jako parametru funkcji, znalazłem problem.Różnica między * ptr + = 1 i * ptr ++ w C

To jest mój przykładowy kod:

#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; 
} 

Problem pojawia się w wierszu 16, kiedy modyfikować *ptr+=1 do *ptr++. Oczekiwanym wynikiem powinna być cała tablica i numer 1, ale gdy używam *ptr++, wynik to 0.

Czy istnieje różnica między +=1 a ++? Myślałem, że oba są takie same.

+2

Należy zauważyć, że podany kod nie zostanie skompilowany, ponieważ nie zadeklarowano 'ciągu'. –

+6

Pozostałe uwagi: 1) "allocateIntArray" jest złą nazwą, ponieważ wydaje się, że "malloc" jest tablicą z funkcji, ale nie robisz tego. Zamiast tego proponuję 'fillIntArray'. 2) Nie używasz zwracanej wartości 'allocateIntArray'. Proponuję zmienić typ zwrotu na "void". 3) Nie powinno być 'if (ptr! = NULL)' w funkcji 'increasePointer' to' if (* ptr! = NULL) '? 4) Gips w "malloc" jest niepotrzebny. Zobacz komentarz Sourava powyżej. 5) To: 'for (int i = 0; i <10; i ++) {printf ("% d \ n ", p1 [i]); } 'i' printf ("% d \ n", * p1); p1 -; 'musi być ujęte w' if (p1! = NULL) '. 6) 'string.h' nie jest używany. –

+1

Powiązane: [++ na wskaźniku dereferencji w C?] (Http://stackoverflow.com/questions/859770/on-a-dereferencjonowany-pointer-in-c) –

Odpowiedz

281

Różnica wynika z pierwszeństwa operatora.

Operator post-inkrementujący ++ ma wyższy priorytet niż operator dereferencji *. Tak więc *ptr++ jest odpowiednikiem *(ptr++). Innymi słowy, przyrostek postu modyfikuje wskaźnik, a nie to, co wskazuje.

Operator przypisania += ma niższy priorytet niż operator dereferencji *, więc *ptr+=1 jest równoważny . Innymi słowy, operator przypisania modyfikuje wartość wskazywaną przez wskaźnik i nie zmienia samego wskaźnika.

+3

Dla początkujących mnemonik to podobieństwo między '* p ++' i '* ++ p'. Pierwszeństwo operatora tego ostatniego jest oczywiste, pierwsze z tych pierwszych. –

21

Kolejność pierwszeństwa dla 3 podmiotów zaangażowanych w swoje pytanie jest następujące:

postinkrementacja ++> dereference *> Przypisanie +=

Można to sprawdzić page celu uzyskania dalszych informacji na ten temat.

podczas analizowania ekspresji, operator, który znajduje się na liście w pewnym rzędu będą związane mocniej (jak w nawiasie) jej argumenty niż operatora, który jest określony w wierszu dalej poniżej. Na przykład wyrażenie *p++ jest analizowane jako *(p++), a nie jako (*p)++.

Krótko mówiąc, w celu wyrażenia tego zadania *ptr+=1 pomocą operatora postinkrementacja trzeba dodać nawiasy do operatora dereference dać tę operację pierwszeństwo nad ++ jak w tym (*ptr)++

+3

W tej chwili jest to jedyna odpowiedź, która zawiera rozwiązanie ... (* ptr) ++ – hyde

7

LET'S stosuje się nawiasy, aby pokazać order of operations

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

Zróbmy to jeszcze raz z

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

I znowu z

*ptr++ 
*(ptr++) 
  • W *ptr += 1, zwiększamy wartość zmiennej nasze wskaźnik punktów do.
  • W *ptr++, zwiększamy wskaźnik po naszej całej wypowiedzi (linia kodu) jest zrobione, i zwraca referencję do zmiennej nasze wskaźnik punktów do.

Ten ostatni pozwala robić takie rzeczy jak:

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++); 
} 

To jest powszechna metoda używana do kopiowania src tablicę do innego dest tablicy.

+0

"i zwraca odniesienie do zmiennej, do której wskazuje nasz wskaźnik." C nie ma referencji. –

+0

@MilesRout Być może nazwanie go wartością l może być dokładniejsze? Ale nie jestem pewien, jak to ująć bez dodawania żargonu. –

3

Bardzo dobre pytanie.

W K & R "Język programowania C" "5.1 Wskaźniki i adresy", możemy uzyskać na to odpowiedź.

„Operatorzy unarne * i & wiążą szczelniej niż operatory arytmetyczne”

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

„Jednoargumentowe operatory takie jak * i ++ współpracownik prawej do lewej”.

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

// Działa jak * (ptr ++).

Prawidłowy sposób jest:

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

Czy możesz sformatować część kodu? – manetsus

+0

Po raz pierwszy komentuję Stack Overflow. Zaktualizowałem format kodu. ^^ Dzięki za twoją sugestię. –

2

* PTR + = 1: Dane Przyrost że PTR punktów. * ptr ++: Wskaźnik przyrostu, który wskazuje na następną lokalizację w pamięci zamiast danych wskazanych przez wskaźnik.

Powiązane problemy