Bagaimana cara menaikkan alamat penunjuk dan nilai penunjuk?

96

Mari kita asumsikan,

int *p;
int a = 100;
p = &a;

Apa yang sebenarnya akan dilakukan kode berikut dan bagaimana caranya?

p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

Saya tahu, ini agak berantakan dalam hal pengkodean, tetapi saya ingin tahu apa yang sebenarnya akan terjadi ketika kita membuat kode seperti ini.

Catatan: Mari kita asumsikan bahwa alamat a=5120300, disimpan di pointer pyang alamatnya adalah 3560200. Sekarang, berapa nilai p & asetelah eksekusi setiap pernyataan?

Dinesh
sumber
3
kenapa kamu tidak menjalankannya di debugger?
AndersK
24
Nah .. kenapa tidak coba saja dan lihat saja? printfakan mencetak pointer dengan% p
Brian Roach
Jika Anda penasaran dengan perilaku, mainkan saja. Cukup tulis program c sederhana yang membahas semua kasus penggunaan ini dan lihat apakah itu masuk akal bagi Anda.
Cyrus
@Anderson. Mungkin OP mengharapkan perilaku yang tidak ditentukan? ...Atau mungkin tidak.
Mateen Ulhaq

Jawaban:

178

Pertama, operator ++ lebih diutamakan daripada operator *, dan operator () lebih diutamakan daripada yang lainnya.

Kedua, operator nomor ++ sama dengan operator nomor ++ jika Anda tidak menugaskannya ke apa pun. Perbedaannya adalah angka ++ mengembalikan angka dan kemudian menambah angka, dan ++ angka bertambah terlebih dahulu dan kemudian mengembalikannya.

Ketiga, dengan meningkatkan nilai sebuah pointer, Anda menambahnya dengan ukuran isinya, yaitu Anda menambahnya seolah-olah Anda sedang mengulang dalam sebuah array.

Jadi, untuk merangkum semuanya:

ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value of ptr is incremented
++(*ptr); // The value of ptr is incremented
++*(ptr); // The value of ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value of ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then get's accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then get's accessed, with your code, segfault

Karena ada banyak kasus di sini, saya mungkin telah membuat kesalahan, mohon koreksi saya jika saya salah.

EDIT:

Jadi saya salah, yang diutamakan sedikit lebih rumit dari yang saya tulis, lihat di sini: http://en.cppreference.com/w/cpp/language/operator_precedence

felipemaia
sumber
6
* ptr ++, nilainya tidak bertambah, penunjuknya adalah. Operator unary ini memiliki prioritas yang sama tetapi dievaluasi dari kanan ke kiri. Kode tersebut berarti "mengambil konten dari titik ptr, lalu menaikkan ptr". Ini adalah kode C yang sangat umum (dan ya, cukup membingungkan). Harap perbaiki ini dan saya akan menghapus suara negatifnya. Sama untuk * (ptr) ++, tanda kurung tidak melakukan apa pun.
Lundin
Terima kasih banyak Lundin, apakah saya melewatkan hal lain?
felipemaia
@Lundin Hai, apakah jawaban di atas diperbaiki sekarang? Terima kasih.
Unheilig
4
@Unheilig Kalimat pertama masih sepenuhnya salah, postfix ++ lebih diutamakan daripada unary * yang memiliki prioritas yang sama dengan awalan ++. Selain itu, sepertinya ok.
Lundin
4
@felipemaia Apakah Anda yakin akan segfault? Mungkin itu hanya perilakunya yang tidak terdefinisi?
jotik
14

cek programnya dan hasilnya seperti,

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value
Sujith R Kumar
sumber
2
@alex gunakan artinya misalnya pertimbangkan pernyataan, 'int * a = p ++;' Di sini nilai pertama dari pointer 'p' akan digunakan dan setelah itu p akan berpindah ke posisi berikutnya. Jadi akibatnya setelah menjalankan pernyataan di atas 'a' akan memiliki alamat lokasi sebelumnya yang ditunjukkan oleh 'p' dan 'p' akan mengarah ke posisi berikutnya. Yaitu pertama menggunakan nilai 'p' untuk ekspresi tugas seperti di atas dan kemudian nilai 'p' untuk menunjuk ke posisi berikutnya
Sujith R Kumar
Singkatnya, saya pikir dia menggunakan frase "gunakan" untuk istilah yang lebih formal "menetapkan". Itu semuanya.
Apekshik Panigrahi
4

Berikut ini adalah contoh dari berbagai saran "cetak saja". Saya merasa itu instruktif.

#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

Ia kembali

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

Saya mentransmisikan alamat pointer ke ints sehingga mereka dapat dengan mudah dibandingkan.

Saya menyusunnya dengan GCC.

Rico Picone
sumber
1
Saya akan mengubah ini untuk memasukkan nilai x dan p setelah operasi.
NetJohn
3

Berkenaan dengan "Bagaimana cara menaikkan alamat pointer dan nilai pointer?" Saya pikir itu ++(*p++);sebenarnya didefinisikan dengan baik dan melakukan apa yang Anda minta, misalnya:

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

Ini tidak mengubah hal yang sama dua kali sebelum titik urutan. Saya tidak berpikir itu gaya yang baik untuk sebagian besar penggunaan - itu agak terlalu samar untuk saya sukai.

Flexo
sumber
Sebenarnya, tanda kurung tidak diperlukan: ++*p++akan berhasil menaikkan nilai dan penunjuk (postfix ++mengikat lebih kuat dari dereferensi *, dan itu terjadi sebelum prefiks ++karena urutan). Tanda kurung hanya diperlukan saat Anda membutuhkan nilai sebelum menambahkannya (*p++)++. Jika Anda menggunakan all-prefix, ++*++pakan berfungsi dengan baik tanpa tanda kurung juga (tetapi menambah nilai yang ditunjukkan setelah kenaikan pointer).
cmaster
1
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);
Abhishek DK
sumber
Apa itu asosiativitas?
71GA
1
dalam kode Anda dapat melihat * str ++, sekarang di sini * dan ++ memiliki prioritas yang sama (prioritas yang sama dalam istilah awam) dan juga * str ++ tidak dipisahkan menggunakan tanda kurung seperti * (str ++) atau (* str) ++, jadi menjadi perlu bagaimana seharusnya dievaluasi. jadi kanan ke kiri berarti (x = str ++) dan kemudian (y = * x)
Abhishek DK