Att använda pekare i. C-kod



Relevanta dokument
Övningar Dag 2 En första klass

Föreläsning 10. Pekare (Pointers)

Om include-filer i PHP

*Pekarvärden *Pekarvariabler & *

Programmeringsteknik med C och Matlab

OOP Objekt-orienterad programmering

1 Funktioner och procedurell abstraktion

Tentamen OOP

Föreläsning 2 Objektorienterad programmering DD1332. Typomvandling

Introduktion till arv

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

Föreläsning 4: Poster

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Föreläsning 6: Introduktion av listor

Elektroteknik MF1016 föreläsning 9 MF1017 föreläsning 7 Mikrodatorteknik

Dagens föreläsning. Repetition. Repetition - Programmering i C. Repetition - Vad C består av. Repetition Ett första C-program

1 Texthantering. 1.1 Typen char. Exempel, skriv ut alfabetet

Hantering av textsträngar och talsträngar. William Sandqvist

Föreläsning 3.1: Datastrukturer, en översikt

Föreläsning 6 pekare och pekare tillsammans med arrayer

4 Sammansatta datatyper

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Objektorienterad programmering i Java

#include <stdio.h> #include <string.h>

Det finns många flaggor till g++,

C-programmering, föreläsning 2 Jesper Wilhelmsson

Föreläsning 1 & 2 INTRODUKTION

Grunderna i stegkodsprogrammering

Föreläsning 5: Introduktion av pekare

Pekare. Pekare. Varför använder vi pekare? Vad är en pekare? Pekare. Deklaration/initiering av pekare

SMD 134 Objektorienterad programmering

Algoritmanalys. Genomsnittligen behövs n/2 jämförelser vilket är proportionellt mot n, vi säger att vi har en O(n) algoritm.

Javisst! Uttrycken kan bli komplicerade, och för att få lite överblick över det hela så gör vi det så enkelt som möjligt för oss.

Digital Display VDS / Bus2

Föreläsning 2: Avlusning och antilustekniker

Chapter 3: Using Classes and Objects

Ulf Assarsson. Grundläggande C-programmering del 2 Pekare och Arrayer. Läromoment:

Programmering av inbyggda system. Pekare och Arrayer. Viktor Kämpe

LEU240 Mikrodatorsystem

Programmering, grundkurs, 8.0 hp, Elektro, KTH, hösten 2010

trafiksimulering Intro OU5 trafiksimulering

TDIU01 - Programmering i C++, grundkurs

Uppgift (poäng) 1 (2) 2 (3) 3 (4) 4 (4) 5 (3) 6 (4) 7 (6) 8 (6) 9 (8) Summa

Programmering A C# VT Ett kompendie över Programmering A (50p) i c# Stefan Fredriksson

Effektpedal för elgitarr

Föreläsning 7 Strängar

Felsökning av mjukvara

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

Inledande programmering med C# (1DV402) 27+15=42 1 (22)

PROGRAMMERING 2 GRUNDLÄGGANDE SEMANTIK 4

Skizz till en enkel databas

Sätt att skriva ut binärträd

Tentaupplägg denna gång

Tentamen. 2D4135 vt 2005 Objektorienterad programmering, design och analys med Java Lördagen den 28 maj 2005 kl

Innehåll. Introduktion till objektorientering. OOP (objektorienterad programmering) Objekt, instanser, klasser

Datorteknik 2 (AVR 2)

TDDC76 - Programmering och Datastrukturer

Minnestilldelning (allokering) och frigörande (avallokering) av minne

TDIU01 - Programmering i C++, grundkurs

Tentamen i Programmering grundkurs och Programmering C

Objektorienterad programmering D2

Användarhandledning Version 1.2

Grundläggande programmering med C# 7,5 högskolepoäng

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Hjälpmedel för kompilatorkonstruktion, DVB004

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Agenda. Arrayer deklaration, åtkomst Makron Flerdimensionella arrayer Initiering Strängar Funktioner och arrayer. Övningar nu och då

Dagens föreläsning. Repetition. Repetition - Programmering i C. Repetition - Vad C består av. Repetition Ett första C-program

TUTORIAL: SAMLING & KONSOLL

Lathund. C för inbyggda system

TENTAMEN CD5250. Objektorienterad programutveckling med C++, 5p. Datum: , Tid: 14:00-19:00

Instruktion för att slutföra registreringen

C++ Lektion Tecken och teckenfält

Funktionspekare, inledning: funktionsanropsmekanismen. Anrop via pekare

Föreläsning 8 Programmeringsteknik och Matlab 2D1312/2D1305. Klass Object, instans av klass public/private Klassvariabler och klassmetoder

Tentaupplägg denna gång

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

Ekvationssystem - Övningar

Dynamiskt minne. Vad är dynamiskt minne Motivering Hur gör man i C Övningar

Tänk på följande: Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

HI1024 Programmering, grundkurs TEN

Lathund. C för inbyggda system

Föreläsning 6: Metoder och fält (arrays)

Programmering B med Visual C

DELPROV 1 I DATAVETENSKAP

CPU. Carry/Borrow IX. Programräknare

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Lösningsförslag, tentamen FYTA11 Javaprogrammering

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

PROGRAMMERING A VC# 2008 EXPRESS UTVECKLINGSVERKTYGET VISUAL C#

Funktionens deklaration

Programmering av inbyggda system. Pekare och Arrayer. Ulf Assarsson. Originalslides av Viktor Kämpe

IS1200 Datorteknik. Övning CE_O4 Maskinnära programmering med C Förberedelser till hemlaboration 1

Föreläsning 5 (6) Metoder. Metoder Deklarera. Metoder. Parametrar Returvärden Överlagring Konstruktorer Statiska metoder tostring() metoden javadoc

NXT LEGO-robot laboration Programmering och felsökning av en LEGOrobot

SORTERING OCH SÖKNING

grundläggande C++, funktioner m.m.

Programsystemkonstruktion med C++: Övning 1. Karl Palmskog september 2010

Transkript:

Att använda pekare i C-kod (Bör användas av de som känner sig lite hemma med C-programmering!) Rev 1, 2005-11-23 av Ted Wolfram www.wolfram.se

Syfte: Man kan tycka att det är komplicerat att använda pekare när man programmerar i C men det finns tre stora fördelar som man måste beakta: Programmet kommer att gå mycket snabbare samt att man slipper använda globala variabler som tar upp en massa ramminne. Man kommer även att spara ROM-minne också om man gör det på ett snyggt sätt vilket visas i exemplen nedan Vad är en pekare? En pekare är inget annat än en variabel som pekar på en minnesadress. Detta är väldigt användbart då man ska skicka långa strängar eller arrayer till en funktion och sedan göra något med den som t.ex. förändrar dess värde innan man går vidare. Med pekare räcker det att bara skicka startadressen för hela textsträngen! Även om man bara skickar in en textsträng för utskrift på t.ex. en display är det att föredra om man använder pekare. Man slipper allokera en massa RAM-minne och det hela går snabbare. Varför använda dessa På följande sidor har jag bifogat tre exempel på hur effektivt det är med pekare istället för andra lösningar Dessa exempel är kompilerade med HITECH PICC18 v8.35pl2 och avsedda att användas med PIC18 serien. Alla program utför samma sak; Det finns två arrayer, array1 och array2, de är båda 200 byte långa och ges två olika startvärden. Därefter är vitsen att man ska öka alla värden i de båda arrayerna med 1. Givetvis är detta ett enkelt exempel på hur man kan göra, vanligtvis gör ju funktionen något helt annat än att bara addera 1 till var indexvärde

Exempel 1 Här använder vi inte pekare utan man anropar en funktion som ökar värdet med 1, sedan sparas det i en global variabel som man sedan måste kopiera resultatet från för att få tillbaka det förändrade värdet till string1 eller string2. Så här måste man göra om man vill få tillbaka resultatet i den sträng som skickades in i funktionen och använda det till något vettigt. #include <pic18.h> static char glob_array[200]; void main_utanpekare(unsigned char array[]) glob_array[i] = array[i] + 1; // Öka vart index med 1... void main() static unsigned char array1[200], array2[200]; // Ge array1 & array2 startvärden... array1[i] = i; array2[i] = 200 - i; main_utanpekare(array1); // Öka strängens värde med 1 array1[i] = glob_array[i]; // Kopiera till array1 main_utanpekare(array2); array2[i] = glob_array[i]; // Samma sak med array2... Efter att ha kompilerat detta program upptog det: 230 byte ROM 603 byte RAM Tiden det tog att köra programmet från main_utanpekare(array1); till tog 16418 instruktionscykler!

Exempel 2 Här använder vi pekare istället och då ser programmet ut enligt följande: #include <pic18.h> void main_pekare(unsigned char *parray) *parray = *parray + 1; // Öka värdet med 1.. // OBS! Det går inte att skriva // *parray++!!!! parray++; // Öka pekaradressen med 1... void main() static unsigned char array1[200], array2[200]; // Ge array1 & array2 startvärden... array1[i] = i; array2[i] = 200 - i; main_pekare(&array1[0]); // Öka arrayens värde med 1 main_pekare(&array2[0]); // Samma sak med array2... Efter att ha kompilerat detta program upptog det: 138 byte ROM Exempel 1 blev 1,6 ggr större, detta gäller givetvis inte alls för större program! 403 byte RAM Här blev det 200 byte mindre pga. att det inte behövs någon global variabel! Det viktigaste av allt är dock att tiden det tog att köra de två funktionerna main_pekare(&array1[0]); och main_pekare(&array2[0]); endast blev: 4026 instruktionscykler! Det är mer än 4 ggr snabbare!

Exempel 3 Mitt exempel gör ju inget annat än adderar 1 till alla element och i och med det går det givetvis att hoppa över funktionsanropet och göra en forloop som sköter det hela för var array. Givetvis krävs denna loop för var array, vilket man slipper om man har en funktion som sköter detta. Detta funkar ju inte om nu funktionen utför lite mer avancerade saker än att bara addera 1 till arrayen för då blir det ohållbart mycket kod att kompilera. (Samma kod till var array som ska bearbetas!) OK, då visar vi hur det kan gå till. #include <pic18.h> void main() static unsigned char array1[200]; static unsigned char array2[200]; // Ge array1 & array2 startvärden... array1[i] = i; array2[i] = 200 - i; array1[i]++; // Öka array1 med 1... array2[i]++; // Öka array2 med 1... Efter att ha kompilerat detta program upptog det: 130 byte ROM Exempel 2 blev faktiskt 1,1 ggr större, men lägg till en array till som ska modifieras så blir det större än Exempel 2! 400 byte RAM Här blev det bara 400 byte i RAM. Hur lång tid tog det då att köra de två for-looparna? Jo det tog 4800 instruktionscykler vilket innebär att det tog 1,2 ggr längre tid än Exempel 2! Skulle man sedan ha 3 arrayer att kopiera så skulle Exempel 3 ta upp mer ROM än Exempel 3.

Att använda pekare i C Översikt Som det har nämnts tidigare är pekare en variabel som pekar på en adress i processorns RAM-minne. OBS! Det är viktigt att man håller reda på vart i minnet man är och arbetar i, särskilt när man håller på med strängar och arrayer. Annars kan det lätt bli konstiga problem om man pekar utanför den sträng/array man vill arbeta med och därmed ändrar i någon annan variabel. OBS! Deklarationer: Här är ett exempel på hur pekare deklareras: unsigned char intepekare, intepekarr[10]; unsigned char *pekare1, *pekare2, *pekare3; pekare1 = &intepekare; // 1 *pekare1 = 5; // 2 pekare2 = &intepekarr[0]; // 3 pekare3 = &pekare2[1]; // 4 Förklaring: 1. pekare1 pekar nu på intepekare:s RAM-adress 2. Detta är samma sak som att skriva: intepekare = 5; 3. pekare2 pekar på intepekarr[0]:s RAM-adress När man pekar på en array måste man ange ett index på vart i arrayen man pekar. 4. pekare3 pekar på intepekarr[1]:s RAM-adress Likaså här måste man ange ett index i förhållande till pekaren vart man pekar, kan vara negativt! Sammanfattning Genom att sätta en * framför variabelnamnet i deklarationen berättar det för kompilatorn att det är en pekare. Ett & framför en variabel ger adressen till var den är lagrad i RAMminnet. En * framför en pekare behandlar värdet för adressen den pekar på.

Exempel: Om man ska skriva ett mellanslag på alla positioner genom att använda pekaren gör man följande: unsigned char txt[10], *ptxt; ptxt = &txt[0]; for(i=0;i<10;i++) *ptxt = ; ptxt++; // Spara ett mellanslag på den adress // pekaren pekar på... // Peka på nästa fält i strängen När man skriver en * framför pekaren i funktionen betyder det att man sparar i adressen! Så i vårt fall sparas ett mellanslag på den adress som pekaren pekar på. Koden: ptxt++; gör inget annat än räknar upp adressen. Pekare i funktionsanrop Om man vill anropa en funktion som använder pekare gör man följande: // Funktion som använder pekare... void pfunct(unsigned char *p) *p = *p + *p; // Dubbla värdet i den RAM-adress som *p pekar på. void main(); unsigned char foo = 8; pfunct(&foo); // Skicka in RAM-adressen för foo // foo kommer nu att vara 16!! Här finns det en funktion som har pekare i sitt funktionsanrop, då måste den variabel som skickas till funktionen ha ett & framför sig i funktionsanropet. Vad händer här då? Jo variabeln foo är en vanlig char och därmed måste man skicka in RAM-adressen för denna variabel när man anropar funktionen pfunct(); Adressen får man om man skriver & framför den variabel som skickas in. I detta fall &foo.

Väl inne i funktionen pfunct har pekaren p samma adress som foo och därmed måste man för att förändra värdet på p skriva *p. Raden *p = *p + *p; gör följande: *p = värdet för den adress som *p pekar på och därmed adderas det med sig själv och sparas på samma adress. Skicka arrayer till funktioner Om man vill skicka in adressen till en array så får man göra följande: // Funktion som använder pekare... void funcarr(unsigned char *p) for(i=0;i<10;i++) *p = i; // Ge pekarens adress värdet i // (Adressen är inte lika med i!!!) P++; // Öka pekaren med 1 void main(); unsigned char arr[10]; funcarr(&arr[0]); // Skicka in RAM-adressen till arr[0] När man använder strängar måste man skicka en adress i arrayen. I exemplet ovan skickar vi in adressen till position 0 (&foo[0]), givetvis kan man skicka in vilken adress som helst, även adresser utanför arrayens längd vilket kan medföra vissa problem som ni kanske förstår, kompilatorn varnar dock om detta inträffar...

Skicka en pekare till en funktion som anropas med pekare Om man vill skicka vidare en pekare från en funktion till ytterligare en funktion som anropas med pekare gör man följande: // Funktion 1 som använder pekare... void funcarr1(unsigned char *p) funcarr2(p); // Eftersom p är en adress behöver // man inte skriva & framför p!!! // Funktion 2 som använder pekare... void funcarr2(unsigned char *p) *p = *p + 1; // Öka adressens värde med 1 => foo = foo + 1!! void main(); unsigned char foo; Funcarr1(&foo); // Skicka in RAM-adressen till foo Skicka en pekare till en funktion som inte anropas med pekare Om man vill skicka vidare en pekare från en funktion till ytterligare en funktion som inte anropas med pekare gör man följande: // Funktion 1 som använder pekare... void funcptr(unsigned char *p) funcnotptr(*p); // Eftersom p är en adress måste man // skriva * framför p för att få värdet!!! // Funktion 2 som inte använder pekare... void funcnotptr(unsigned char test) test++; // test = foo + 1!! Däremot ändras inte foo!! void main(); unsigned char foo; funcptr(&foo); // Skicka in RAM-adressen till foo Här är det bara värdet på test som ändras eftersom man bara skickade in värdet på *p!

Strängar i funktionsanrop När man hanterar textsträngar som till skillnad från arrayer alltid avslutas med 0x00 som sista tecken behöver man inte skriva ett & framför strängnamnet. Detta bara för att de automatiskt tolkas som en pekare. Peka på text i programminnet (ROM) Om man vill peka på minnet i ROM måste man skriva const framför pekarvariabeln för att visa kompilatorn att texten ligger i ROM-minnet, dock är ju inte pekaren en konstant! Pekarens fysiska storlek Om man har en pekare som pekar på en array som är deklarerad som char kommer givetvis pekaren att vara mer än 8 bitar lång. Detta måste den ju vara eftersom adressen som den pekar mot är ju i stort sett alltid större än 8 bitar eller adressvärdet 256