Argumentumok kiírása
Írj programot, amely számozva kiírja a parancssori argumentumait a képernyőre!
Megoldás
#include <stdio.h>
int main(int argc, char *argv[]) {
/* argv[0] a program neve, és argv[argc]=NULL.
* ezért 1-től argc-1-ig kell mennie a ciklusnak. */
for (int i = 1; i < argc; ++i)
printf("%d. %s\n", i, argv[i]);
return 0;
}
Az argumentumok száma
Tegyük fel, hogy írni kell egy programot, amely két parancssori argumentumot vár: egy bemeneti és egy kimeneti fájl nevét. Írj rövid programot, amely ellenőrzi, hogy pontosan két parancssori argumentumot kapott-e! Írjon a program hibaüzenetet a képernyőre, ha nem!
Megoldás
#include <stdio.h>
int main(int argc, char *argv[]) {
/* a buktato: argv[0], vagyis a nulladik parancssori argumentum
* a program neve. ez beleszamit a kapott argumentumok szamaba,
* ezert pontosan 2 argumentum eseten argc erteke 3 lesz! */
if (argc == 3)
printf("Ket parancssori argumentumot kaptam.\n");
else
printf("Hiba: nem pontosan ket argumentumot kaptam!\n");
return 0;
}
Mini számológép
Írj programot, amely parancssori argumentumként három valamit vár: az első és a harmadik egy szám, a középső pedig a +, -, *, / műveleti jelek egyike! Írja ki a program a képernyőre az elvégzett művelet eredményét, vagy egy hibaüzenetet, ha az argumentumok bármilyen szempontból nem elfogadhatóak!
frank@hal9000:~$ szamologep 1 / 2 Az eredmeny: 0.5 frank@hal9000:~$ szamologep b + 2 Az elso es a harmadik argumentum legyen szam! frank@hal9000:~$ szamologep 1 +xyz 2 A masodik argumentum egy muveleti jel legyen!
Megoldás
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
double a, b, e;
if (argc != 4) {
printf("Harom argumentum kell: ket szam, es kozte egy muveleti jel!\n");
return 1;
}
/* az argumentumokat sztringkent (!) kapjuk, ezekbol
* az sscanf-fel kiolvashato a szamertek. */
if (sscanf(argv[1], "%lf", &a) != 1
|| sscanf(argv[3], "%lf", &b) != 1) {
printf("Az elso es a harmadik argumentum legyen szam!\n");
return 1;
}
if (strlen(argv[2]) != 1) {
printf("A masodik argumentum egy muveleti jel legyen!\n");
return 1;
}
/* argv[2] a masodik parameter, argv[2][0] annak legelso karaktere. */
if (argv[2][0] != '+' && argv[2][0] != '-'
&& argv[2][0] != '*' && argv[2][0] != '/') {
printf("A masodik argumentum egy muveleti jel legyen!\n");
return 1;
}
switch (argv[2][0]) {
case '+': e = a+b; break;
case '-': e = a-b; break;
case '*': e = a*b; break;
case '/': e = a/b; break;
default: /* lehetetlen */ break;
}
printf("Az eredmeny: %g\n", e);
return 0;
}
Mátrix négyzetre emelése
Írj egy programot, amelyik a parancssori paramétereiben vesz át egy négyzet alakú mátrixot, és megszorozza azt saját magával! Az eredményt mátrix formában jelenítse meg!
Megoldás
A következő dolgokra kell figyelni:
- A
main
két paramétereint argc
éschar *argv[]
. Az utóbbi a paramétereket tartalmazza sztring formájában, az előbbi pedig a paraméterek száma +1.argv[0]
a program neve, innen adódik a +1 – erre figyelni kell, amikor indexeljük a tömböt, illetveargc
-t vizsgáljuk. Ha 1 paraméter van,argc
értéke 2 lesz! - Mivel
char *argv[]
sztringeket tartalmaz, konvertálni kell azokat szám formába. Lent nem teszem, de azsscanf
függvény visszatérési értéke lehetővé tenné ennek ellenőrzését.
A memória foglalásoknál meg kell nézni, hogy sikeresek-e. A foglaláshoz lent egy külön függvény van, ahol ez jól látszik. A feladat megoldása egyébként elég egyszerű; inkább a lexikai tudásból igényel sokat, parancssori argumentumok kezelése stb.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
double **foglal(int meret) {
double **tomb;
tomb = (double **) malloc(meret * sizeof(double *));
if (!tomb) {
fprintf(stderr, "Memoriafoglalasi hiba\n");
exit(1); /* jobb hijan kiugrunk a programbol */
}
for (int y = 0; y < meret; ++y) {
tomb[y] = (double *) malloc(meret * sizeof(double));
if (!tomb[y]) {
fprintf(stderr, "Memoriafoglalasi hiba\n");
exit(1);
}
}
return tomb;
}
void felszabadit(double **tomb, int meret) {
for (int y = 0; y < meret; ++y)
free(tomb[y]);
free(tomb);
}
int main(int argc, char *argv[]) {
int meret = sqrt(argc - 1);
/* nezzuk, hogy negyzetszam-e */
if (meret * meret != argc - 1) {
fprintf(stderr, "Nem negyzetszam a parameterek szama!\n");
exit(1);
}
double **be = foglal(meret);
double **ki = foglal(meret);
/* beolvasas */
for (int y = 0; y < meret; ++y)
for (int x = 0; x < meret; ++x)
sscanf(argv[y * meret + x + 1], "%lf", &be[y][x]);
// negyzet kiszamitasa - ez a feladat lenyege
for (int y = 0; y < meret; ++y)
for (int x = 0; x < meret; ++x) {
double osszeg = 0;
int i;
for (int i = 0; i < meret; ++i)
osszeg += be[y][i] * be[i][x];
ki[y][x] = osszeg;
}
/* kiiras */
for (int y = 0; y < meret; ++y) {
for (int x = 0; x < meret; ++x)
printf("%8.4lf ", ki[y][x]);
printf("\n");
}
felszabadit(be, meret);
felszabadit(ki, meret);
return 0;
}
Fájl beolvasása
Készíts programot, mely az „adat1.txt” fájl tartalmát beolvassa és kiírja a képernyőre!
Fájl írása
Készíts programot, mely bekéri a felhasználó nevét, és azt az „adat1.txt” fájlba eltárolja! (Ha már létezett a file korábban, írja felül.)
Hányszor indult?
Készíts programot, mely induláskor írja ki a képernyőre, hogy hanyadszorra indítják. Az indítások számát tárolja az "indit.ini" fájlban. (Ha a file még nem létezik, akkor ez az első indítás, ha már létezik, akkor olvassa ki belőle az eddigi indítások számát, adjon hozzá egyet, azt írja ki a képernyőre, és tárolja vissza a fájlba.)
Kisbetűk
Készíts programot, amely egy megadott fájlt átolvasva kiírja, hogy az angol ABC kisbetűi közül melyik hányszor szerepel benne.
Köbméter
Egy tóra négyzetrácsot fektetünk, a négyzetrács egyes pontjaiban a tó mélységét tároljuk. 0-val jelöljük a szárazföldet, negatív számmal a mélységet méterben. Készíts programot, amelyik egy ilyen, fájlban adott „térkép” alapján téglatest módszerrel becsli a tó térfogatát. Az egyes mérési pontok távolságát kérdezze meg a program a felhasználótól. A fájl első sorában a táblázat szélessége és magassága (egész számok), a többi sorokban a táblázat egyes sorai; valós számok szóközzel elválasztva.
Szövegfájl titkosítása
Készítsünk egy programot, amelyik egy szövegfájlt titkosít. A titkosítás egyszerű: minden betű helyett az ABC-ben következőt használjuk, 'z' helyett pedig 'a'-t.
Megoldás
Ez szinte ugyanaz, mint a félév eleji változat, amelyik a billentyűzetről olvasott. Fájlból
olvasni, fájlba írni semmivel nem nehezebb: minden függvény neve elé még egy f betű kerül (
printf-fprintf
, scanf-fscanf
), és első paraméter a fájl, amin dolgozni
kell.
#include <stdio.h>
char kodol(char c) {
/* ez a ketto specialis, mert "tulpordul" */
if (c=='z') return 'a';
if (c=='Z') return 'A';
/* tobbi kodolando */
if ((c>='a' && c<'z') || (c>='A' && c<'Z'))
return c+1;
/* ha nem ezek, marad valtozatlanul */
return c;
}
int main(void) {
FILE *be = fopen("eredeti.txt", "r");
if (be == NULL) {
perror("eredeti.txt megnyitása");
return 1;
}
FILE *ki = fopen("kodolt.txt", "w");
if (ki == NULL) {
perror("kodolt.txt megnyitása");
return 2;
}
/* egyesevel a karakterek */
int c;
while ((c = fgetc(be)) != EOF)
fputc(kodol(c), ki);
fclose(be);
fclose(ki);
return 0;
}
Minimumkeresés fájlból, formátumsztringek
Egy meteorológiai állomás által rögzített hőmérsékleti értékeket fájlban kapjuk. A fájl első
sorában a mérés napja van, év, szóköz, hónap, szóköz, nap
formátumban. A fájl többi
sora óra, kettőspont, perc, szóköz, hőmérséklet
(valós szám) formátumban. Olvassuk
be a fájlt, és keressük meg, mikor volt a legmelegebb aznap. Írjuk ki az ehhez tartozó órát és
percet, illetve a hőmérsékletet, 2009.09.17. 12:08 +14.1
formátumban.
Példa bemenet:
2009 09 17 12:45 11.1 12:59 14.3 04:34 -5
Példa kimenet, amely a fenti bemenetre generálódik:
2009.09.17. 12:59 +14.3
Megoldás
#include <stdio.h>
#include <stdbool.h>
int main(void) {
typedef struct Datum {
int ev, honap, nap;
} Datum;
typedef struct Meres {
int ora, perc;
double fok;
} Meres;
/* fussunk neki */
FILE *fbe = fopen("eredmenyek.txt", "r");
if (!fbe) {
perror("eredmenyek.txt: nem sikerult megnyitni a fajlt");
return 1;
}
Datum d;
Meres beolv, max;
fscanf(fbe, "%d %d %d", &d.ev, &d.honap, &d.nap);
/* a maximumkeresesnel az elso megkulonbozteteset
itt segedvaltozoval oldottam meg */
bool elso = true;
while (fscanf(fbe, "%d:%d %lf", &beolv.ora, &beolv.perc, &beolv.fok) == 3) {
if (elso || beolv.fok > max.fok)
max = beolv;
elso = false;
}
/* ennyi */
fclose(fbe);
/* eredmeny kiirasa, formatumsztring */
printf("%d.%02d.%02d. %02d:%02d %+g\n",
d.ev, d.honap, d.nap,
max.ora, max.perc, max.fok);
return 0;
}
Névsor
Egy fájl hallgatók vizsgajegyeit tartalmazza, Neptun-kód, szóköz, jegy, szóköz, név formátumban soronként. Ha a hallgató nem kapott aláírást, a jegy helyén egy mínusz szerepel. Készíts programot, amely statisztikát ír ki a vizsgáról. Például:
AABB12 5 Tehetséges Béla CC43EF 4 Pedál Tibi BBCC34 - Lógós Feri XYYXY1 4 Ezoterikus János
Kimenet:
Jeles: 1 fő Jó: 2 fő Nem kapott aláírást: 1 fő
Egyszerű preprocesszor
Írj programot, amely egy egyszerű C preprocesszorként működik. Beolvas egy C forráskódú
programot, és a #define
sorokat értelmezi, illetve a megadott szavakat cseréli.
(Paraméteres makrókat nem kell felismernie.) Példa bemenet:
#define YES 1 #define NO 0 fuggveny(a, YES);
Kimenet:
fuggveny(b, 1);
Az alábbi egyszerűsítésekkel élhetsz. Elegendő, ha a program maximum 100 makrót tud megtanulni. A makrók neve legfeljebb 30 betűs, a tartalmuk legfeljebb 200 betűs lehet. A sorok maximális hossza 1000 lehet, viszont egy sorban egy makró szerepelhet többször is! Feltételezheted, hogy a forráskódban nincsenek sztringek.
Bináris fájlból C forráskód
Gyakran praktikus, ha a programjaink bizonyos adatokat nem fájlból olvasnak, hanem a lefordított program eleve tartalmazza azokat. Készíts programot, amely bináris fájlt beolvasva C-s tömböt készít abból. Például ha egy 8 bájtos bináris fájl a 98, 21, 17, 58, 255, 0, 7, 1 bájtokat tartalmazza, a program által létrehozott szövegfájl így néz ki:
unsigned char adat[] = { 98, 21, 17, 58, 255, 0, 7, 1, }; const int adat_len=8;
Figyelj arra, hogy a kimeneti fájl tartalmazzon sortöréseket is, vagyis a vesszővel elválasztott számok ne nyúljanak túl a 80 karakteres képernyőn! (A C a tömbök kezdeti értékének megadásakor megengedi, hogy az utolsó adat után is szerepeljen vessző. A fenti példa is ilyen.)
Fájlok összehasonlítása
Írj olyan programot, amely két bináris fájlt hasonlít össze, és kiírja az eltérések helyét, továbbá az első és második fájlban található különböző bájtokat! Például:
poz. f1 f2 0456 00 12 0ef3 fe fb
A nem egyforma méretű fájlokat el se kezdje összehasonlítani!
Megoldás
Az fread()
függvénnyel tudunk a fájlból olvasni, és figyelni kell a
"b"
betűre a fájl megnyitásánál.
A fájl méretét megadó függvény a C-ben nincs. Helyette azt csinálhatjuk, hogy a végére
ugrunk (fseek()
), és lekérdezzük a pozíciót (ftell()
).
#include <stdio.h>
/* kulturalt fuggveny: a fajlbol elugrik mashova,
de vissza is ugrik oda, ahol eredetileg volt */
long meret(FILE *fp) {
long pos, meret;
pos = ftell(fp);
/* 0 bajt a vegehez kepest, az pont a vege */
fseek(fp, 0, SEEK_END);
meret = ftell(fp);
fseek(fp, pos, SEEK_SET);
return meret;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Ket fajlnevet kerek!\n");
return -1;
}
FILE* f1 = fopen(argv[1], "rb");
if (f1 == NULL) {
perror(argv[1]);
return 1;
}
FILE* f2 = fopen(argv[2], "rb");
if (f2 == NULL) {
perror(argv[2]);
fclose(f1); /* nagyon kis rendesek vagyunk */
return 2;
}
if (meret(f1) != meret(f2)) {
fprintf(stderr, "Nem egyforma meretuek!\n");
fclose(f1);
fclose(f2);
return 3;
}
/* amig sikerul az elso fajlbol olvasni */
unsigned char buf1[512], buf2[512];
size_t beolv, pos;
pos = 0;
while ((beolv = fread(buf1, 1, sizeof(buf1), f1)) > 0) {
/* ennek is mennie kell */
fread(buf2, 1, sizeof(buf2), f2);
/* csak annyit hasonlitunk, amennyit beolvastunk! */
for (int i = 0; i < beolv; i++) {
if (buf1[i] != buf2[i])
/* pos: eddig feldolgozott bajtok,
+i: a most vizsgalt bajt */
printf("%08x %02x %02x\n", pos + i, buf1[i], buf2[i]);
}
pos += beolv;
}
fclose(f1);
fclose(f2);
return 0;
}
RLE betömörítés
Az RLE (run length encoding) az egyik legegyszerűbb tömörítési algoritmus. Lényege, hogy az egymás után következő egyforma bájtokat elég csak egyszer eltárolni, és megjelölni, hogy hányszor szerepeltek. Ha pedig nem egyforma bájtok követik egymást, azokat simán átmásolja az RLE.
A tömörített adatunkban 0xbf karakterrel jelöljük az ilyen többszörözést. A 0xbf utáni első karakter az ismétlendő bájt, az azutáni pedig az ismétlések száma!
Írj programot, amelyik egy megadott fájlt betömörítve egy másik fájlba ír! Figyelj arra, hogy ha az eredeti fájlban 0xbf szerepel, azt nem szabad egyszerűen átmásolni, mert akkor a kitömörítő algoritmus ismétlés megjelölésének próbálná értelmezni.
RLE kitömörítés
Írd meg a fenti program kitömörítő párját.
RLE tömörítő
Dolgozd össze az előző két feladat megoldását egy komplett parancssori alkalmazássá! Az alkalmazással lehessen betömöríteni és kitömöríteni is fájlokat! Az elvégzendő műveletet az első parancssori paraméter, a két fájlnevet (bemenet és kimenet) pedig a második parancssori paraméter adja meg!
C:\> rle betomorit input.dat output.rle C:\> rle kitomorit output.rle input.dat