En introduktion till pekare för programmerare

En introduktion till pekare för programmerare / Programmering

Oavsett om du inser det eller inte, använder den stora majoriteten av de program du har använt på några sätt tips. Kanske har du upplevt en NullPointerException vid något tillfälle. Som programmerare kommer den kod du skriver att använda mer än troligt pekare, även om du inte själv har implementerat dem.

Idag visar jag hur pointer fungerar, så du kanske vill kolla hur arrays och listor fungerar. Hur Arrays and Lists Arbetar i Python. Hur Arrays and Lists fungerar i Python Arrays 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. Denna artikel kommer att vara mer teoribaserad än vanligt, men hålla fast vid det, pekare är väldigt komplexa!

Sammanställningskod

Innan du gräver i pekare måste du förstå hur kod byggs och körs - kanske vet du redan detta. 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 av dem.

Låt oss ta saker tillbaka till början. Varje dator använder binär Vad är binärt? [Teknologi förklarad] Vad är binärt? [Teknologi förklaras] Eftersom binär är så helt grundläggande för förekomsten av datorer, verkar det konstigt att vi aldrig har tagit upp ämnet förut - så idag trodde jag att jag skulle ge en kort översikt över vilket binärt ... Läs mer, en serie av sådana och nollor som utgör modern teknik som vi känner till det. Det är extremt svårt att koda någonting i binär (filerna skulle vara mycket förvirrande), eftersom det här är de rätta instruktionerna som behövs av din centrala behandlingsenheten eller CPU för att fungera Vad är en CPU och vad gör den? Vad är en CPU och vad gör den? Computing akronymer är förvirrande. Vad är en CPU i alla fall? Och behöver jag en quad eller dual-core processor? Vad sägs om AMD eller Intel? Vi är här för att hjälpa till att förklara skillnaden! Läs mer . Detta är känt som Maskinkod.

Nästa steg upp från maskinkoden är hopsättning. Detta är ett något mänskligt läsbart format. Medan det fortfarande är komplext att programmera in, är det möjligt. Montering består av en serie enkla kommandon för att utföra uppgifter, och är känd som a låg nivå programmeringsspråk. Det är möjligt att skriva komplicerade program, men det är svårt att uttrycka abstrakta begrepp och kräver mycket övervägande.

Många videospel och högpresterande applikationer har en del av logiken som skrivs i montering, eftersom vissa reella hastighetsökningar kan hittas om du vet vad du gör. Men för de allra flesta programmeringsprojekt behöver du inte känna till någon enhet 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 där hög nivå språk kommer in. Språk på hög nivå gör programmen enkla att skriva. Du kan programmera i 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 språk på hög nivå (och du kommer definitivt att ha använt ett program skrivet i dem):

  • GRUNDLÄGGANDE
  • C++
  • Läspa

Dessa språk är väldigt gamla nu, och många utvecklades i början av 1950-talet! Nästan alla moderna programmeringsspråk är ett högnivå språk, inklusive PHP och Python. Det finns flera språk som uppfunnits varje dag (även om det förmodligen är tillräckligt nu), men hur exakt fungerar din kod fortfarande korrekt om datorer kräver maskinkod?

Här är var kompilering kommer in. En kompilator är ett program som konverterar din högnivåkod till en blankett som kan utföras. Det här kan vara ett annat språk på hög nivå, men det är vanligtvis sammansättning. Vissa språk (som Python eller Java) konverterar din kod till ett mellanstadium som heter bytekod. Detta kommer att behöva kompilera igen vid ett senare tillfälle, vilket vanligtvis görs på begäran, till exempel när programmet körs. Detta är känt som precis i tid kompilering, och det är ganska populärt.

Minneshantering

Nu när du vet hur programmering av språk fungerar, låt oss titta på minneshantering på högnivå språk. För dessa exempel använder jag pseudokod - kod skriven inte på något specifikt språk, men brukade visa begrepp snarare än exakt syntax. Idag kommer det här mest att likna C ++ eftersom det är det bästa högnivåspråket (enligt min mening).

För det här avsnittet kommer det att hjälpa dig om du har en förståelse för hur RAM fungerar. En snabb och smutsig guide till RAM: Vad du behöver veta En snabb och smutsig guide till RAM: Vad du behöver veta RAM är en viktig del av varje dator , men det kan vara förvirrande att förstå om du inte är en techguru. I det här inlägget bryter vi ner det på ett enkelt sätt. Läs mer .

De flesta språk har variabler - behållare som lagrar vissa data. Du måste uttryckligen definiera datatypen. Vissa dynamiskt typade språk som Python eller PHP hanterar detta för dig, men de måste fortfarande göra det.

Säg att du har en variabel:

int minNumber;

Denna kod deklarerar en variabel som heter mitt nummer, och ger den en datatyp av heltal. När du kompilerat 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 det här kommandot har körts kan inte den här minnet 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 det reserverade minnesplatsen och ändrar vilket värde som lagras där, till det nya värdet.

Nu är det bra och bra, men hur får minnesplatserna obesvarade? Om program reserverade allt minne som de vill, skulle RAM-minne fylla omedelbart - det skulle göra för en mycket långsamt system.

För att undvika detta potentiella problem, implementerar många språk a skräp samlare, brukade förstöra variabler (och därmed släppa de reserverade minnesplatserna) som har gått ur sikte.

Du kanske undrar vad omfattningen är och varför det är så viktigt. Omfattning definierar gränserna och livslängden för variabler eller något minne som används av ett program. En variabel är “ur sikte” när det inte längre kan nås av någon kod (det är när sopor samlar in). Här är ett exempel:

funktion matematik () int firstNumber = 1;  int sekundNumber = 2; skriva ut (första nummer + andra nummer); // kommer inte att fungera

Detta exempel kommer inte att kompileras. Variabeln firstNumber ligger inom matte funktion, så det är dess omfattning. Den kan inte nås utanför den funktion där den har deklarerats. Detta är ett viktigt programmeringskoncept, och förstå att det är viktigt att arbeta med pekare.

Detta sätt att hantera minnet kallas stack. Det är så som de flesta programmen fungerar. Du behöver inte förstå pekare för att använda den, och det är ganska välstrukturerad. Nackdelen med stapeln är hastigheten. Eftersom datorn måste tilldela minnet, hålla reda på variabler och köra sopkollektionen finns det en liten omkostnad. Det här är bra för mindre program, men vad sägs om högpresterande uppgifter eller data tunga applikationer?

Ange: pekare.

pekare

På ytan låter pekarna enkelt. De refererar (peka mot) en plats i minnet. Det här kanske inte verkar annorlunda än “regelbunden” variabler på stacken, men lita på mig, det är en stor skillnad. Pekare lagras på högen. Detta är motsatsen till stacken - det är mindre organiserat, men är mycket snabbare.

Låt oss titta på hur variabler tilldelas på stapeln:

int numberOne = 1; int numberTwo = numberOne;

Detta är enkel syntax; Variabeln nummer två innehåller nummer ett. Det är värdet kopieras över under uppdraget från nummer ett variabel.

Om du ville få minnesadress av en variabel, istället för dess värde måste du använda ampersand-tecknet (&). Detta kallas adress till operatör, och är en väsentlig del av din pekare verktygslåda.

int numberOne = 1; int numberTwo = & number One;

Nu den nummer två variabel poäng till ett minnesläge, istället för att få nummer ett kopierat till det egna, nya minnesplatsen. Om du skulle mata ut denna variabel, skulle det inte vara nummer ett (även om det lagras i minnesplatsen). Det skulle mata ut sin minnesplats (förmodligen något som 2167, även om det varierar beroende på system och tillgängligt RAM). För att komma åt det värde som lagrats i en pekare, istället för minnesplatsen måste du dereference pekaren. Detta öppnar värdet direkt, vilket skulle vara nummer ett i det här fallet. Så här ser du bort en pekare:

int numberTwo = * numberOne;

De dereference operatör är en asterisk (*).

Detta kan vara ett svårt begrepp att förstå, så låt oss gå över det igen:

  • De adress till operatören (&) lagrar minnesadressen.
  • De dereference operatör (*) får tillgång till värdet.

Syntaxen ändras något när de förklarar pekare:

int * myPointer;

Datatypen av int här hänvisar till datatypen pekaren poäng till och inte typ av pekaren själv.

Nu när du vet vilka pekar är, kan du göra några riktigt snygga knep med dem! När minnet används börjar ditt operativsystem sekventiellt. Du kan tänka på RAM som duvhål. Många hål att lagra något, bara en kan användas samtidigt. Skillnaden här är, dessa duvahål är alla numrerade. När du tilldelar minnet startar operativsystemet ditt med det lägsta antalet och fungerar. Det kommer aldrig att hoppa runt mellan slumpmässiga nummer.

När du arbetar med pekare, om du har tilldelat en array, kan du enkelt navigera till nästa element genom att enkelt öka din pekare.

Här är det som blir intressant. När du skickar värden till en funktion (med hjälp av variabler lagrade på stapeln), kopieras dessa värden till din funktion. Om dessa är stora variabler, lagrar du programmet två gånger nu. När din funktion är klar kan du behöva ett sätt att returnera dessa värden. Funktioner kan i allmänhet bara returnera en sak - så vad om du ville återvända två, tre eller fyra saker?

Om du skickar en pekare till din funktion kopieras endast minnesadressen (vilken är liten). Detta sparar din CPU mycket arbete! Kanske pekaren pekar på en stor bildgrupp - inte bara kan din funktion fungera på exakt samma data som lagras på exakt samma minnesplats, men när det är klart, behöver du inte returnera någonting. Propert!

Du måste dock vara mycket försiktig. Pekare kan fortfarande gå ur räckvidd och samlas in av sopkollektor. Värdena som lagras i minnet samlas emellertid inte. Detta kallas en minnesläcka. Du kan inte längre komma åt data (som pekarna har förstörts), men det använder fortfarande upp minne. Det här är en vanlig orsak till att många program kraschar, och det kan misslyckas spektakulärt om det finns en stor mängd data. Större delen av tiden kommer ditt operativsystem att döda ditt program om du har en stor läckage (med mer RAM än systemet har), men det är inte önskvärt.

Felsökningspunkter kan vara en mardröm, speciellt om du arbetar med stora mängder data eller arbetar i loopar. Deras nackdelar och svårigheter att förstå är verkligen värda de avvägningar du får i prestanda. Även om du kommer 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 vi behöver veta - det är ett mycket komplext ämne. Om du är intresserad av att lära dig mer, rekommenderar jag C ++ på 24 timmar.

Om det här var lite komplext, ta en titt på vår guide till de enklaste programmeringsspråken. 6 Lättaste programmeringsspråk att lära sig för nybörjare. 6 Lättaste programmeringsspråk att lära sig för nybörjare. Lära sig att 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åk för nybörjare. Läs mer .

Lärde du dig hur pekare arbetar idag? Har du några tips och tricks du vill dela med andra programmerare? Hoppa in i kommentarerna och dela dina tankar nedan!

Utforska mer om: Programmering.