O introducere la indicatori pentru programatori
Dacă vă dați seama sau nu, marea majoritate a programelor pe care le-ați utilizat fac uz de indicii într-un fel. Poate că ați experimentat a NullPointerException la un moment dat. Ca programator, codul pe care îl scrieți va folosi mai mult decât probabil indicii, chiar dacă nu i-ați implementat singur.
Astăzi vă voi arăta cum funcționează pointerii, așa că puteți dori să verificați modul în care funcționează matricele și listele Cum funcționează matricele și listele în Python Cum funcționează matricele și listele în Python Arrays și liste sunt unele dintre cele mai utile structuri de date în programare - - deși puțini oameni le folosesc la potențialul lor maxim. Citiți mai multe pentru un primer de programare. Acest articol va fi mai bazat pe teorie decât de obicei, dar se va lipi de ea, pointerii sunt foarte complexi!
Compilarea codului
Înainte de a sări în pointeri, trebuie să înțelegeți modul în care codul este construit și executat - poate că știți deja acest lucru. Această secțiune va avea afirmații destul de generale - lucruri care se aplică la majoritate de limbi, dar nu neapărat toate.
Să reluăm lucrurile la început. Fiecare computer utilizează binar Ce este binar? [Tehnologie explicată] Ce este binar? [Tehnologie Explained] Având în vedere că binar este atât de absolut fundamental pentru existența de calculatoare, pare ciudat că nu am abordat niciodată subiectul anterior - așa că astăzi m-am gândit că voi da o scurtă prezentare a ceea ce binar ... Citește mai mult, o serie de cele și zerouri care alcătuiesc tehnologia modernă așa cum o știm. Este extrem de dificil să codifici ceva în binar (fișierele ar fi foarte confuze), deoarece acestea sunt instrucțiunile prime necesare de dvs. unități centrale de procesare sau CPU-ul pentru a funcționa Ce este un procesor și ce face? Ce este un procesor și ce face? Componentele de acronime sunt confuze. Ce este un procesor oricum? Și am nevoie de un procesor quad sau dual-core? Ce zici de AMD sau Intel? Suntem aici pentru a explica diferența! Citeste mai mult . Acest lucru este cunoscut sub numele de Codul mașinii.
Următorul pas de la codul mașinii este Asamblare. Acesta este un format ușor de citit de om. Deși este încă complexă pentru a programa, este posibil. Adunarea este alcătuită dintr-o serie de comenzi simple pentru executarea sarcinilor și este cunoscută sub numele de a nivel scăzut limbaj de programare. Este posibil să se scrie programe complexe, dar este dificil să se exprime concepte abstracte și necesită multă atenție.
Multe jocuri video și aplicații de înaltă performanță au o parte din logica scrisă în ansamblu, deoarece unele creșteri ale vitezei reale pot fi găsite dacă știți ce faceți. Cu toate acestea, pentru marea majoritate a proiectelor de programare, nu trebuie să cunoașteți niciun ansamblu.
Deci, dacă codul mașinii este prea greu de scris și asamblarea este prea dificil de programat, cu ce scrieți codul? Aici e locul nivel inalt Limbile de nivel înalt fac programele ușor de scris. Puteți programa în ceva care seamănă cu limba dvs. maternă și este ușor să exprimați algoritmi complexe. S-ar putea să fi auzit de multe limbi de nivel înalt (și cu siguranță veți fi folosit un program scris în ele):
- DE BAZĂ
- C++
- foșnet
Aceste limbi sunt foarte vechi acum și multe au fost dezvoltate la începutul anilor '50! Aproape fiecare limbaj de programare modern este un limbaj de nivel înalt, incluzând PHP și Python. Există mai multe limbi care sunt inventate în fiecare zi (deși probabil sunt suficiente acum), dar exact cum codul dvs. funcționează corect dacă calculatoarele necesită codul mașinii?
Aici este locul unde intră compilația. Un compilator este un program care convertește codul de nivel înalt într-o formă care poate fi executată. Acesta ar putea fi un alt limbaj de nivel înalt, dar este, de obicei, asamblare. Unele limbi (cum ar fi Python sau Java) convertesc codul într-o etapă intermediară numită bytecode. Aceasta va trebui să se compileze din nou la o dată ulterioară, care se face, de obicei, la cerere, cum ar fi când rulează programul. Acest lucru este cunoscut sub numele de la timp compilație, și este destul de popular.
Gestionarea memoriei
Acum, că știți cum funcționează limbile de programare, să examinăm gestionarea memoriei în limbi de nivel înalt. Pentru aceste exemple, voi folosi codul pseudo-cod scrise nu într-o anumită limbă, ci folosit pentru a arăta mai degrabă concepte decât sintaxă exactă. Astăzi, acest lucru se va asemăna cel mai mult C ++, deoarece acesta este cel mai bun limbaj de nivel înalt (după părerea mea).
Pentru această secțiune, aceasta va ajuta dacă aveți o înțelegere a modului în care funcționează RAM Un ghid rapid și murdar pentru RAM: Ce trebuie să știți Un ghid rapid și murdar pentru RAM: Ce trebuie să știți RAM este o componentă crucială a fiecărui computer , dar poate fi confuz să înțelegi dacă nu ești un guru tehnic. În acest post, îl împărțim în termeni ușor de înțeles. Citeste mai mult .
Cele mai multe limbi au variabile - containere care stochează date. Trebuie să definiți în mod explicit tipul de date. Unele limbi tipărite dinamic, cum ar fi Python sau PHP, se ocupă de acest lucru pentru dvs., dar ei încă mai trebuie să o facă.
Spuneți că aveți o variabilă:
int myNumber;
Acest cod declară o variabilă numită numărul meu, și îi dă un tip de date întreg. După compilare, computerul interpretează această comandă ca fiind:
“Găsiți o memorie goală și rezervați un spațiu suficient de mare pentru a stoca un număr întreg”
Odată ce această comandă a fost executată, acest bit de memorie nu poate fi utilizat de un alt program. Nu conține încă date, dar este rezervată variabilei myNumber.
Acum atribuiți o valoare variabilei dvs.:
myNumber = 10;
Pentru a finaliza această sarcină, computerul accesează locația rezervată de memorie și modifică orice valoare este stocată acolo, la această nouă valoare.
Acum, toate acestea sunt bune și bune, dar cum se obțin locurile de memorie fără rezerve? Dacă programele își rezervă toată memoria care le place, memoria RAM se va umple imediat - ceea ce ar face pentru a foarte sistem lent.
Pentru a evita această problemă potențială, multe limbi implementează a colector de gunoi, folosite pentru a distruge variabilele (și, prin urmare, eliberați locațiile de memorie rezervate) care au dispărut fara scop.
S-ar putea să vă întrebați ce este domeniul de aplicare și de ce este atât de important. Domeniul de aplicare definește limitele și durata de viață a variabilelor sau a oricărei memorii utilizate de un program. O variabilă este “fara scop” când nu mai poate fi accesat de nici un cod (atunci când colectorul de gunoi se află în). Iată un exemplu:
funcția matematică () int firstNumber = 1; int secondNumber = 2; tipăriți (firstNumber + secondNumber); // nu va funcționa
Acest exemplu nu se va compila. Variabila firstNumber este în cadrul matematica funcția, astfel încât este domeniul de aplicare. Nu poate fi accesat din afara funcției în care a fost declarată. Acesta este un concept de programare important, și înțelegerea este crucială pentru a lucra cu pointeri.
Acest mod de manipulare a memoriei este numit grămadă. Este modul în care marea majoritate a programelor funcționează. Nu trebuie să înțelegeți indicatorii să o utilizați și este destul de bine structurat. Dezavantajul stiva este viteza. Deoarece calculatorul trebuie să atribuie memorie, să țină evidența variabilelor și să ruleze colecția de gunoi, există o mică cheltuială. Acest lucru este bine pentru programele mai mici, dar ce despre sarcinile de înaltă performanță sau aplicații grele de date?
Introduceți: indicații.
pointeri
La suprafață, indicii sună simplu. Acestea fac trimitere (arata spre) o locație în memorie. Acest lucru nu pare diferit “regulat” variabilele de pe stivă, dar credeți-mă, există o mare diferență. Indicatorii sunt stocați pe morman. Acesta este opusul stivei - este mai puțin organizat, dar este mult mai rapid.
Să vedem cum sunt atribuite variabilele în stivă:
int numberOne = 1; int numberTwo = numberOne;
Aceasta este o sintaxă simplă; Variabila numarul doi conține numărul unu. Valoarea este copiată în timpul alocării de la numarul unu variabil.
Dacă ați vrut să obțineți adresa de memorie a unei variabile, în loc de valoarea acesteia, trebuie să utilizați semnul ampersand (&). Aceasta se numește adresa operator și este o parte esențială a setului de instrumente pentru indicatori.
int numberOne = 1; int numberTwo = & numberOne;
Acum numarul doi variabil puncte într-o locație de memorie, mai degrabă decât să obțineți numărul unu copiat în locația sa proprie, nouă de memorie. Dacă ați fi ieșit la ieșire această variabilă, nu ar fi numărul unu (chiar dacă acesta este stocat în locația de memorie). Ar fi dat locația de memorie (probabil ceva de genul 2167, deși variază în funcție de sistem și de memoria RAM disponibilă). Pentru a accesa valoarea stocată într-un indicator, în loc de locația de memorie, trebuie să endiancu pointerul. Aceasta accesează direct valoarea, care ar fi numărul unu în acest caz. Iată cum dereference un pointer:
int numberTwo = * numberOne;
dereference operator este un asterisc (*).
Acest lucru poate fi un concept dificil de înțeles, așa că haideți să mergem din nou peste el:
- adresa operatorul (&) stochează adresa memoriei.
- dereference operator (*) accesează valoarea.
Sintaxa se modifică ușor când se declară indicii:
int * myPointer;
Tipul de date din int aici se referă la tipul de date indicatorul puncte la, și nu tipul de pointer în sine.
Acum că știți ce indicii sunt, puteți să faceți niște trucuri cu ele! Când este utilizată memoria, sistemul de operare pornește secvențial. Vă puteți gândi la RAM ca găuri de porumbei. Multe găuri pentru a stoca ceva, doar unul poate fi folosit deodată. Diferența este că aceste găuri de porumbei sunt numerotate. La atribuirea memoriei, sistemul dvs. de operare începe de la cel mai mic număr și funcționează. Nu va sari niciodata intre numerele aleatoare.
Când lucrați cu indicatori, dacă ați atribuit o matrice, puteți naviga cu ușurință la următorul element prin simpla incrementare a indicatorului.
Iată unde devine interesant. Când treceți valorile unei funcții (folosind variabilele stocate în stivă), aceste valori se copiază în funcție. Dacă acestea sunt mari variabile, programul le stochează de două ori. Când funcția dvs. este terminată, este posibil să aveți nevoie de o modalitate de a returna aceste valori. Funcțiile pot reveni, în general, la un singur lucru - deci dacă ați fi vrut să reveniți la două, trei sau patru lucruri?
Dacă transmiteți un indicator la funcția dvs., numai adresa memoriei este copiată (care este mică). Acest lucru vă salvează foarte mult procesorul! Poate că indicatorul dvs. indică o gamă imensă de imagini - nu numai că funcția dvs. poate funcționa exact pe aceleași date stocate în aceeași locație de memorie, dar odată ce este terminată, nu este nevoie să returnați nimic. ordinat!
Totuși, trebuie să fii foarte atent. Pointerii pot totuși să iasă din spațiu și să fie colectați de colectorul de gunoi. Valorile stocate în memorie, cu toate acestea, nu se colectează. Aceasta se numește scurgere de memorie. Nu mai puteți accesa datele (deoarece indicii au fost distruși), dar este încă folosită memoria. Acesta este un motiv obișnuit pentru multe programe să se prăbușească și poate eșua spectaculos dacă există o cantitate mare de date. De cele mai multe ori, sistemul dvs. de operare va ucide programul dvs. dacă aveți o scurgere mare (folosind mai multă memorie RAM decât sistemul), dar acest lucru nu este de dorit.
Instrumentele de depanare pot fi un coșmar, mai ales dacă lucrați cu cantități mari de date sau lucrați în bucle. Dezavantajele lor și dificultatea de a înțelege sunt într-adevăr merită compensațiile pe care le câștigi în performanță. Deși nu uitați, ele nu pot fi întotdeauna necesare.
Asta e pentru ziua de azi. Sper că ați învățat ceva util în legătură cu un subiect complex. Desigur, nu am acoperit tot ceea ce este de știut - este un subiect foarte complex. Dacă sunteți interesat să aflați mai multe, recomand C ++ în 24 de ore.
Dacă acest lucru a fost un pic mai complex, aruncăm o privire la ghidul nostru pentru cele mai simple limbi de programare 6 Limbi de programare mai ușor de învățat pentru începători 6 Limbi de programare mai ușoare de învățat pentru începători Învățarea de programare este despre găsirea limbii potrivite la fel de mult ca despre procesul de edificare. Iată primele șase limbi de programare cele mai bune pentru începători. Citeste mai mult .
Ați învățat cum funcționează indicii de azi? Aveți orice sfaturi și trucuri pe care doriți să le împărtășiți altor programatori? Săriți în comentarii și împărtășiți-vă gândurile de mai jos!
Explorați mai multe despre: Programare.