Annons
Oavsett om du inser det eller inte, använder de allra flesta program du har använt pekare på något sätt. Du kanske har upplevt en NullPointerException vid något tillfälle. Som programmerare kommer kod du skriver mer än troligt att använda pekare, även om du inte har implementerat dem själv.
Idag visar jag hur pekare fungerar, så du kanske vill kolla in hur matriser och listor fungerar Hur arrayer och listor fungerar i PythonMatriser och listor är några av de mest användbara datastrukturerna i programmering - även om få människor använder dem till sin fulla potential. Läs mer för en programmeringsprimer. Den här artikeln kommer att vara mer teoribaserad än vanligt, men håll dig fast, pekarna är väldigt komplexa!
Kompileringskod
Innan du gräver i pekare måste du förstå hur kod byggs och körs - kanske vet du det redan. Det här avsnittet kommer att ha ganska allmänna uttalanden - saker som gäller för majoritet av språk, men inte nödvändigtvis alla.
Låt oss ta saker tillbaka till början. Varje dator
använder binär Vad är binärt? [Teknisk förklaring]Med tanke på att binär är så absolut grundläggande för att det finns datorer, verkar det konstigt att vi aldrig har behandlat ämnet förut - så idag trodde jag att jag skulle ge en kort överblick över vilken binär ... Läs mer , en serie av nollor som utgör modern teknologi som vi känner till den. Det är extremt svårt att koda någonting i binär (filerna skulle vara väldigt förvirrande), eftersom det här är de råa instruktionerna som du behöver centrala behandlingsenheten eller CPU för att fungera Vad är en CPU och vad gör den?Beräkningsförkortningar är förvirrande. Vad är en CPU ändå? Och behöver jag en fyr- eller dual-core processor? Vad sägs om AMD eller Intel? Vi är här för att förklara skillnaden! Läs mer . Detta kallas Maskinkod.Nästa steg upp från maskinkoden är hopsättning. Detta är ett något mänskligt läsbart format. Det är fortfarande komplext att programmera i, men det är möjligt. Montering består av en serie enkla kommandon för att utföra uppgifter och är känd som en låg nivå programmeringsspråk. Det är möjligt att skriva komplexa program, men det är svårt att uttrycka abstrakta begrepp och kräver mycket hänsyn.
Många videospel och högpresterande applikationer har några av de logiker som skrivs i montering, eftersom vissa verkliga hastighetsökningar kan hittas om du vet vad du gör. För de allra flesta programmeringsprojekt behöver du dock inte känna till någon montering alls.
Så om maskinkoden är för svår att skriva och montering är för svår att programmera, vad skriver du kod med? Här är var hög nivå språk kommer in. Språk på hög nivå gör programmen lätta att skriva. Du kan programmera på något som liknar ditt modersmål och det är lätt att uttrycka komplexa algoritmer. Du kanske har hört talas om många högnivåspråk (och du har definitivt använt ett program skrivet i dem):
- GRUNDLÄGGANDE
- C ++
- Läspa
Dessa språk är mycket gamla nu och många utvecklades i början av 1950-talet! Nästan varje modernt programmeringsspråk är ett språk på hög nivå, inklusive PHP och Python. Det finns fler språk som uppfinns varje dag (även om det förmodligen finns tillräckligt nu), men hur exakt fungerar din kod fortfarande ordentligt om datorer kräver maskinkod?
Här kommer sammanställningen in. En kompilator är ett program som konverterar din höga nivå till en form som kan köras. Detta kan vara ett annat språk på hög nivå, men det är vanligtvis montering. Vissa språk (som Python eller Java) konverterar din kod till ett mellanstadium som heter bytekod. Detta kommer att behöva sammanställas igen vid ett senare datum, vilket vanligtvis görs på begäran, till exempel när programmet körs. Detta kallas precis i tid sammanställning, och det är ganska populärt.
Minneshantering
Nu när du vet hur programmeringsspråk fungerar, låt oss titta på minneshantering på högnivåspråk. För dessa exempel kommer jag att använda pseudokod - kod skriven inte på något specifikt språk, men används för att visa begrepp snarare än exakt syntax. Idag kommer detta mest att likna C ++ eftersom det är det bästa språket på hög nivå (enligt min mening).
För det här avsnittet hjälper det om du har förståelse för hur RAM fungerar En snabb och smutsig guide till RAM: Vad du behöver vetaRAM är en avgörande komponent i varje dator, men det kan vara förvirrande. Vi delar upp det i lättfattliga termer du förstår. Läs mer .
De flesta språk har variabler - behållare som lagrar en del data. Du måste definiera datatypen uttryckligen. Vissa dynamiskt typade språk som Python eller PHP hanterar detta åt dig, men de måste fortfarande göra det.
Säg att du har en variabel:
int myNumber;
Denna kod deklarerar en variabel som heter mitt nummer, och ger den en datatyp av heltal. När den har sammanställts tolkar datorn detta kommando som:
"Hitta lite tomt minne och reservera ett utrymme som är tillräckligt stort för att lagra ett heltal"
När detta kommando har körts, kan den minnet inte användas av ett annat program. Det innehåller inga data ännu, men det är reserverat för din myNumber-variabel.
Tilldela nu ett värde till din variabel:
myNumber = 10;
För att slutföra denna uppgift kommer din dator åtkomst till den reserverade minnesplatsen och ändrar det värde som finns lagrat där till detta nya värde.
Nu är allt bra och bra, men hur blir minnesplatserna obehållna? Om program reserverade allt minne de gillar skulle RAM-minnet fyllas omedelbart - det skulle göra för en mycket långsamt system.
För att undvika denna potentiella problem implementerar många språk a skräp samlare, används för att förstöra variabler (och därför släppa de reserverade minnesplatserna) som har gått ur sikte.
Du undrar kanske vad omfattningen är och varför det är så viktigt. Scope definierar gränserna och livslängden för variabler eller vilket minne som används av ett program. En variabel är "utanför räckvidden" när den inte längre kan nås med någon kod (det är när sopor samlaren träder in). Här är ett exempel:
funktionsmatematik () {int firstNumber = 1; } int secondNumber = 2; tryck (firstNumber + secondNumber); // kommer inte att fungera
Detta exempel kommer inte att kompilera. Variabeln firstNumber är inom matte funktion, så det är det omfattning. Det går inte att komma åt det utanför funktionen där den har deklarerats. Detta är ett viktigt programmeringskonceptoch att förstå det är avgörande för att arbeta med pekare.
Detta sätt att hantera minne kallas stack. Det är så som de allra flesta program fungerar. Du behöver inte förstå pekare för att använda det och det är ganska väl strukturerat. Nackdelen med stacken är hastigheten. Eftersom datorn måste tilldela minne, hålla reda på variabler och köra sopor, finns det en liten overhead. Det är bra för mindre program, men hur är det med högpresterande uppgifter eller datatunga applikationer?
Ange: pekare.
pekare
På ytan låter pekare enkelt. De refererar till (peka mot) en plats i minnet. Detta kanske inte verkar annorlunda än "vanliga" variabler på stacken, men lita på mig, det finns en enorm skillnad. Pekare lagras på högen. Detta är motsatsen till stacken - den är mindre organiserad, men är mycket snabbare.
Låt oss titta på hur variabler tilldelas i bunten:
int nummer En = 1; int nummerTvå = antal En;
Detta är enkel syntax; Variabeln nummer två innehåller nummer ett. Det är värdet som kopieras över under uppdraget från nummer ett variabel.
Om du ville få minnesadress av en variabel, istället för det är värdet, måste du använda ampersand-tecknet (&). Detta kallas adress till operatör och är en väsentlig del av din pekare verktygssats.
int nummer En = 1; int numberTwo = & numberOne;
Nu den nummer två variabel poäng till en minnesplats istället för att få den nummer som kopieras över till den egna, nya minnesplatsen. Om du skulle mata ut denna variabel skulle det inte vara nummer ett (även om det är lagrat i minnesplatsen). Det skulle mata ut dets minnesplats (förmodligen något som 2167, även om det varierar beroende på systemet och tillgängligt RAM). För att komma åt värdet som är lagrat i en pekare måste du göra det istället för minnesplatsen dereference pekaren. Detta får direkt tillgång till värdet, vilket skulle vara nummer ett i detta fall. Så här leder du till en pekare:
int nummerTo = * antal En;
De dereference operatör är en asterisk (*).
Detta kan vara ett svårt begrepp att förstå, så låt oss gå igenom det igen:
- De adress till operator (&) lagrar minnesadressen.
- De dereference operatör (*) öppnar värdet.
Syntaxen ändras något när deklarerar pekare:
int * myPointer;
Datatypen av int här hänvisar till datatypen pekaren poäng till och inte typen av pekaren själv.
Nu när du vet vad pekare är kan du göra några riktigt snygga trick med dem! När minnet används startar operativsystemet sekventiellt. Du kan tänka på RAM som duvahål. Många hål för att lagra något, bara ett kan användas på en gång. Skillnaden här är att alla duvahål är numrerade. När du tilldelar minne startar ditt operativsystem på det lägsta antalet och fungerar. Det hoppar aldrig runt mellan slumpmässiga nummer.
När du arbetar med pekare, om du har tilldelat en matris, kan du enkelt navigera till nästa element genom att enkelt öka pekaren.
Här blir det intressant. När du skickar värden till en funktion (med variabler lagrade i stacken) kopieras dessa värden till din funktion. Om det här är stora variabler lagrar du dem nu två gånger. När din funktion är klar kan du behöva ett sätt att returnera dessa värden. Funktioner kan generellt bara returnera en sak - så om du vill returnera två, tre eller fyra saker?
Om du skickar en pekare till din funktion kopieras bara minnesadressen (som är liten). Detta sparar din CPU mycket arbete! Kanske pekaren pekar på en enorm bildbild - inte bara kan din funktion fungera på exakt samma sätt data lagras på exakt samma minnesplats, men när det är gjort behöver du inte återvända något. Propert!
Du måste dock vara mycket försiktig. Pekare kan fortfarande gå utanför räckvidden och samlas in av avfallssamlaren. De värden som lagras i minnet samlas dock inte in. Detta kallas ett minnesläcka. Du kan inte längre få åtkomst till data (eftersom pekarna har förstörts), men det använder fortfarande upp minnet. Detta är ett vanligt skäl för att många program kraschar, och det kan misslyckas spektakulärt om det finns en stor mängd data. För det mesta kommer ditt operativsystem att döda ditt program om du har en stor läcka (med mer RAM än vad systemet har), men det är inte önskvärt.
Felsökningspekare kan vara en mardröm, särskilt om du arbetar med stora mängder data eller arbetar i slingor. Deras nackdelar och svårigheter att förstå är verkligen värda de utbyten du får i prestanda. Trots att kom ihåg, kanske de inte alltid krävs.
Det är det för idag. Jag hoppas att du har lärt dig något användbart om ett komplext ämne. Naturligtvis har vi inte täckt allt som finns att veta - det är ett mycket komplicerat ämne. Om du är intresserad av att lära dig mer rekommenderar jag starkt C ++ inom 24 timmar.
Om det här var lite komplicerat, ta en titt på vår guide till de enklaste programmeringsspråken 6 enklaste programmeringsspråk att lära sig för nybörjareAtt lära sig programmera handlar om att hitta rätt språk lika mycket som det handlar om uppbyggnadsprocessen. Här är de sex bästa enklaste programmeringsspråken för nybörjare. Läs mer .
Läste du hur pekare fungerar idag? Har du några tips och tricks som du vill dela med andra programmerare? Hoppa in i kommentarerna och dela dina tankar nedan!
Joe är en examen i datavetenskap från University of Lincoln, Storbritannien. Han är en professionell mjukvaruutvecklare, och när han inte flyger drönare eller skriver musik kan han ofta hitta foton eller producera videor.