Kasutaja:M2s17/meeldetuletused/Programmeerimiskeel C

Kuidas defineerida ja mida muuda

C on loodud nõnda, et tema puudujääke saaks võimalikult lihtsasti kõrvaldada. Üks selliseid võimalusi on kasutada prekompilleerimise võtmesõna #define. Nõnda defineeritud koodiosa asendatakse päris koodiga enne kompileerimist. Meeldetuletuseks, viisakas oleks defineeritute koodiosal kasutada suuri tähti.

Järgnevalt midagi kasuliku mida saab teha, kasutades võtmesõna define.

Näide muuda

Selle näitega olen püüdnud ühe korraga võimalikult palju C defineerimise võlusid kuvada. Seega loetleksin ülesse, mis alljärgnevalt tähelepanuväärset on.

  1. Programeerimiskeel C ei oma kahendväärtuseid ja kahtlemata kõige lihtsam võimalus on neid imiteerida Define võtmesõnaga
  2. Tihti kasutatakse täisarvude sisestust, kuigi pole raske kirjutada scanf("%d",&x);, siis palju mugavam oleks kirjeldada tüüp+S(muutujanimi) ehk seega täisarvu puhul INTS(x)
  3. Kui muutujale väärtuse lisamine tundub lihtsam, siis veel lihtsam andmete kuvamine
  4. Preprotsessorit saab panna ka lahendama arvutusi nt: leidama kahest arvust suurima, tagastama suvalise arvu, tagastama omatüüpi kellaaja jne.
  5. Tihti on kergem lugeda keele süntaksi asemel emakeelseid lipikuid. See on eriti kasulik, kui tegemist on keeruliste tingimustega. Ka on palju omasem kirja panna tingimus a + b ON c ON VALE, kui a + b == c == 0.
  6. Ka on võimalik kasutada konsoolipõhiseid küljenduslike elemente nagu reavahetust või kriipsude rida
  7. Kuigi tuleks kasutada tavalist if tingimust, võib ka selle emakeelde tõlkida
  8. Kui programm ei jookse terminalis (tüüpiline Linuxis/Unixis/Mac'idel/BSD's/Sun Os'is), siis võib kuvatav konsooliaken sulguda ennem, kui soovitud - selle vältimiseks oodatakse klahvivajutust ja alles siis väljutakse; ka seda võib teha preprotsessor.
#define T6SI 1
#define VALE 0
#define INTS(x) scanf("%d",&x);
#define TYYP(x) printf("Sisesta %d arv: ",x)
#define KUVA(x) printf("%s",x)
#define KUVA2(x,y) printf("%s%d",x,y)
#define MIN(a,b) ((a)>(b)?(b):(a))
#define MAX(a,b) ((a)<(b)?(b):(a))
#define V6I ||
#define ON ==
#define JA &&
#define RV printf("\n")
#define K printf("----------")
#define KUI(tingimus,kui_t6si,kui_vale) if(tingimus){kui_t6si}else{kui_vale}
#define OOTA getchar();getchar()

int main(){
    int a,b,c,d;
    KUVA("Tere");RV;
    KUVA("Sisesta 3 arvu ja ma leian sulle neist suurima ja vähima");RV;
    K;K;K;K;K;K;RV;
    TYYP(1);INTS(a);
    TYYP(2);INTS(b);
    TYYP(3);INTS(c);
    K;K;RV;
    KUI(a ON b V6I a ON c V6I b ON c, 
       KUVA("Vähemalt 2 sisestatut on võrdsed");RV;
       KUI(a>=b JA a>=c,KUVA2("Üks parim arv oli esimene sisestus: ",a);RV;,)
       KUI(b>=a JA b>=c,KUVA2("Üks parim arv oli teine sisestus: ",b);RV;,)
       KUI(c>=b JA c>=a,KUVA2("Üks parim arv oli kolmas sisestus: ",c);RV;,)
       KUI(a<=b JA a<=c,KUVA2("Üks vähim arv oli esimene sisestus: ",a);RV;,)
       KUI(b<=a JA b<=c,KUVA2("Üks vähim arv oli teine sisestus: ",b);RV;,)
       KUI(c<=b JA c<=a,KUVA2("Üks vähim arv oli kolmas sisestus: ",c);RV;,)
    ,
       KUVA2("Parim arv oli: ",MAX(a,MAX(b,c)));RV;
       KUVA2("Vähim arv oli: ",MIN(a,MIN(b,c)));RV;
    )
    K;K;RV;
    KUI(a - b ON c ON T6SI,KUVA("a - b on c");RV;,)
    KUI(a - b ON c ON VALE,,KUVA("a - b on c");RV;)
    OOTA;
}

Mida ei saa #define'iga defineerida muuda

Programmeerimiskeeles C puudub tüüp string ja oleks loomupärane, et üritada seda imiteerida. Kui luua viit char sümbolimasiivile, oleks tõepoolest võimalik taoline teguviis, aga sellelaadsete tegevuste puhul kasutatakse hoopis typedef võtmesõna. Kui kasutada #define'i saab nõnda deklareerida vaid ühte sümbolit.

Järgnevas näites on toodud kuidas deklareerida tüüp, mida saab stringimoodi väärtustada. Alljärgnevas näites on tüüp deklareeritud globaalselt, ehk seda tüüpi saab kasutada kõigis funktsioonides. Kuid see ei pea nii olema ja võite tüübi deklareerida ka funktsioonisiseselt.

#define OOTA getchar();getchar()
typedef char *TEKST ;

int main(){
    TEKST tekst1, tekst2; 
    
    tekst1="läks poodi.";
    tekst2="Tädi maali ";
    printf("%s%s",tekst2,tekst1);
    
    OOTA;
}

Kuidas määrata komakohtade arv muuda

Meeldetuletuseks, et komakohtade kuvamise pikuse üle saab otsustada vaid siis, kui tegemist on murdarvuga, mitte täisarvuga (int). Võib tekkida komplikatsiooone, kui soovid kahe long arvutüübiga väärtustada double arvtüübiga muutujat.
Näites on kasutatud arvutüüpi double ja väljastatud on arvu täispikkus on 9 arvukohta, koos 2 komakohaga ehk %9.2lf. Analoogselt tuleb teha ka teistel juhtudel -  %[arvu_täispikkus].[komakohti][arvutüüp]. Näide:

void kuva(double a, double b, double c)
{
   printf("Kui jagame %9.2lf arvuga %9.2lf on tulemuseks %9.2lf\n",a,b,c);
   return;
}

Kood on nagu korras, aga millegi pärast on midagi viga muuda

Programeerimiskeel C on selles suhtes üsna värvikas ja võimalusi on palju.

Tingimused muuda

Ka pole tingimused samased teiste keeltega. Näiteks tuleb kasutada järgnevaid märke, et võrrelda:

  vähem kui            <
  vähem või samapalju  <=
  rohkem kui           >
  rohkem või samapalju >=
  samane               ==
  mittesamane          !=
  mitte                !
  ja                   &&
  või                  ||

Funktsioonide deklareerimine muuda

Kompilleerides programmi läheb vaja, et kompilleeritaval funktsioonil oleksid atribuut funktsioonid ennem teda juba deklareeritud. Funktsiooni deklareerimisel jäetakse muutujad välja, kud kuvatakse nende tüübid.

arvuta(double, double, double);
kuva(double, double, double);

void arvuta(double a, double b, double c)
{
   sisu;
   kuva(a,b,c);
}
int main(void)
{
   sisu;
   arvuta(a,b,c);
}

Tüüpide korrektsus muuda

Üsna tihti võib probleemiks olla tüüpide sobimatus ja sellest tingitud tulemused.

void arvuta(long a)
{
   printf("Arvu väärtus on %5,4lf", a);
   return;
}
int main(void)
{
   integer arv=3,14123614683968;
   arvuta(arv);
}

Näites tehtud vead:

  1. Täisarv (integer), ei saa omada komakohti.
  2. Funktsiooni muutuja ei ühit välja kutsuja poolt pakutava muutuja failitüübiga.
  3. Arv soovitakse kuvada double suurusega, kui ta seda pole.
  4. Arvu komakohtada määramisel on täiskohtade ja komakohtade numbrite vahel punkt mitte koma.

Suured tähed ja väikesed tähed muuda

See võib tunduda üsna imelikuna, kuid C teeb vahet selle, kui sa kirjutad PrintF(sisu); ja printf(sisu);. Seega tasuks alati üle kontrollida, et tähesuurused oleksid samased kogu koodi kestel.

Tähemassiivide ja stringide väärtustamine muuda

Siin tuleb tähele panna, et ühel juhul on tegemist chr tüüpi viidaga ja teisel juhul kindla suurusega tähtede massiiviga. Algajale võib tekkida küsimus - "mis vahe siin on?", nõnda oleks soovitatav üle vaadata. mis viidad on ja kuidas nad töötavad.

    char *m;
    char n[20];

    m="hello";
    strcpy(n,"hello");

    printf("%s\n",m);
    printf("%s\n",n);

M puhul on tegemist viidaga, talle ei ole määratud suurust, vaid tema alguspunkt. M'i saab väärtustada tavaliselt m="väärtus";

N puhul on tegemist tähemärgi tüüpi massiiviga. Massiivi ei saa otse väärtustada viisil m="väärtus", selleks tuleb kasutada funktsiooni, mis paneb antud väärtuse täht tähe haaval massiivi.

See on üsna tüüpiline viga, mida algajad C programmeerijad tihti võivad teha - ajada m ja n sassi.

Näide mida näitab, et tähtis on olla programmeerija, olenemata keelest muuda

Näide on koodi minimeerimisest, või siis optimeerimisest koodikirjutajale. Sarnaseks nähtuseks võib võib täheldada kiirkirjutamisena.

Näites deklareeritakse 11 täisarvulist muutujat, millele antakse genereeritud suvaline arvväärtus. Peale seda kuvatakse konsooli teade "muutuja=väärtus" ja oodatakse klahvivajutust programmist väljumiseks.

#define nr(x) rand()% x
#define OOTA getchar();getchar();
#define IV(m,n) printf("m2s_j%d=%d",n,m2s_##m##n);
#define LI(i,r,n) int m2s_##i##r = n;
#define RV printf("\n");

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
   LI(i,1,11)

   while(m2s_i1--){
      LI(j,m2s_i1,nr(9))
      IV(j,m2s_i1)
      RV
   }
   OOTA
}

Ilma lühendamiseta polegi samalaadset võimalik teha, kuid kui kasutada mitme muutuja asemel 1 masiivi näeks kood välja selline


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
     int m2s_i1 = 9;
     int m2s_j[10];

     while(--m2s_i1){
        m2s_j[m2s_i1]=rand()%9;
        printf("m2s_j[%d]=%d",m2s_i1,m2s_j[m2s_i1]);
        printf("\n")
     }
     getchar();
     getchar(); 
}

Kahel koodil on vaid 1 erinevus, 1 kasutab palju ühesuguseid muutujaid ja teine masiivi.

Vaata ka muuda