Dizilerle niyə belədir, [5] == 5 [a]?

Cuelin on123.ru # 34 podcastində qeyd etdiyimiz kimi, C proqramlaşdırma dilində (aka: K R) C -dəki arrayların bu xüsusiyyəti qeyd olunur: a[5] == 5[a]

Joel bu pointer aritmetiğinin səbəbi olduğunu söyləyir, amma hələ də başa düşmürəm. Niyə a[5] == 5[a] ?

1456
19 дек. Dinah dekabrın 19-na təyin olundu 2008-12-19 20:01 '08 saat 20:01 'da 2008-12-19 20:01
@ 18 cavab

C standartı [] operatorunu aşağıdakı kimi təyin edir:

a[b] == *(a + b)

Buna görə a[5] qiymətləndirir:

 *(a + 5) 

5[a] qiymətləndirəcəkdir:

 *(5 + a) 

a serialın ilk elementi üçün bir göstəricidir. a[5] 5 elementdən daha çox olan bir dəyərdir ki, bu da *(a + 5) ilə bərabərdir və ibtidai məktəbin riyaziyyatından bərabər olduğunu ( komutativ əlavə) bilirik.

1733
19 дек. Mehrdad Afshari tərəfindən verilmiş cavab 19 dekabr 2008-12-19 20:04 '08 saat 20:04 'da 2008-12-19 20:04

Serialın göstəriciləri baxımından müəyyən olduğu üçün. a[i] commutative" *(a + i) mənası kimi təsvir olunur.

border=0
273
19 дек. David Thornley tərəfindən verilmiş cavab 19 dekabr 2008-12-19 20:05 '08 saat 08:05 'da 2008-12-19 20:05

Hesab edirəm ki, başqa bir cavabın əskikliyi yoxdur.

Bəli, p[i] müəyyən bir təsirə görə *(p+i) ekvivalentdir (bu, əlavə olaraq komutativdir) *(i+p) bərabərdir.

(Və array[i] serialın adı birbaşa dizinin birinci elementinə göstərici çevrilir.)

Amma bu vəziyyətdə əlavə olunmanın komutativliyi belə aydın deyil.

Hər iki əməliyyat eyni tipli və ya ümumi tipə keçən müxtəlif ədədi növlərdən ibarətdirsə, commutativity mantıksızdır: x + y == y + x .

Amma bu vəziyyətdə xüsusilə pointer arithmetic haqqında danışırıq, burada bir operand bir göstərici, digəri isə tamsayıdır. (Integer + tamsayı başqa bir əməliyyatdır və pointer + pointer cəfəngiyatdır.)

Standart + C operatorun təsviri ( N1570 6.5.6) aşağıdakı kimi oxuyur:

Əlavə etmək üçün hər iki operand aritmetik tipdə olmalıdır və ya bir operand obyektin tam növü üçün bir göstərici, digəri isə tamsayı növü olmalıdır.

Siz asanlıqla deyə bilərsiniz:

Əlavə etmək üçün hər iki işarə aritmetik tipdə olmalıdır və ya sol işlənən obyektin tam növü üçün bir göstərici olmalıdır və sağ operand tam ədəd olmalıdır.

bu halda i + pi[p] qanunsuz olardı.

C ++ şərtlərində, həqiqətən, iki şərti aşırı yüklü + operatoru var, bunlar şərti şəkildə təsvir edilə bilər:

 pointer operator+(pointer p, integer i); 

 pointer operator+(integer i, pointer p); 

yalnız ilk həqiqətən vacibdir.

Niyə belədir?

C ++, bu tərifi C-dən əldə edən C-dən əldə edilmişdir (dizinin komutativ indeksasiyası 1972-ci ildə istifadəçilər üçün B ), bunu BCPL- dən (1967-ci ildən götürmüş) götürmüş və daha çoxunu almış ola bilər erkən dillər (CPL? Algol?).

Beləliklə, dizinin indeksləşdirilməsini əlavə etmək baxımından müəyyənləşdirilmişdir və hətta bir göstəricinin və tamsayıın əlavə olunması komutativdir, ata-baba dillərinin dillərinə bir çox onilliklər uzanır.

Bu dillər müasir C-ə nisbətən daha az qətiliklə yazılmışdır. Xüsusilə göstəricilərlə tamsayılar arasında fərq çox vaxt nəzərə alınmamışdır. (Erkən C programcıları, unsigned dilinə əlavə edilmədikdən əvvəl imzalanmış tamsayılar kimi göstəriciləri bəzən istifadə etdilər.) Beləliklə, müxtəlif növ operandların bu dillərdən çıxmadığı ehtimal olunurdu. Istifadəçi bu "tam" tamsayılar, göstəricilər və ya başqa bir şeydən asılı olmayaraq iki "şey" əlavə etmək istəsə, onu qarşısını almaq üçün dildən asılı deyildir.

Və illər ərzində, bu qayda hər hansı bir dəyişiklik mövcud kodunu pozacaq (baxmayaraq ki, 1989 ANSI C standartı yaxşı bir fürsət ola bilərdi).

C və / və ya C ++ dəyişdirilməsi sola bir göstəricinin daxil edilməsini tələb edir və sağdakı bütün mövcud kodları poza bilər, amma real ifadə gücünü itirməyəcəkdir.

Beləliklə, indi arr[3]3[arr] , buna görə də sonuncu forma IOCCC-dən kənarda görünməməlidir .

190
23 авг. Keith Thompson tərəfindən cavab 23 Avqust 2013-08-23 04:37 '13 'da 4:37 2013-08-23 04:37

Və əlbəttə

  ("ABCD"[2] == 2["ABCD"])  (2["ABCD"] == 'C')  ("ABCD"[2] == 'C') 

Bunun əsas səbəbi, 70-ci illərdə C-nin inkişaf etdirildiyi zaman, kompüterlərin çox yaddaşa malik olmadığı idi (64KB çox şey var idi), beləliklə, C kompilyatoru çox sintaksis yoxlanılmadı. Buna görə də, " X[Y] " kor-koranə " *(X+Y) "

Həmçinin " += " və " ++ " sintaksislərini izah edir. " A = B + C " şəklində olan hər şey eyni tərtib edilmiş forma idi. B isə A kimi bir obyekt olsa, qurma səviyyəsinin optimallaşdırılması mümkün idi. Lakin kompilyator onu tanımaq üçün kifayət qədər parlaq deyildi, belə ki, geliştirici ( A += C ) idi. Eynilə, C 1 idi, başqa bir qurma səviyyəsinin optimallaşdırılması mümkün idi və tərtibatçı bunu açıqlamadı, çünki kompilyator onu tanımadı. (Ən son olaraq kompilyatorlar bunu edirlər, buna görə bu günlərdə bu sintaksislər əsasən lazım deyil.)

186
19 дек. 19 dekabrda James Curran tərəfindən cavab verildi. 2008-12-19 20:07 '08 at 8:07 pm 2008-12-19 20:07

sizeof problemini sizeof ilə bağlı bir şey söyləməmiş görünmür:

Dizine bir tamsayı əlavə edə bilərsiniz; iki əlamətlə birlikdə əlavə edə bilməzsiniz. Beləliklə, bir göstəriciyə bir tamsayı əlavə edərkən və ya bir tam göstəriciyə əlavə edərkən, kompilyator həmişə hansı bitin nəzərə alınması lazım olan bir ölçüsü olduğunu bilir.

51
11 февр. Cavab 11 fevralda 30364 istifadəçi tərəfindən verilir. 2009-02-11 18:56 '09 da 18:56 'da 2009-02-11 18:56

Sualına sanki cavab vermək. Həmişə doğru deyil, x == x

 double zero = 0.0; double a[] = { 0,0,0,0,0, zero/zero}; // NaN cout << (a[5] == 5[a] ? "true" : "false") << endl; 

təzyiqlər

 false 
47
11 авг. Peter Lawrey tərəfindən 11 Avqustda cavab verdi 2011-08-11 16:50 '11 at 16:50 2011-08-11 16:50

Yaxşı sual / cavablar.

Yalnızca qeyd etmək istəyirəm ki, C-göstəricilər və dizilər uyğun deyil, baxmayaraq ki, bu fərq fərqi yoxdur.

Aşağıdakı elanları nəzərdən keçirin:

 int a[10]; int* p = a; 

A.out'da, a a array ilə başlayan ünvanda yerləşdirilir və karakter p pleyerin saxlandığı ünvanda yerləşdirilir və bu yaddaş yerindəki göstəricinin dəyəri dizinin başlanğıcıdır.

23
20 дек. Cavab PolyThinker tərəfindən verilir 20 dekabr. 2008-12-20 11:16 '08 at 11:16 2008-12-20 11:16

Yalnızca bu düzgün olmayan sintaksın, eyni dizideki mövqeləri göstərən bir sıra göstəricilərlə məşğul olmaq istədiyiniz zaman "faydalı" və ya ən azı çox komik ola biləcəyini öyrənirəm. Nested brackets əvəz və kodu daha oxunaqlı edə bilər!

 int a[] = { 2 , 3 , 3 , 2 , 4 }; int s = sizeof a / sizeof *a; // s == 5 for(int i = 0 ; i < s ; ++i) { cout << a[a[a[i]]] << endl; // ... is equivalent to ... cout << i[a][a][a] << endl; // but I prefer this one, it easier to increase the level of indirection (without loop) } 

Əlbəttə ki, mən real kodun istifadə edilməsində heç bir nöqtə olmadığına inanıram, amma mənim üçün hələ maraqlıdır :)

21
10 июня '12 в 22:50 2012-06-10 22:50 Cavab 10 iyun 2012-ci il saat 10:50 'da Frédéric Terrazzoni'ye verilir. 2012-06-10 22:50

C'de göstəricilər üçün biz var

 a[5] == *(a + 5) 

və həmçinin

 5[a] == *(5 + a) 

Buna görə də, a[5] == 5[a].

17
23 марта '12 в 10:05 2012-03-23 10:05 cavab 23 mart 2012-ci il saat 10: 05-da user1287577 tərəfindən verilmişdir 2012-03-23 ​​10:05

Cavab deyil, düşüncə üçün yalnız yemək. Sinifdə bir çox yüklənən indeksi / indeksi operatoru varsa, 0[x] ifadəsi işləməyəcəkdir:

 class Sub { public: int operator [](size_t nIndex) { return 0; } }; int main() { Sub s; s[0]; 0[s]; // ERROR } 

Sınıf int'sine erişemediğimizden bu mümkün deyil:

 class int { int operator[](const Sub }; 
14
19 июня '11 в 11:37 2011-06-19 11:37 Cavab Ajay tərəfindən 19 iyun '11' də 11:37 'də verildi 2011-06-19 11:37

C Ted Jensen-də bal və hücumlarda təlimçidə çox yaxşı bir şərh var.

Ted Jensen bunu belə izah etdi:

Əslində, bu doğru, yəni hər hansı a[i] yazı yazıldığı yerdən *(a + i) ilə əvəz edilə bilməz. Əslində, kompilyator hər halda eyni kodu yaradır. Beləliklə, göstərici aritmetikinin dizi indeksasiyası ilə eyni olduğunu görürük. Hər hansı bir sintaksis eyni nəticə verir.

Bu, göstəricilərin və dizilərin bir və eyni olduğunu deyir, onlar deyil. Yalnız dediyimiz kimi, bir sıra elementini müəyyən etmək üçün iki sintaksis seçimi var: biri array indeksindən, digəri isə pointer aritmetikindən istifadə edərək eyni nəticələr verir.

İndi bu sonuncu ifadəyə baxın, onun hissəsi (a + i) + operator və komutativ ifadə olan C dövlət qaydalarını istifadə edən sadə bir əlavədir. Yəni (a + i) eynidır (i + a) . Beləliklə *(a + i) kimi asanlıqla *(i + a) yaza bilərik. Amma *(i + a) gəlmiş ola bilərdi! Bütün bunlardan maraqlı həqiqət gəlir ki, əgər:

 char a[20]; 

yazmaq

 a[3] = 'x'; 

Girişə uyğun gəlir

 3[a] = 'x'; 
9
27 сент. Cavab Bhullar 27 sep kimi verilir . 2013-09-27 09:46 '13 at 9:46 2013-09-27 09:46

Suala cavab verildiyini bilirəm, amma bu izahatla razılaşa bilmədi.

Kompilyatorun dizayn prinsiplərini xatırlayıram, a int bir sıra və bir int ölçüsü 2 bayt və amp; a üçün əsas ünvan 1000-dir.

a[5] necə işləyəcək →

 Base Address of your Array a + (5*size of(data type for array a)) ie 1000 + (5*2) = 1010 

Beləliklə

Eynilə, kod c 3-ünvan koduna bölünsə, 5[a] → olur

 Base Address of your Array a + (size of(data type for array a)*5) ie 1000 + (2*5) = 1010 

Beləliklə, əsasən hər iki operator eyni yeri yaddaşda saxlayır və buna görə də a[5] = 5[a] .

Bu açıqlama da dizilərdə C-də işləyəcək mənfi göstəricilərə səbəb olur.

yəni. əgər a[-5] əldə a[-5] , mənə verəcəkdir

 Base Address of your Array a + (-5 * size of(data type for array a)) ie 1000 + (-5*2) = 990 

O, 990 nöqtəsində obyekti mənə qaytaracaq.

6
04 мая '16 в 11:24 2016-05-04 11:24 cavab Ajinkya Patil tərəfindən 04 may '16 saat 11:24 2016-05-04 11:24 tərəfindən verilir

kompilyatorda c

 a[i] i[a] *(a+i) 

- bunlar bir sıra elementinə müraciət etmək üçün müxtəlif yollardır! (BÜTÜN TIME üçün deyil)

4
29 окт. Cavab AVIK DUTTA 29 oct verilir . 2014-10-29 12:14 '14 at 12:14 2014-10-29 12:14

arr[3]3[arr] dizilişlərində3[arr] göstəricilərin onların *(arr + 3) göstəriciləri *(arr + 3) - *(3 + arr) , əksinə [arr]3 və ya [3]arr səhvdir və nəticədə sintaksis səhvi, çünki (arr + 3)*(3 + arr)* etibarsız ifadələrdir. Bunun səbəbi, dereference operatorunun, ifadədən sonra göstərilən ünvana yerləşdirilməməsi və ünvandan sonra yerləşdirilməsidir.

4
17 дек. Cavab 17 dekabrda Krishan tərəfindən verilir . 2013-12-17 14:22 '13 'da 14:22' de 2013-12-17 14:22

C

  int a[]={10,20,30,40,50}; int *p=a; printf("%d\n",*p++);//output will be 10 printf("%d\n",*a++);//will give an error 

Pointer "dəyişən"

array adı "mnemonic" və ya "sinonim"

p++; etibarlıdır, ancaq a++ etibarlı deyil

a[2] 2 [a] təşkil edir, çünki hər ikisi üzrə daxili əməliyyat

"Pointer arithmetic" daxili olaraq hesablanır

*(a+3) bərabərdir *(3+a)

0
12 февр. Cavab 12 fevralda Jayghosh Wankar tərəfindən verilir. 2017-02-12 16:54 '17 saat 16:54 'da 2017-02-12 16:54

C-dilində göstərici və array bir-birinə çox yaxındır, array göstərici şəklində bölünə bilər. Serialın adı ilk elementi üçün göstəricidir. Buna görə, əgər acData bir sıra simvol varsa, "acData" ilk elementin ünvanı olacaq. Ayrıca, acData'nın acData [0] ilə bənzər olduğunu söyləyə bilərsiniz.

C standartına uyğun olaraq, bir göstərici kimi 1D array təmsil edə bilərik.

Aşağıdakı ifadəyə baxın.

acData [i] = * (acData + i); ---------> 1D array göstərici kimi

Beləliklə, əgər i = 5;

cData [5] = * (acData +5);

Aşağıdakı formada ifadəni də təqdim edə bilərik,

cData [5] = * (5 + acData);

İndi yaza bilərik

cData [5] = 5 [cData];

Aşağıdakı kodu baxın.

 #include <stdio.h> int main(int argc, char *argv[]) { char cData [] = {'w', 'o', 'r', 'l' ,'d' }; // character array int index = 0; for(index = 0; index < sizeof(cData ); ++index) { printf("Array element access by pointer = %c\n\n",cData[index]); printf("Array element access by array = %c\n\n",index[cData]); } return 0; } 

Ədəbiyyat, https://aticleworld.com/array-in-c/

0
18 апр. Cavab amlendra mishra verildi 18 Aprel. 2018-04-18 09:52 '18 saat 09:52 'da 2018-04-18 09:52

Bəli, bu, dil dəstəyi ilə mümkün olan bir funksiyadır.

Derleyici a[i] kimi *(a+i) şərh a[i]5[a] ifadəsi *(5+a) kimi qiymətləndirilir. Əlavə komutativ olduğundan, hər ikisi bərabərdir. Buna görə ifadəsi true olaraq qiymətləndirilir.

0
02 апр. Cavab Harsha JK 02 Aprel verilir. 2018-04-02 21:42 '18 at 21:42 2018-04-02 21:42

pointer növləri

1) data göstəricisi

 int *ptr; 

2) data göstəricisinə işarə edir

 int const *ptr; 

3) const data üçün const pointer

 int const *const ptr; 

və dizilerimiz siyahımızdan tip (2)
Bir zamanda bir sıra müəyyən edərkən, bu ünvan bu göstəricidə başlayır.
Bildiyimiz kimi, proqramımızda const dəyərini dəyişdirə və dəyişə bilmirik, çünki kompilyasiya zamanı ERROR yaradır.

Mən tapdığım əsas fərq ...

İşarəçiyi ünvana bərpa edə bilərik, ancaq eyni vəziyyətdə deyil.

======
və sualına geri dön ...
[5] başqa bir şey deyil (a + 5)
asanlıqla başa düşə bilərsiniz
a - ünvanımızı (insanların əsas ünvanını adlandırdıqları), həmçinin bizim siyahımızda (2) bir göstərici göstəricisini ehtiva edir
[] - bu operator bir pointer ilə əvəz edilə bilər *.

nəhayət ...

 a[5] == *(a +5) == *(5 + a) == 5[a] 
-2
13 июля '18 в 10:34 2018-07-13 10:34 Cavab Jeet Parik tərəfindən 13 iyul 18: 18-da saat 10 : 34-də 2018-07-13 10:34