Čítanie z parametrov
Načítajte z parametrov programu n čísiel a nájdite najväčšie spomedzi nich.
Využime funkciu
main()
s dvoma parametrami.- podrobnosti viď Z Javy migrujuvší céčkar 6
- deklarácia
char **
znamená po čítaní sprava do ľava- pointer na pointer na
char
, ale keďžechar *
je veľmi často reťazec, tak: - pointer na reťazec, ale keďže pole a pointer sú ekvivalentné, tak
- pole reťazcov
- pointer na pointer na
- na prevod reťazca na číslo použime
strtol()
.- podrobnosti viď Prevod reťazcov na čísla
- druhý parameter v
strtol
je tiežchar **
. V tomto prípade to však nie je pole charov, ale parameter odovzdávaný odkazom (teda vstupno-výstupná premenná), v ktorom sa po skončení parsovania objaví podreťazec vstupu, ktorý sa už nedal viac naparsovať na číslo. strtol
vracialong int
! (analógialong
z Javy)- nezabudnime inicializovať premennú pre doposiaľ nájdené maximum!
- využijeme “najmenší možný
long
” zlimits.h
- využijeme “najmenší možný
pri výpise
long int
ov cezprintf()
využime konštantu%ld
.#include<stdlib.h> #include<stdio.h> #include<limits.h> int main(int argc, char** argv) { int i; long int max = LONG_MIN; long int cislo; if(argc > 1) { max = strtol(argv[1], NULL, 10); } for (i = 2; i < argc; i++) { cislo = strtol(argv[i], NULL, 10); if(cislo > max) { max = cislo; } } printf("%ld\n", max); return 0; }
Triedenie polí
Zotrieďte 10prvkové pole
- Využime
qsort()
zostdlib.h
, čo je quicksort.
Quicksort qsort
Poobdivujme deklaráciu:
void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
- prvý parameter
base
obsahuje pole, ktoré sa ide triediť- je typu
void *
, pointer navoid
. - V tomto prípade to chápeme ako pointer na ľubovoľný typ.
- Ide o generický pointer, teda premennú, ktorá môže ukazovať na ľubovoľný typ.
- Akousi veľmi veľmi vzdialenou analógiou je premenná typu
Object
v Jave, ktorá môže tiež obsahovať ľubovoľný objekt. - v tomto prípade je to však
pole ľubovoľného typu
- je typu
- druhý parameter obsahuje počet prvkov poľa
- je typu
size_t
, čo je alias pre celé číslo reprezentujúce veľkost size_t
je napríklad typ, ktorý vracia makrosizeof
- je typu
- tretí parameter obsahuje veľkost jedného prvku
- ak máme pole
int
ov, posielamesizeof(int)
- ak máme pole
štvrtý parameter predstavuje odkaz na funkciu, ktorá porovná dva prvky poľa (komparátor)
- v Jave máme
Collections.sort()
, ktorá očakáva komparátor, teda triedu implementujúci interfejsjava.util.Comparator
komparátorom v C je ľubovoľná funkcia, ktorá spĺňa predpis
int(*compar)(const void *, const void *));
- musí vracať
int
- berie dva parametre, oba typu
const void *
- znamená to, že berie dva generické pointery
- musí vracať
- v Jave máme
- prvý parameter
Pointre na funkcie
qsort()
dostane odkaz na funkciuštvrtý parameter je potom pointer na funkciu
int(*compar)(const void *, const void *));
Predpis čítame zvnútra von ako compar je premenná typu pointer na funkciu, ktorá vracia
int
a berie dva generické pointre.ukážka funkcie, ktorá porovná dva
int
y:int compare(const void * cislo1, const void * cislo2) { int * c1 = (int *) cislo1; int * c2 = (int *) cislo2; if(*c1 < *c2){ return -1; } else if (*c1 > *c2) { return 1; } else { return 0; } }
- oba generické pointre musíme pretypovať na pointre príslušných typov
- podobne ako v Jave musíme
Object
pretypovať na príslušnú triedu, ak ho chceme zmysluplne používať - s pointrami pracujeme potom cez operátor referencie klasickým spôsobom
- pozor na zádrheľ, ak by sme referencie vynechali, porovnávali by sme v
c1 < c2
dve adresy, čo je síce možné (adresy sú čísla), ale nedáva to zmysel
funkciu potom použijeme veľmi jednoducho: cez názov
qsort(cisla, 8, sizeof(int), compare);
Celý kód
#include<stdio.h>
#include<stdlib.h>
#define DLZKA 8
int compare(const void * cislo1, const void * cislo2) {
int * c1 = (int *) cislo1;
int * c2 = (int *) cislo2;
if(*c1 < *c2){
return -1;
} else if (*c1 > *c2) {
return 1;
} else {
return 0;
}
}
int main(void) {
int i = 0;
int cisla[] = { 1, 5, -52, 68, 12, 45, -48, 78 };
qsort(cisla, DLZKA, sizeof(int), compare);
for(i = 0; i < DLZKA; i++) {
printf("%d, ", cisla[i]);
}
return 0;
}
Bonus
Keďže pole cisla
je staticky alokované (teda nie cez malloc()
), môžeme zistiť jeho dĺžku v programe:
int dlzka = sizeof(cisla) / sizeof(int);
Čítajme to ako “počet bajtov, ktoré zaberá celé pole delené počtom bajtov pre jeden prvok”.
Toto je jediný prípad, keď v C vieme zistiť dĺžku poľa za behu! Pole však musí byť alokované staticky, lebo celý výraz sa vyhodnotí v čase kompilácie!
Dvojrozmerné polia
Naplňte maticu číslami a vypíšte ju
Prvý pokus:
int matica[][] = {
{ 1, 2, 3},
{ 4, 5, 6},
{ 123456, 8, 9}
};
Kompilátor však vypíše:
error: array type has incomplete element type
Dvojrozmerné pole treba chápať ako pole polí. V tomto prípade musíme povedať, koľko polí bude podpole obsahovať (= koľko riadkov má matica):
int matica[][3] = {
{ 1, 2, 3},
{ 4, 5, 6},
{ 123456, 8, 9}
};
Ak by sme chceli funkciu pre výpis matice, musíme pamätať na to, že pole potrebuje dodať aj jeho dĺžku. Dvojrozmerné pole potrebuje teda dva rozmery:
/* TOTO NEFUNGUJE */
void matica_print(int m[][], int r, int s);
Opäť však dostaneme hlášku:
error: type of formal parameter 1 is incomplete
Funkcia musí dostať vonkajší rozmer!
void matica_print(int m[][3], int r, int s);
Táto funkcia je však prudko nepoužiteľná. Musíme to spraviť dynamicky. (Vysvetlenie napríklad C-Faq.com 6.19).
Funkcia bude mať parameter typu int **
(chápaný ako pole polí int
ov):
void matica_to_string(int ** m, int pocet_riadkov, int pocet_stlpcov) {
V kóde funkcie radostne pristupujeme k dvojrozmernému poľu cez indexy.
void matica_to_string(int ** m, int pocet_riadkov, int pocet_stlpcov) {
int i = 0;
int j = 0;
for(i = 0; i < pocet_riadkov; i++) {
for(j = 0; j < pocet_stlpcov; j++){
printf("%d ", m[i][j]);
}
printf("\n");
}
}
Dynamická alokácia poľa
najprv alokujeme pamäť pre vonkajšie pole (bude obsahovať pointre na “int`, teda odkazy na riadkové polia.):
int ** m = malloc(POCET_RIADKOV * sizeof( int * ));
potom pre každé riadkové pole alokujeme pamäť.
int ** m = malloc(POCET_RIADKOV * sizeof( int * )); if( m == NULL ) { perror("Zlyhal malloc()"); return -1; } for(i = 0; i < POCET_RIADKOV; i++) { m[i] = malloc( POCET_STLPCOV * sizeof( int )); }
- následne pristupujeme k pamäti cez indexy.
Dynamická dealokácia
- použime opačný proces: najprv v cykle dealokujeme riadkové polia
- potom dealokujeme hlavné pole.
Celý kód
#include<stdio.h>
#include<stdlib.h>
#define POCET_RIADKOV
#define POCET_STLPCOV
void matica_print(int ** m, int r, int r) {
int i = 0;
int j = 0;
for(i = 0; i < r; i++) {
for(j = 0; j < s; j++){
printf("%d ", m[i][j]);
}
printf("\n");
}
}
int ** matica_new(int riadkov, int stlpcov) {
int ** m = malloc(POCET_RIADKOV * sizeof( int * ));
if( m == NULL ) {
perror("Zlyhal malloc()");
return NULL;
}
for(i = 0; i < POCET_RIADKOV; i++) {
m[i] = malloc( POCET_STLPCOV * sizeof( int ));
if(m[i] == NULL) {
perror("Zlyhal malloc()");
return NULL;
}
}
return m;
}
void matica_free(int ** matica, int riadkov) {
for(i = 0; i < riadkov; i++) {
free(matica[i]);
}
free(m);
}
int main(void) {
int i;
int ** m = matica_new(POCET_RIADKOV, POCET_STLPCOV);
m[0][0] = 1; m[0][1] = 2; m[0][0] = 1;
m[0][0] = 4; m[0][1] = 5; m[0][0] = 6;
m[0][0] = 1234567890; m[0][1] = 8; m[0][0] = 9;
matica_print(m, POCET_RIADKOV, POCET_STLPCOV);
matica_free(m, POCET_RIADKOV);
return 0;
}
Zdroje
- Prednáška č. 12/2010 z predmetu Systémové programovanie o viacrozmerných poliach.
Dobry den
Chcel by som sa spytat, ako mam postupovat ak mam vytvorit program, ktory pomocou funkcie nacita prvky do stvrocovej matice rozmeru 4×4, nasledne vytvori transponovanu maticu,(tj. vymeni stplce za riadky) a pomocou dalsej funkcie tuto maticu vypise.
Dakujem :)
Odkiaľ sa má načítať obsah matice? Zo súboru?