Endimensionella vektorer Endimensionella vektorer

Endimensionella vektorer
Endimensionella vektorer
• Har man relaterat data kan man lagra detta i
vektorer istället för i enkla variabler.
• Vektorer deklareras och indexeras med hjälp av
hakparenteser ([ och ]) direkt efter
variabelnamnet.
• Exempel:
int x0;
int x1;
int x2;
x0 = 2;
x1 = 1;
x2 = x0;
• Vektorer kan liksom enkla variabler initieras med
ett värde vid deklarationen.
int x0 = 2; int x[3] = {2, 1, 4};
int x1 = 1;
int x2 = 4;
int x[3];
• Om listan med initieringsvärden är kortare än
vektorn, initieras resterande element till 0.
x[0] = 2;
x[1] = 1;
x[2] = x[0];
int x[100] = {1,0}; /* första elementet i x blir 1 resten 0 */
int y[100] = {0}; /* nollställer alla element i y */
• Vektorer har en fix längd, n, och indexeras från 0,
dvs 0,1,2,…,n-1.
126
127
Endimensionella vektorer
Endimensionella vektorer
• Om en vektor är deklarerad utan längd, men
initierad med en lista av initierare, är dess storlek
implicit satt till antalet initierare.
• Följande två deklarationer är därmed ekvivalenta
int x[] = {5, 1, -3, 4};
int x[4] = {5, 1, -3, 4};
• För vektorer av tecken finns en alternativ notation.
Följande två deklarationer är ekvivalenta.
char s[] = {’a’, ’b’, ’c’, ’\0’}
char s[] = "abc";
128
#include <stdio.h>
#define N 5
/* Läs in heltal till en vektor. Beräkna och
skriv ut dess summa */
int main(void) {
int values[N];
int i;
int sum = 0;
for (i=0; i<N; i++) {
printf("Enter value %d: ",i);
scanf("%d",&values[i]);
}
for (i=0; i<N; i++) {
sum += values[i];
}
printf("\nSum: %d\n",sum);
}
Pekare
129
Pekare
• Varje variabel i ett program har en unik
minnesadress.
• Med pekare kan man referera och manipulera
minnesadresser.
• Värdet i en pekarvariabel är minnesadressen till
en variabel.
• Om vi har en variabel v så anger &v
minnesadressen till v.
• Deklarationer av pekare görs med en * före
variabelnamnet.
• Bland de tillåtna adresserna att referera finns alltid
adressen 0.
• Adressen 0 har i C ett speciellt namn, nämligen
NULL.
• Adressen NULL används som defaultvärde hos
pekare då inga variabler kan ha den adressen,
d.v.s. &v kan aldrig vara 0 (NULL).
• Några exempel på tilldelning av pekare kan vara:
int
int
p =
p =
p =
int *ip;
char *cp;
double *dp;
130
i;
*p;
0;
NULL;
&i;
131
1
Pekare
Pekare
int a = 3;
int *p;
int a = 3;
int *p = NULL;
• Man kan referera värdet på variabler med hjälp av
pekare.
• Om p är en pekare som pekar på b:s minnesadress,
ger *p värdet av b, en s.k. indirekt adressering.
• Exempel:
int a = 3;
int *p = &a;
int b = 3;
int *p = &b; /* Initiering till adressen av b */
printf(" b: %d\n p: %p\n*p: %d\n", b, p, *p);
• Ger utskriften
b: 3
p: effffbac /*Adressen skriven i hexadecimal form */
*p: 3
132
133
Pekare
Pekare
int a = 1;
int *p;
• I C används void * som generell pekartyp.
• Jämför med void.
p = &a;
printf(" a = %d *p = %d\n\n", a, *p);
...
int a = 3;
char c = ’c’;
void *p;
p = &a;
p = &c;
...
*p = 2; /* ekvivalent med a = 2 */
printf(" a = %d *p = %d\n\n", a, *p);
a = 3; /* ekvivalent med *p = 3 */
printf(" a = %d *p = %d\n", a, *p);
• I ANCI C kan man inte göra konverteringar
mellan olika pekartyper om inte den ena är av
typen void *.
Ger utskriften:
a = 1 *p = 1
a = 2 *p = 2
a = 3 *p = 3
134
135
Call-by-Reference
Call-by-Reference
• När en variabel skickas som argument till en
funktion kopieras dess värde till funktionens
parameter och värdet på variabeln är oför ändrat.
Detta kallas “Call-by-value“.
• Om i stället en referens till variabeln skickas som
argument kan variabelns värde ändras i den
anropade funktionen. Detta kallas “Call-byReference“.
• C använder alltid “Call-by-value“, men pekare
kan användas ¨ for att åstadkomma samma effekt
som i “Call-by-reference“.
136
• Programmen
#include <stdio.h>
void set(int a, int value){
a = value;
}
#include <stdio.h>
void set(int *a, int value){
*a = value;
}
int main(void) {
int a = 5;
set(a, 2);
printf("a = %d\n",a);
}
int main(void) {
int a = 5;
set(&a, 2);
printf("a = %d\n",a);
}
ger utskrifterna:
a = 5
a = 2
137
2
Pekare vs. vektorer
Pekare vs. vektorer
• En vektorvariabel, ex. float x[20], är i sig
själv en adress (ett pekarvärde).
• Medan pekare kan anta nya pekarvärden så är
vektorvariabler fixa.
• Både pekare och vektorer kan indexeras.
• Om a är en vektor, är a[3] ekvivalent med
*(a + 3).
• a + 3 är ett pekaruttryck som anger tredje
elementpositionen efter a.
• Ekvivalent, om p är en pekare, är p[3]
ekvivalent med *(p + 3).
#define N 3
int main(void) {
int a[N] = {0, 1, 2};
int i;
for (i=0; i<N; i++) {
printf("a[%d]=%d *(a + %d)=%d", i, a[i],i,*(a+ i);
printf("&a[%d]=%p (a + %d) =%p\n", i, &a[i], i,(a +
i));
}
}
• Ger utskriften:
a[0]=0 *(a + 0)=0 &a[0]=effffb98 (a + 0)=effffb98
a[1]=1 *(a + 1)=1 &a[1]=effffb9c (a + 1)=effffb9c
a[2]=2 *(a + 2)=2 &a[2]=effffba0 (a + 2)=effffba0
138
Pekare vs. vektorer
139
Pekare vs. vektorer
• Vi kan alltså se det som att det ser ut så här i
minnet.
• Vi kan alltså använda pekare för att referera
positioner i vektorer.
• Exempel:
• Observera
– C tillåter oss att referera och ändra hur vi vill i minnet.
– Om vi försöker ändra minne som programmet inte
“äger“ avslutar vanligtvis operativsystemet
programmet.
– Däremot kan vi ändra i det minne som programmet
“äger“ .
– Om vi antar att i har adressen effffb94 kan vi alltså
ändra värdet på i genom att skriva *(a - 1) = 3;.
#define N 5
int a[N] = {0, 1, 2, 3, 4};
int *p;
int sum = 0;
p = &a[1]; /* *p == 1 */
p = (a + 2) /* *p == 2 */
*p = 7; /* a[2] == 7 */
for (p=a; p<&a[N]; p++) {
sum += *p;
}
Värdet på sum är efter detta 15.
140
141
Vektorer som argument
Strängar
• Man kan även ge vektorer som argument till
funktioner.
• När vektorer skickas som argument kopieras
vektorns adress med “Call-by-value“, medan
vektorelementen inte kopieras.
• Exempel:
• Strängar är endimensionella vektorer av typen
char.
• En sträng avslutas med ett \0 tecken, dvs ett
tecken med alla bitar satta till 0.
• En strängs längd kan ses på två sätt:
– En fix maximal längd som avgörs av vektorns
allokerade längd.
– En variabel längd som bestäms av första \0 tecknet.
void scale(double v[], int n, double scale) {
int i;
for (i=0; i<n; i++) {
v[i] *= scale;
}
}
• \0 tecknet måste rymmas inom det allokerade
utrymmet.
H
• Observera att följande deklaration är ekvivalent.
void scale(double *v, int n, double scale) {
...
142
e
j
!
\0
?
?
?
143
3
Strängar
strcat & strncat
char s[] = "abc";
a b c \0
char s[] ={’a’,’b’,’c’,’\0’}
a b c \0
char *p = "abc";
a b c \0
#include <string.h>
char *strcat(char *s1, const char *s2);
char *strncat(char *s1,const char *s2, size_t n);
• Returnerar: Pekaren s1.
• Konkatenerar (slår ihop) två strängar och lägger
resultatet i s1. s1 måste vara stor nog för att
rymma resultatet. strncat lägger till som mest
n tecken.
144
strcmp & strncmp
145
Strängfunktioner
#include <string.h>
int strcmp(char *s1, const char *s2);
int strncmp(char *s1, const char *s2, size_t n);
#include <string.h>
char *strcpy(char *s1, const char *s2);
char *strncpy(char *s1,const char *s2, size_t n);
• Returnerar: Ett heltal < 0, lika med 0 eller > 0,
beroende på om s1 är lexikografiskt mindre, lika
eller större än s2.
• Jämför två strängar. strncmp jämför som mest n
tecken.
• Returnerar: Pekaren s1.
• Innehållet i s2 kopieras till s1 tills \0 flyttas. s1
måste ha plats för resultatet.
• strncpy kopierar som mest n tecken.
#include <string.h>
size_t strlen(const char *s);
• Returnerar: Antalet tecken före \0.
• Undersöker längden av eller antalet tecken före\0
hos en sträng.
146
Flerdimensionella vektorer
147
Två-dimensionella vektorer
• I C kan man deklarera vektorer av alla typer,
inklusive vektorer av vektorer. På så vis kan
man skapa vektorer i flera dimensioner.
int a[100]; /*en endimensionell vektor*/
int b[2][7]; /*en två-dimensionell vektor*/
int c[6][2][5];/*en tredimensionell vektor*/
• Det är lättast att tänka på två-dimensionella
vektorer som en matris, med rader och kolumner.
• Deklarationen int a[3][5] kan ses på
följande vis:
• Initiering sker på liknande sätt som med
endimensionella vektorer.
int a[2][2] = {{1, 2}, {4, 0}};
• I minnet lagras dock flerdimensionella vektorer
kontinuerligt.
148
149
4
Två-dimensionella vektorer
Bubble sort
#include <math.h>
#include <stdio.h>
#define N 5
#define M 3
int main(void) {
double A[M][N];
int i, j;
for (i=0; i<M; i++) {
for (j=0; j<N; j++) {
A[i][j] = i*N+j;
printf("%4.0f", A[i][j]);
}
printf("\n"); /*Ny rad för varje rad i A */
}
}
150
void swap(int *a, int *b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void bubble(int v[], int n) {
int i=0, j, swaped=1;
while(swaped) {
swaped=0;
for (j=0; j<n-i-1; j++)
if (v[j] > v[j+1]) {
swap(&v[j], &v[j+1]);
swaped=1;
}
i++;
}
}
151
5