FizWeb

Porkoláb Zoltán - C programozás 2017.11.06. előadás jegyzet

6. előadás: Láthatóság, élettartam szabályai.

1. (scope)
változók, függvények, típusok !azonosítói!
-> a program mely részében mit jelent

2. (life)
-> egy változó (akár a heapben) mettől meddig érvényes (hivatkozhatok rá)

pl. 1. -> globális változó

int glob = 0;
int main(){
  glob = 1;
}
// ez statikus élettartamú: a program elejétől a végéig
// alapértelmezetten (implicit) 0-val teszi egyenlővé

pl. ha több forrásfájl: elég egyszer lefoglalni a tárterületet, SŐT!: ha kétszer definiálom-> ambiguous reference
DE: deklarálni kell

extern int glob;
void f(){
  int i;
  glob++;
}

statikus ill. automatikus élettartam
 ____________ ____________ _______
| "glob"     | "i"        |
|____________|____________|_______
  statikus    automatikus
                (stack)

-> minden forrásfájlban

Van egy  spec eset:
  olyan nevet szeretnénk, ami az adott részben (forrásfájlban) lokálisan statikus

static char buffer[1024];

a másik forrásfájlban lehet:
static int buffer; //nem fog ütközni, de nem is tudom használni

stack szerkezete: mint egy "verem"
-> a fordítóprogram nem név szerint hivatkozik rá, hanem a BÁZISPOINTER-hez képest egy offsetet ad meg

függvényhíváskor: a bázispointer áthelyeződik, a két helyzet közöttre kerül az összes változó
--> STACK-FRAME

a lokális változó is lehet static:
  static int k;
  az élettartama lesz statikus (a program elejétől a végéig rendelkezésre áll ez a tárterület)
  (a láthatósága: marad lokális, szóval csak az adott blokkban nem használhatom újra a nevét)

ha a globális változó static:
  a láthatósága: csak ebben a forrásfájlban látható

a globális változó nevével deklarálhatok egy blokkban másik automatikus lokális változót,
ekkor abban a blokkban a lokálist jelenti (a belső változó eltakarta a globálisat)

Dinamikus tárterület (heap)
  malloc, free
megmondhatom h mikor foglalom le ill. szabadítom fel

malloc(10*sizeof(int))
--> egy pointert ad vissza
void* (tetszőleges byte-ra mutató pointer)
konvertáljuk int*-ra
int *ip= (int*)malloc(10*sizeof(int));

fel kell szabadítani: különben memory leak, a heap is elfogyhat (nemcsak a stack)

lehetne két lépésben:
void *vp = malloc(10*sizeof(int));
int *ip = (int*)vp;

pointer: tömböt lehet vele indexelni
p[0] //első elem

int t[10];  //tömb
int *ip = t; //az első elemre mutató pointer
int *ip5 = &t[5]; //ez a 5. (6.) elemre mutat

--> ez macerás, ezért kitalálták a pointeraritmetikát:
ip + i //az i. elemre mutat
//(az adott tömb elemei szerint: pl. sizeof(int)-enként)

ip + i == &t[i] //igaz
*(ip+i)==t[i]
*(ip+i) == ip[i] == *(t+i)

__élettartam__:
statikus tár: program elején megmondtam mennyi hely kell
automatikus: adott blokkban lefoglal, utána felszabadít
heap/dinamikus: ha nem szabadítom fel (free), kifogyhatok
--> DE ilyenkor is lehet baj:
lehet h nincs elég nagy ÖSSZEFÜGGŐ tárterület

C#, managed C/C++:
ott a futtató rendszer áthelyezi a pointereket (egybe rakja)
--> hátrány: ez ront a hatékonyságon
_____________________
példa program: kérdez a felhasználótól, és a választ kiírja

#include 

char *answer(char *q);

int main(){
  printf("%s\n", answer("Hogy vagy?"));
  return 0;
}

char *answer(char *q){
  char buffer[80];
  printf("%s", q);
  fgets(buffer, 80, stdin);  //nehogy hosszabb legyen (a végén még \0)
  return buffer;
}  //a gets a hackereké!!!

eddig hibás!!!
--> néha száll el

MERT: a buffer automatikus élettartamú tárterület!!!
a függvényen kívül nem érvényes (life)

nulladik verzió: globális buffer
DE: csak az answer függvénynek kéne látni! -> elhasználtam ezt a nevet
helyette: lokális statikus

#include 

char *answer(char *q);

int main(){
  printf("%s\n", answer("Hogy vagy?"));
  return 0;
}

char *answer(char *q){
  static char buffer[80]; //STATIKUS
  printf("%s", q);
  fgets(buffer, 80, stdin);  //nehogy hosszabb legyen (a végén még \0)
  return buffer;
}

még nem tökéletes!!!

[
  char *q = "Hello"; //ilyenkor lefoglal egy statikus tárterületet
  //maga az fgets nem foglal le helyet
  //nem lehet "nyújtani" a lefoglalt helyet
]

baj: kétszer meghívva a későbbi hívés maradna benne
printf("%s%s", answer("Hogy vagy?"), answer("Biztos?"));
//ez kétszer kiírná h "Biztos?"

többszálú program: még bajok
globális statikus változók egy időben
több helyről párhuzamosan tudom őket írni, olvasni

Megfelelő kérdés:
Kinek van szüksége a válaszra??
--> itt a main fv-nek
----> ő foglal le

int main(){
  char buffer1[80]; char buffer2[80];
  printf("%s%s", answer("Hogy vagy?", buffer1, 80), answer("Biztos?", buffer2, 80));
  /* ... */
}

char *answer(char *q, char *out, int len){
  printf("%s", q);
  fgets(out, len, stdin);
  return out;
}

még ez se tökéletes: a fordító lehet h felcseréli a paramétereket