Perbedaan antara * ptr + = 1 dan * ptr ++ di C

123

Saya baru saja mulai mempelajari C, dan ketika melakukan satu contoh tentang meneruskan pointer ke pointer sebagai parameter fungsi, saya menemukan masalah.

Ini adalah kode contoh saya:

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

Masalah terjadi di baris 16, saat saya mengubah *ptr+=1ke *ptr++. Hasil yang diharapkan harus berupa seluruh array dan nomor 1 tetapi ketika saya menggunakan *ptr++hasilnya adalah 0.

Apakah ada perbedaan antara +=1dan ++? Saya pikir keduanya sama.

huy nguyen
sumber
2
Perhatikan bahwa kode yang diberikan tidak dapat dikompilasi karena Anda belum mendeklarasikannya string.
Spikatrix
6
Catatan lain: 1) allocateIntArrayadalah nama yang buruk karena tampaknya Anda mallocadalah array dari fungsi tersebut, tetapi Anda tidak melakukannya. Saya menyarankan fillIntArraysebagai gantinya. 2) Anda tidak menggunakan nilai pengembalian allocateIntArray. Saya sarankan Anda mengubah jenis pengembalian menjadi void. 3) Sebaiknya tidak if (ptr != NULL)dalam fungsi increasePointermenjadi if (*ptr != NULL)? 4) Cast in malloctidak perlu. Lihat komentar Sourav di atas. 5) Ini: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }dan printf("%d\n", *p1); p1--;perlu dilampirkan if(p1 != NULL). 6) string.htidak digunakan.
Spikatrix
9
p+=1adalah seperti ++p, tidak sepertip++
Kos
5
pertanyaan ini ditanyakan 4 tahun yang lalu: Apakah ++ sama dengan + = 1 untuk petunjuk
ren
3
@ren Hampir, tapi tidak cukup. Pertanyaan terkait tidak melibatkan operator dereferensi, yang merupakan inti dari masalah OP di sini.
Jason C

Jawaban:

290

Perbedaannya karena prioritas operator.

Operator post-increment ++memiliki prioritas yang lebih tinggi daripada operator dereferensi *. Begitu *ptr++pula dengan*(ptr++) . Dengan kata lain, kenaikan posting mengubah penunjuk, bukan apa yang ditunjukkannya.

Operator penugasan +=memiliki prioritas yang lebih rendah daripada operator dereferensi *, begitu *ptr+=1juga dengan (*ptr)+=1. Dengan kata lain, operator penugasan mengubah nilai yang ditunjuk penunjuk, dan tidak mengubah penunjuk itu sendiri.

pengguna3386109
sumber
3
Untuk pemula, mnemonik adalah kesamaan antara *p++dan *++p. Urutan operator yang terakhir jelas, yang pertama mengikuti.
Walter Tross
21

Urutan prioritas untuk 3 operator yang terlibat dalam pertanyaan Anda adalah sebagai berikut:

post-increment ++> dereference *> assignment+=

Anda dapat memeriksa halaman ini untuk rincian lebih lanjut tentang subjek tersebut.

Saat mengurai ekspresi, operator yang terdaftar di beberapa baris akan terikat lebih erat (seolah-olah dengan tanda kurung) ke argumennya daripada operator mana pun yang terdaftar di baris jauh di bawahnya. Misalnya, ekspresi *p++diuraikan sebagai *(p++), dan bukan sebagai (*p)++.

Singkat cerita, untuk mengekspresikan tugas ini *ptr+=1menggunakan operator kenaikan setelah Anda perlu menambahkan tanda kurung ke operator dereferensi untuk memberikan operasi yang diutamakan ++seperti dalam ini(*ptr)++

Younes Regaieg
sumber
3
Menariknya, saat ini satu-satunya jawaban yang berisi solusi ... (* ptr) ++
hyde
7

Mari terapkan tanda kurung untuk menunjukkan urutan operasi

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

Ayo lakukan lagi dengan

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

Dan lagi dengan

*ptr++
*(ptr++)
  • Di *ptr += 1, kami menambah nilai variabel yang ditunjuk penunjuk kami .
  • Di *ptr++, kita menambah pointer setelah seluruh pernyataan kita (baris kode) selesai, dan mengembalikan referensi ke variabel yang ditunjuk oleh pointer kita .

Yang terakhir memungkinkan Anda melakukan hal-hal seperti:

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

Ini adalah metode umum yang digunakan untuk menyalin srcarray ke destarray lain .

Mateen Ulhaq
sumber
"dan mengembalikan referensi ke variabel yang ditunjuk penunjuk kami." C tidak memiliki referensi.
Miles Rout
@MilesRout Mungkin menyebutnya lvalue mungkin lebih akurat? Tapi saya tidak yakin bagaimana menjelaskannya tanpa menambahkan jargon.
Mateen Ulhaq
3

Pertanyaan yang sangat bagus.

Dalam "bahasa pemrograman C" K&R "5.1 Pointer dan Alamat", kita bisa mendapatkan jawaban untuk ini.

"Operator unary * dan & mengikat lebih erat daripada operator aritmatika"

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

"Operator unary seperti * dan ++ associate kanan ke kiri ."

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

// Ia bekerja seperti * (ptr ++).

Cara yang benar adalah:

(*ptr)++      //This will work.
Nick.Sang
sumber
Ini adalah pertama kalinya saya mengomentari Stack Overflow. Saya telah memperbarui format kode. ^^ Terima kasih atas saran Anda.
Nick.Sang
2

* ptr + = 1: Data kenaikan yang ditunjukkan oleh ptr. * ptr ++: Penunjuk kenaikan yang mengarah ke lokasi memori berikutnya, bukan ke data yang ditunjuk penunjuk.

pengguna5787482
sumber