Informatika2-2015/Eloadas 9 C-2 C tombok

A MathWikiből
(Változatok közti eltérés)
(Új oldal, tartalma: „= C tömbök = A C-ben a tömbök töltik be körülbelül ugyanazt a szerepet, mint python-ban a listák. Ez az alapvető mód, amivel több dolgot egymás után rend…”)
 
36. sor: 36. sor:
  
 
Az két tömböt definiál, és egy sima ''int''-et. De általánosságban azt ajánlom hogy egy sorban csak egy változót definiáljunk, vagy legfeljebb azonos típusú összetartozó dolgokat, de ilyen különböző típusokat ne vegyítsünk.
 
Az két tömböt definiál, és egy sima ''int''-et. De általánosságban azt ajánlom hogy egy sorban csak egy változót definiáljunk, vagy legfeljebb azonos típusú összetartozó dolgokat, de ilyen különböző típusokat ne vegyítsünk.
 +
 +
Egy másik módosító a ''mutató'', amit mi majd csak későbbi órán veszünk, és amit csillaggal jelölünk így:
 +
<c>
 +
int *mutato;
 +
</c>
 +
Csak azért említom most meg, mert sok szempontból ekvivalens a tömbbel, és ezért hibaüzenetben lehet hogy ezt látjuk amikor mi tömbökkel foglalkozunk, ekkor egyelőre mi ezt érthetjük úgy mintha az lenne ott hogy
 +
<c>
 +
int mutato[];
 +
</c>
 +
 +
 +
== Tömb kapása függvényparaméterként ==
 +
 +
Ha függvényparaméterként szeretnénk tömböt kapni, akkor is használhatom mind a két változatot:
 +
 +
<c>
 +
void f1(int v1[]) {
 +
  printf("%d\n", v1[0]);
 +
  // kod
 +
}
 +
</c>
 +
 +
vagy
 +
 +
<c>
 +
void f2(int v2[3]) {
 +
  printf("%d, %d, %d\n", v2[0], v2[1], v2[2]);
 +
  // kod
 +
}
 +
</c>
 +
 +
Azonban a két módszer teljesen ekvivalens, a C fordító nem ellenőrzi hogy stimmel a tömb mérete, akkor se ha megadtuk. Az ott megadott méret tehát csak szándékot jelez, kvázi dokumentáció. Így ez a kód lefordul, csak aztán nem működik jól:
 +
 +
 +
<c>
 +
void f2(int v2[3]) {
 +
  printf("%d, %d, %d\n", v2[0], v2[1], v2[2]);
 +
  // kod
 +
}
 +
 +
void main() {
 +
  int kettestomb[] = {30, 40};
 +
  f2(kettestomb);
 +
}
 +
</c>
  
 
== Ellenőrzés és "undefined behaviour" ==
 
== Ellenőrzés és "undefined behaviour" ==
143. sor: 188. sor:
  
 
A karakterláncok kezeléséhez lesz néhány függvény a beépített könyvtárakban majd, egyelőre ennyit elég tudni róluk.
 
A karakterláncok kezeléséhez lesz néhány függvény a beépített könyvtárakban majd, egyelőre ennyit elég tudni róluk.
 +
 +
= További alapok =
 +
 +
== Számok beolvasása ==
 +
 +
Ahogy a ''printf'' használható a parancssorra kiíráshoz, a [http://en.cppreference.com/w/c/io/fscanf scanf] használható a parancssorról való beolvasáshoz. Egyszerű példa:
 +
 +
<c>
 +
#include <stdio.h>
 +
 +
void main() {
 +
  int n;
 +
  printf("Irj be egy szamot!\n");
 +
  scanf("%d", &n);
 +
  printf("Azt irtad be, hogy %d.\n", n);
 +
}
 +
</c>
 +
 +
A ''printf''-hez hasonlóan a "%d" az egész szám beolvasása, a "%f" a valós szám beolvasása. Amikor a változót ahova be akarunk olvasni megadjuk, elé kell tenni egy "és" karaktert, egy "&"-t. Ha számokat akarunk beolvasni, akkor a scanf a whitespace-t figyelmen kívül hagyja, viszont ha más szöveget lát szám helyett, akkor nem megy. Így ahelyett hogy "5" beírhatom azt hogy "  5", és akkor még működni fog, de ha már azt írom be hogy "a5", akkor nem olvassa be sikeresen az 5-öt. Tehát parancssorról egy legfeljebb 100 elemű tömböt pl így olvashatunk be:
 +
 +
<c>
 +
#include <stdio.h>
 +
 +
void main() {
 +
  int n;
 +
  int v[100];
 +
  int i;
 +
  scanf("%d", &n);
 +
  for(i = 0; i < n; ++i) {
 +
    scanf("%d", &v[i]);
 +
  }
 +
 +
  // Feldolgozni a tombot
 +
}
 +
</c>
 +
 +
Így ez be tudja olvasni a következő szöveget parancssorból:
 +
 +
3
 +
10 11 12
 +
 +
Egy 3 elemű tömbbe aminek a 3 tagja 10, 11 és 12. (Igazából 100 a tömb mérete, de a kódban majd mindig csak az első 3 elemével foglalkozunk, mindig csak n-ig megyünk, így effektíve 3 eleműnek vehető a tömb.)
 +
 +
Ezt a példát azért mutatom külön, mert több labor feladatnál fog kelleni konkrétan.
 +
 +
== Operátorok ==
 +
 +
Az operátorokat már eddig is használtuk, Ezek az ilyen jelölések mint a +, -, vagy a tömb indexelés. Az operátorok precedenciája mondja meg hogy amikor több operátor is szerepel egy sorban, akkor azt hogyan kell pontosan értelmezni. Itt a C-ben levő összes operátor egy táblázatban:
 +
 +
{| class="wikitable"
 +
|+
 +
! Precedencia !! Operátor !! Rövid leírás !! Asszociativitás !! Példa
 +
|-
 +
| 1 || () <br/>[] <br/> -> <br/>. <br/>++ <br/>-- || Függvényhívás<br/> Tömb-elérés <br/> Mutatón keresztüli tag-elérés <br/> Objektumon keresztüli tag-elérés <br/> Posztfix növelés <br/> Posztfix csökkentés || Bal || f(a) <br/> a[1] <br/> ptr->b <br/> a.b <br/> a++ <br/> a--
 +
|-
 +
| 2 || ! <br/> ~ <br/> ++ <br/> -- <br/> - <br/> + <br/> * <br/> & <br/> (típus) <br/> sizeof || Logikai tagadás <br/> Bitenkénti negálás <br/> Prefix növelés <br/> Prefix csökkentés <br/> Előjel - <br/> Előjel + <br/> Dereferálás <br/> Objektum címe <br/> Konverzió típusra <br/> Méret || Jobb || !a <br/> ~a <br/> ++a <br/> --a <br/> -a <br/> +a <br/> *ptr <br/> &a <br/> (int)a <br/> sizeof(a)
 +
|-
 +
| 3 || * <br/> / <br/> % || Szorzás <br/> Osztás <br/> Maradékszámítás || Bal || 5 * 3 == 15 <br/> 5 / 3 == 1<br/> 5 % 3 == 2
 +
|-
 +
| 4 || + <br/> - || Összeadás <br/> Kivonás || Bal || 5 + 3 == 8 <br/> 5 - 3 == 2
 +
|-
 +
| 5 || << <br/> >> || Bitenkénti eltolás balra <br/> Bitenkénti eltolás jobbra || Bal || 5 << 1 == 10 <br/> 5 >> 1 == 2
 +
|-
 +
| 6 || < <br/> <= <br/> > <br/> >= || Kisebb <br/> Kisebb-egyenlő <br/> Nagyobb <br/> Nagyobb-egyenlő || Bal || a < b <br/> a <= b <br/> a > b <br/> a >= b
 +
|-
 +
| 7 || == <br/> != || Egyenlő <br/> Nemegyenlő || Bal || a == b <br/> a != b
 +
|-
 +
| 8 || & || Bitenkénti ÉS || Bal || 6 & 5 == 4
 +
|-
 +
| 9 || ^ || Bitenkénti kizáró VAGY || Bal || 6 ^ 5 == 3
 +
|-
 +
| 10 || <nowiki>|</nowiki> || Bitenkénti megengedő VAGY || Bal || 6 <nowiki>|</nowiki> 5 == 7
 +
|-
 +
| 11 || && || Logikai ÉS || Bal || (i < n) && good
 +
|-
 +
| 12 || <nowiki>||</nowiki> || Logikai(megengedő) VAGY || Bal || (i < n) <nowiki>||</nowiki> good
 +
|-
 +
| 13 || ? : || if-then-else operátor || Jobb || (i < n) ? "kisebb" : "nem kisebb"
 +
|-
 +
| 14 || = <br> += <br> -= <br> *= <br> /= <br> %= <br> &= <br> ^= <br> <nowiki>|=</nowiki> <br> <<= <br> >>= || Értékadás <br> Összeadás és értékadás <br> Kivonás és értékadás <br> Szorzás és értékadás <br> Osztás és értékadás <br> Maradékképzés és értékadás <br> Bitenkénti ÉS és értékadás <br> Bitenkénti kizáró VAGY és értékadás <br> Bitenkénti megengedő VAGY és értékadás <br> Eltolás balra és értékadás <br> Eltolás jobbra és értékadás || Jobb || i += 5 <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
 +
|-
 +
| 15 || , || Szekvencia operátor || Bal || a, b
 +
|}
 +
 +
Itt a magasabb precedencia azt jelenti, hogy azt az operátort hajtja előbb végre ha lehet. Tehát pl. azt hogy:
 +
 +
<c>
 +
a = 5 + 3 * 4;
 +
</c>
 +
 +
úgy fogja a C értelmezni, hogy a szorzást hajtja először végre, mintha az zárójelezve lenne így:
 +
 +
<c>
 +
a = 5 + (3 * 4);
 +
</c>
 +
 +
mivel a szorzásnak magasabb a precedenciája, 3, mint az összeadásnak, 4. Most még nem ismerünk a táblázatból minden operátort, de amire fel szeretném hívni a figyelmet, az a 14-es precedenciájúak, hogy minden aritmetikai operátor használható ilyen "változtatós" formátumban, azok sokszor jól jönnek.
 +
 +
== Könyvtárak ==
 +
 +
[http://en.cppreference.com/w/c C dokumentáció] [http://math.bme.hu/~csirke/Info2-2015/stdc.pdf C összefoglaló]
 +
 +
== Preprocesszor ==

A lap 2015. április 8., 10:38-kori változata

Tartalomjegyzék

C tömbök

A C-ben a tömbök töltik be körülbelül ugyanazt a szerepet, mint python-ban a listák. Ez az alapvető mód, amivel több dolgot egymás után rendezhetünk. Azonban a tömbök egy jelentősen egyszerűbb konstrukció mint a listák. Ennek egyik része a típusosság következménye, egy tömbben mindennek egyforma típusúnak kell lennie, hisz előre meg kell mondanom az elemek típusát. De vannak ezen túli különbségek is, amik még megnehezíthetik az életünket.

Tömbök definiálása

Alapvetően kétféleképpen lehet tömböket definiálni a C-ben. Az egyik módszer az, ha a definíciónál egyből megmondod az értékeket is amik a tömbben vannak. Pl.:

int primek[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%d\n", primek[0]);  // Ez a 2-t fogja kiirni

A másik módszer az, hogy a definíciónál csak a méretét mondom meg, pl.:

int primek[8];
primek[0] = 2;
// Ez nem mukodik: primek = {2, 3, 5, 7, 11, 13, 17, 19};
// Csak definicional
printf("%d\n", primek[0]);  // Ez a 2-t fogja kiirni

Miután definiáltam a tömböt, a következő dolgok igazak rá:

  • A tömb mérete fix, nem változhat a futás közben. Sőt, a hivatalos szabvány szerint nem is lehet oda a méret helyére változót írni, csak egy fix számot, esetleg egyszerű számítást mint "4*10". (A gcc viszont elfogad egy változót oda.)
  • Ezek a tömb típusok is mind különböző típusok (általában úgy írják hogy pl. "int[]" ha int tömbről van szó), tehát nem "kompatibilisek" más típusokkal csak az explicit megengedett esetekben.
  • A tömb tagjait a python-hoz hasonló szögletes zárójeles módszerrel lehet elérni, és itt is 0-tól (n-1)-ig vannak számozva. Itt nem működnek az olyan negatív indexek, se az ilyen hosszabb részek kiválasztása kettőspontos kifejezésekkel. Csak egy darab egész szám lehet az index amit a szögletes zárójelbe írunk.
  • A tömb hosszának meghatározására nincs egyszerű és mindig működő módszer. Általában ha nem egyértelmű (mert pl. mindig 3 dimenzió), akkor egy külön egész szám változóban tároljuk el, amit a tömbbel együtt odaadunk pl. függvényeknek meg ilyesmi.

Ez a szögletes zárójel egy módosító az alaptípushoz. Egy sorban több változót is lehet definiálni, és a hozzátartozó módosítók különbözőek is lehetnek, így pl. ez:

int tomb_a[10], szam, tomb_b[10];

Az két tömböt definiál, és egy sima int-et. De általánosságban azt ajánlom hogy egy sorban csak egy változót definiáljunk, vagy legfeljebb azonos típusú összetartozó dolgokat, de ilyen különböző típusokat ne vegyítsünk.

Egy másik módosító a mutató, amit mi majd csak későbbi órán veszünk, és amit csillaggal jelölünk így:

int *mutato;

Csak azért említom most meg, mert sok szempontból ekvivalens a tömbbel, és ezért hibaüzenetben lehet hogy ezt látjuk amikor mi tömbökkel foglalkozunk, ekkor egyelőre mi ezt érthetjük úgy mintha az lenne ott hogy

int mutato[];


Tömb kapása függvényparaméterként

Ha függvényparaméterként szeretnénk tömböt kapni, akkor is használhatom mind a két változatot:

void f1(int v1[]) {
  printf("%d\n", v1[0]);
  // kod
}

vagy

void f2(int v2[3]) {
  printf("%d, %d, %d\n", v2[0], v2[1], v2[2]);
  // kod
}

Azonban a két módszer teljesen ekvivalens, a C fordító nem ellenőrzi hogy stimmel a tömb mérete, akkor se ha megadtuk. Az ott megadott méret tehát csak szándékot jelez, kvázi dokumentáció. Így ez a kód lefordul, csak aztán nem működik jól:


void f2(int v2[3]) {
  printf("%d, %d, %d\n", v2[0], v2[1], v2[2]);
  // kod
}
 
void main() {
  int kettestomb[] = {30, 40};
  f2(kettestomb);
}

Ellenőrzés és "undefined behaviour"

Fontos különbség a python és a C alapvető filozófiái között, hogy mit csinál a program, ha hiba történik. Nézzük a következő, egyszerű, C kódot:

int a[] = {10, 11};
int b[] = {20, 21};
 
printf("%d\n", a[-1]);

Mit fog kiírni ez a kód? Először is, az biztos, hogy nem fog egy szép (vagy csúnya) hibaüzenetet dobni, hogy nem lehet -1-dik tagot kérni. Ahol én teszteltem, ott az alapbeállításokkal, ez azt írja ki, hogy 21, mert a memóriában éppen a b tömb adatai vannak az a mellett, ezért ha megyek egyet az a tömb 0. elemétől visszafelé, ott a b tömb utolsó elemét találom. A C szabvány szerint ez "undefined behaviour". Ezzel a kifejezéssel még fogunk találkozni máskor is, úgyhogy kifejtem hosszabban mit jelent ez a C sztenderd esetében.

A szabvány meghatározza hogy a helyes programoknak hogy kell viselkedniük, nem csak hogy mit kell kiírniuk, de a hatékonyságra és egyéb hasonló dolgokra is ad feltételeket. Azonban, ha a program nem helyes, ha a programozó hibát követ el, akkor sok helyen a szabvány azt mondja, hogy ebben az esetben a lefordított program "undefined behaviour"-t tanusít. Ez elméletben a szabvány szerint azt jelenti, hogy ha ilyent csinálunk, akkor a szabvány felteszi a kezét, hogy akkor ő nem felelős azért, hogy mi fog történni, akár az egész merevlemezünket is formázhatja a program.

Ezt persze nem úgy kell érteni, hogy azt leírni hogy "a[-1]" veszélyes a gépünk egészségére. Azért nincs meghatározva ilyen esetben a viselkedés, hogy a különböző fordítók a lehető legnagyobb hatékonyságot érhessék el abban az esetben, ha helyes a program. Általában a fordítók sok esetet, ami a szabvány szerint "undefined behaviour", jobban definiálnak a dokumentációjukban, hiszen ők már tudják, hogy az ő fordítójuknál ott mi fog történni. Pl. lehet hogy a gcc dokumentációjában le van írva, hogy "ha az egészeket tároló tömbből olyan index-el olvasunk ki adatot, ami nem értelmes, akkor is vissza kapunk egy számot, aminek az értéke bármi lehet". (Bár ebben az esetben ez nem a teljes igazság, de ilyesmi.)

Ezzel ellentétben ugye a python kiírja hogy IndexError ezmegaz. De mit nyerünk ezzel az "undefined behaviour"-rel, fejfájásokon túl? Hatékonyságot! Ha a python-on leírom azt, hogy "l[2]", akkor a processzoron sok utasítás fog lefutni, ami először leellenőrzi hogy a 2-nek van-e értelme az adott listánál, ha nincs, akkor a hibát jelzi, ha van, akkor kiolvassa a megfelelő értéket. A C-ben egyetlen utasítás lesz, ami a megfelelő memóriacímet kiolvassa. Manapság azok az egyszerű ellenőrzések amiket a python csinál, a legtöbb esetben beleférnek az időbe, úgyhogy a legtöbb alkalmazásnál megéri ezt a kis hatékonyságot nagyobb biztonságra cserélni, de általában azokra a célokra használják a C-t ahol minden kis hatékonyságnak örülnek.

A fix méret kezelése

Mivel a tömb mérete a szabvány szerint még változó sem lehet, csak teljesen fix érték, ezért bajban vagyunk ha nem tudjuk előre hogy mekkora tömbre lesz szükségünk, mert pl. a felhasználó által megadott adatoktól függ. Erre több megoldás is van, a szép megoldás majd az lesz, amit később tanulunk, hogy a memóriát kezeljük a programunkban. Addig is egyszerűbb, és sokszor teljesen megfelelő megoldás, ha azt mondjuk, hogy az adott program/függvény maximum 1000 elemű tömb kezelésére alkalmas.

// Dokumentaljuk is le, hogy max. 1000-el mukodik
int fun(int n) {
  if(n > 1000) {
    return -1;  // Ezzel a hibat jelezzuk
  }
  int tomb[1000];
  // A tenyleges szamolasok...
  // Amik a tomb-nek csak az elso n elemet hasznaljak
}

Ez ugyan pazarlásnak tűnhet, és ha nagyon hatékony kell hogy legyen a programunk, akkor nem is jó ötlet, de általában jó. (És ha hatékonyak akarunk lenni, akkor még mindig át tudjuk írni később.) És végezzünk egy gyors számolást hogy mennyire pazarlunk ezzel (a C-nek egy előnye hogy az ilyesmi pontosan kiszámolható):

A gépünkben manapság mondjuk legalább 1 GB (GigaByte) memória van. Egy int típusú egész szám pontosan 4 byte memóriát foglal C-ben. Tehát ez az ezer elemű tömb még mindig csak 4 KB, a rendelkezésre álló memória 250000-ed része. (Ezzel ellentétben a firefox/chrome könnyen többszáz MB memóriát el tudnak vinni.) Amíg az így fixen lefoglalt memória 1 MB alatt van, még messze nem kell aggódni a hatékonyság miatt, ha amúgy úgy biztosra mehetek hogy az elég lesz.

C karakterláncok

A C-ben több különböző típus is van az egész számok tárolására, attól függően hogy mennyi memóriát foglalnak. Nagyjából ezek vannak:

  • A char típus -128 és 127 közötti számokhoz, 1 byte-on
  • A short típus -32,768 és 32,767 közötti számokhoz, 2 byte-on
  • Az int típus -2,147,483,648 és 2,147,483,647 közötti számokhoz, 4 byte-on
  • A long típus, ugyanaz mint az int (A szabványban nem így van meghatározva, de jelenleg ez a helyzet.)
  • A long long típus -9*10^18 és 9*10^18 közötti számokhoz, 8 byte-on (bár ez hivatalosan még a '89-es C szabványban nincs benne, csak a '99-esben, ismerik a fordítók)

Még vannak mindegyikből unsigned változatok is, ha negatív számokra nincs szükségünk, pl. az unsigned int típus 0 és 4,294,967,295 közötti számokat tud tárolni. Még egy fontos típus amit néha láthatunk a size_t, ez csak egy másik név valamelyik már említett típusra (általában az unsigned int-re), a beépített könyvtárak függvényei ezt használják a dolgok méretének a megadására. További leírást találhatunk pl. az angol wikipédián.

Na de ezek közül az egész típusok közül most a char-al foglalkozunk kicsit. A C-ben ha szöveget akarunk tárolni, akkor azt char típusu változók segítségével tesszük. Egy char változóban egy angol betűt el lehet tárolni ASCII kódban kódolva. (Nem angol betűk tárolását a python-ban sem tárgyaltam, de ott azért viszonylag kis szenvedéssel megoldható. C-ben elég nehéz, nem ajánlom.) Így a szöveget el lehet tárolni egy char tömbben, pl.:

char szoveg[] = "Szoveg!\n";

Ez egy 9 elemu char tomb lesz, és szoveg[0] az 83, mert 83 a nagy S-nek az ASCII kódja. Tehát ha egy szöveget char tömbként akarunk nézni akkor arra használjuk a dupla idézőjelet. Ha egy betűt külön akarunk char-ként (és nem tömbként) nézni, ahhoz egyszeres idézőjel kell. Pl.:

char betu = 'S';
// vagy
if(szoveg[0] == 'S') {
  printf("S-el kezdodik!\n");
}

Még egy dolgot csinál pluszban a dupla idézőjel ami itt nem látszott, mégpedig azt, hogy a karakterlánc végére tesz egy 0-t. A 0-nak az ASCII táblában nincs jelentése (az van odaírva hogy "null"), hanem speciálisan arra szokták használni hogy jelezzék a végét a karakterláncnak. Így ha betünként akarunk feldolgozni egy karakterláncot, akkor addig kell menni amig egy 0 betűt találunk. Pl.:

int feldolgoz(char[] szoveg) {
  int i = 0;
  while(szoveg[i] != 0) {
    // Csinalunk valamit szoveg[i]-vel
    ++i;
  }
}

Vagy, mivel a for ciklus rugalmas, azzal is ugyanezt megcsinálhatjuk:

int feldolgoz(char[] szoveg) {
  int i;
  for(i = 0; szoveg[i] != 0; ++i) {
    // Csinalunk valamit szoveg[i]-vel
  }
}

Sőt, mivel a C-ben nincs külön igaz/hamis változó, hanem a 0 jelent hamisat, és minden ami nem 0 az igazat jelent, ezért még egyszerűbben így is írhatjuk:

int feldolgoz(char[] szoveg) {
  int i;
  for(i = 0; szoveg[i]; ++i) {
    // Csinalunk valamit szoveg[i]-vel
  }
}

Ezeket tudva érthetjük hogy a következő két tömbmegadás miért jelenti pontosan ugyanazt:

char sz1[] = "abc\n";
char sz2[] = {97, 98, 99, 12, 0};

A karakterláncok kezeléséhez lesz néhány függvény a beépített könyvtárakban majd, egyelőre ennyit elég tudni róluk.

További alapok

Számok beolvasása

Ahogy a printf használható a parancssorra kiíráshoz, a scanf használható a parancssorról való beolvasáshoz. Egyszerű példa:

#include <stdio.h>
 
void main() {
  int n;
  printf("Irj be egy szamot!\n");
  scanf("%d", &n);
  printf("Azt irtad be, hogy %d.\n", n);
}

A printf-hez hasonlóan a "%d" az egész szám beolvasása, a "%f" a valós szám beolvasása. Amikor a változót ahova be akarunk olvasni megadjuk, elé kell tenni egy "és" karaktert, egy "&"-t. Ha számokat akarunk beolvasni, akkor a scanf a whitespace-t figyelmen kívül hagyja, viszont ha más szöveget lát szám helyett, akkor nem megy. Így ahelyett hogy "5" beírhatom azt hogy " 5", és akkor még működni fog, de ha már azt írom be hogy "a5", akkor nem olvassa be sikeresen az 5-öt. Tehát parancssorról egy legfeljebb 100 elemű tömböt pl így olvashatunk be:

#include <stdio.h>
 
void main() {
  int n;
  int v[100];
  int i;
  scanf("%d", &n);
  for(i = 0; i < n; ++i) {
    scanf("%d", &v[i]);
  }
 
  // Feldolgozni a tombot
}

Így ez be tudja olvasni a következő szöveget parancssorból:

3
10 11 12

Egy 3 elemű tömbbe aminek a 3 tagja 10, 11 és 12. (Igazából 100 a tömb mérete, de a kódban majd mindig csak az első 3 elemével foglalkozunk, mindig csak n-ig megyünk, így effektíve 3 eleműnek vehető a tömb.)

Ezt a példát azért mutatom külön, mert több labor feladatnál fog kelleni konkrétan.

Operátorok

Az operátorokat már eddig is használtuk, Ezek az ilyen jelölések mint a +, -, vagy a tömb indexelés. Az operátorok precedenciája mondja meg hogy amikor több operátor is szerepel egy sorban, akkor azt hogyan kell pontosan értelmezni. Itt a C-ben levő összes operátor egy táblázatban:

Precedencia Operátor Rövid leírás Asszociativitás Példa
1 ()
[]
->
.
++
--
Függvényhívás
Tömb-elérés
Mutatón keresztüli tag-elérés
Objektumon keresztüli tag-elérés
Posztfix növelés
Posztfix csökkentés
Bal f(a)
a[1]
ptr->b
a.b
a++
a--
2  !
~
++
--
-
+
*
&
(típus)
sizeof
Logikai tagadás
Bitenkénti negálás
Prefix növelés
Prefix csökkentés
Előjel -
Előjel +
Dereferálás
Objektum címe
Konverzió típusra
Méret
Jobb  !a
~a
++a
--a
-a
+a
*ptr
&a
(int)a
sizeof(a)
3 *
/
 %
Szorzás
Osztás
Maradékszámítás
Bal 5 * 3 == 15
5 / 3 == 1
5 % 3 == 2
4 +
-
Összeadás
Kivonás
Bal 5 + 3 == 8
5 - 3 == 2
5 <<
>>
Bitenkénti eltolás balra
Bitenkénti eltolás jobbra
Bal 5 << 1 == 10
5 >> 1 == 2
6 <
<=
>
>=
Kisebb
Kisebb-egyenlő
Nagyobb
Nagyobb-egyenlő
Bal a < b
a <= b
a > b
a >= b
7 ==
 !=
Egyenlő
Nemegyenlő
Bal a == b
a != b
8 & Bitenkénti ÉS Bal 6 & 5 == 4
9 ^ Bitenkénti kizáró VAGY Bal 6 ^ 5 == 3
10 | Bitenkénti megengedő VAGY Bal 6 | 5 == 7
11 && Logikai ÉS Bal (i < n) && good
12 || Logikai(megengedő) VAGY Bal (i < n) || good
13  ? : if-then-else operátor Jobb (i < n) ? "kisebb" : "nem kisebb"
14 =
+=
-=
*=
/=
 %=
&=
^=
|=
<<=
>>=
Értékadás
Összeadás és értékadás
Kivonás és értékadás
Szorzás és értékadás
Osztás és értékadás
Maradékképzés és értékadás
Bitenkénti ÉS és értékadás
Bitenkénti kizáró VAGY és értékadás
Bitenkénti megengedő VAGY és értékadás
Eltolás balra és értékadás
Eltolás jobbra és értékadás
Jobb i += 5










15 , Szekvencia operátor Bal a, b

Itt a magasabb precedencia azt jelenti, hogy azt az operátort hajtja előbb végre ha lehet. Tehát pl. azt hogy:

a = 5 + 3 * 4;

úgy fogja a C értelmezni, hogy a szorzást hajtja először végre, mintha az zárójelezve lenne így:

a = 5 + (3 * 4);

mivel a szorzásnak magasabb a precedenciája, 3, mint az összeadásnak, 4. Most még nem ismerünk a táblázatból minden operátort, de amire fel szeretném hívni a figyelmet, az a 14-es precedenciájúak, hogy minden aritmetikai operátor használható ilyen "változtatós" formátumban, azok sokszor jól jönnek.

Könyvtárak

C dokumentáció C összefoglaló

Preprocesszor

Személyes eszközök