5. gyakorlat
2. ZH
A gyakorlat elején 25 percben kerül megírásra a 2. zh.
A feladat(ok) témái:
- függvények megírása, bemenet/kimenet kezelés nélkül
- vezérlési szerkezetek használata
A zh-t a bíró rendszeren keresztül kell leadni az óra időpontjában.
Struktúra és unió
A struct
és a union
is adatok/változók gyűjteményeként, kollekciójaként fogható fel.
Mindkettőnek mezői vannak, melyekben többfajta típusú adat tárolható.
Alapvető különbség viszont, hogy a struct
egyszerre tudja az összes mező értékét tárolni, míg a union
egyszerre csak egy mező értékét tárolja (azét, amelyik legutóbb értéket kapott).
A mezők olyan viszonyban vannak a teljes struktúrával/unióval, mint a tömbelemek a teljes tömbbel.
Csak míg a tömbelemek egyforma típusúak és egy index segítségével hivatkozhatók, addig a struktúra/unió elemei különböző típusúak lehetnek és mezőnévvel tudunk rájuk hivatkozni.
Struktúra
Egy struktúrában tárolhatunk több különböző féle adattípust, kezelhetjük őket külön, de egyetlen egységként is.
Egy struktúra definiálásakor adhatunk neki egy nevet, és meg kell adnunk a benne lévő mezők típusát és neveit is (mintha csak "belső" változókat deklarálnánk).
Például ha létre akarunk hozni egy struktúrát a komplex számok tárolására, azt megtehetjük így:
| struct komplex {
double valos;
double kepzetes;
};
|
Amennyiben el akarjuk érni a struktúránk egyik mezőjét, a .
operátort kell használnunk.
| int main() {
struct komplex z;
z.valos = 0.7071;
z.kepzetes = -0.7071;
return 0;
}
|
A tömbökkel ellentétben egy struct
típus megengedett függvény visszatérési értékeként is:
| struct komplex dupla(struct komplex z) {
z.valos = z.valos*2;
z.kepzetes = z.kepzetes*2;
return z;
}
|
A fenti példában a függvény paramétere is struktúra volt, de paraméterként a tömb is megengedett, így az nem különbség.
Vegyük észre, hogy a típus neve struct komplex
, vagyis így együtt kellett használni mindenhol.
A struct
modnja meg, hogy ez egy ilyen jellegű összetett típus, a struktúranév pedig a pontos belső szerkezetét azonosítja.
Az alábbi videók a struktúrákat mutatják be:
Példák
Egy könnyebb, szemléltető feladaton ki is tudjuk próbálni, hogyan működik:
Feladat (f0181)
Problémafelvetés:
Írj egy programot ami három oldalhosszból kiszámítja egy háromszög kerületét
és területét!
Algoritmustervezés/Megvalósítás:
A számítást egyetlen függvény végezze, a főprogram csak a bemenet-kimenetért
feleljen. A terület és kerület tárolására hozz létre egy struct
adattípust,
a számítást végző függvény egy ilyen típusú értékkel térjen vissza.
Megjegyzés
C-ben egy függvény egyetlen értékkel tud csak visszatérni.
Ez az érték viszont lehet struktúra típusú, ami akárhány és akármilyen típusú mezőt tartalmazhat.
Vagyis, technikailag C-ben is megoldható a több értékkel való visszatérés, bár ilyen esetekben inkább kimenő paramétereket szokás használni, mint azt majd a pointereknél látjuk.
Ötlet
Mivel egy összetett típusú érték megadása szintaktikailag nem annyira triviális, érdemes a függvényben a visszatérési érték tárolására létrehozni egy változót, beállítani ennek mezőit, majd a változó értékével visszatérni.
A háromszög kerületének kiszámolása az \(a\), \(b\) és \(c\) oldalhosszak alapján reméljük nem okoz fejtörést.
A kerület feléből (\(s\)) a Héron-képlet (\(T=\sqrt{s(s-a)(s-b)(s-c)}\)) segítségével ki tudjuk számolni a területet.
Lehetséges megoldás (m0181.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai feladat megoldása
*
* Gergely Tamás, 2018. őszi félév.
*
* Algoritmustervezés/Megvalósítás*:
* A számítást egyetlen függvény végezze, a főprogram csak a bemenet-
* kimenetért feleljen. A terület és kerület tárolására hozz létre egy
* struct adattípust, a számítást végző függvény egy ilyen típusú
* értékkel térjen vissza.
*
* fordítás:
* gcc -o m0181 m0181.c -lm
*
* futtatás:
* ./m0181
*/
#include <math.h>
#include <stdio.h>
struct haromszog {
double kerulet;
double terulet;
};
struct haromszog szamolas(double a, double b, double c) {
struct haromszog retval; // Mivel a visszatérési érték egy összetett típus lesz,
double s; // egyszerűbb egy változóban összerakni ezt az értéket,
retval.kerulet = a + b + c;
s = retval.kerulet / 2.0;
retval.terulet = sqrt(s * (s-a) * (s-b) * (s-c));
return retval; // és a végén a változó értékével visszatérni.
}
int main() {
double a, b, c;
struct haromszog adat;
printf("Kérem a három oldal hosszát: ");
scanf("%lf %lf %lf", &a, &b, &c);
adat = szamolas(a, b, c);
printf("Kerület: %lf\nTerület: %lf\n", adat.kerulet, adat.terulet);
return 0;
}
|
Illetve egy picit belegondolva ezt is meg tudjuk oldani:
Feladat (f0182)
Problémafelvetés:
Írj egy programot ami három kétdimenziós koordináta-párból kiszámítja egy
háromszög kerületét és területét!
Algoritmustervezés/Megvalósítás:
Az érdemi számításokat függvények végezzék, a főprogram csak a
bemenet-kimenetért feleljen. A kétdimenziós pont tárolására, valamint a
terület és kerület együttes tárolására is hozz létre struct
adattípusokat,
és a számítást végző függvények ezeket használják (ahol ez lehetséges).
Ötlet
Érdemes az előző feladat megoldását bővíteni.
Beolvasáskor a scanf
segítségével a struktúra mezőibe mint változókba tudunk beolvasni értékeket (vagyis nem kell külön változóba beolvasni, és azt utána átadni a struktúra megfelelő mezőjének).
A háromszög három oldalát egy-egy pontpár távolságából tudjuk kiszámolni.
Két pont távolságának kiszámolására érdemes külön függvényt csinálni, ez a Pitagorasz tétel alapján a pontok x és y koordinátáinak páronként vett különbségei négyzetösszegének négyzetgyökével fog visszatérni.
A háromszög jellemzőinek kiszámolásához tehát először a pontokból meghatározzuk az \(a\), \(b\) és \(c\) oldalhosszakat, ezekből pedig az előző feladat szamolas
függvénye már ki tudja számolni azt, amit kell.
Lehetséges megoldás (m0182.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai feladat megoldása
*
* Gergely Tamás, 2018. őszi félév.
*
* Algoritmustervezés/Megvalósítás*:
* Az érdemi számításokat függvények végezzék, a főprogram csak a
* bemenet-kimenetért feleljen. A kétdimenziós pont tárolására, valamint
* a terület és kerület együttes tárolására is hozz létre struct
* adattípusokat, és a számítást végző függvények ezeket használják (ahol
* ez lehetséges).
*
* fordítás:
* gcc -o m0182 m0182.c -lm
*
* futtatás:
* ./m0182
*/
#include <math.h>
#include <stdio.h>
struct pont {
double x;
double y;
};
struct haromszog {
double kerulet;
double terulet;
};
double tavolsag(struct pont p, struct pont q) {
double dx, dy;
dx = p.x - q.x;
dy = p.y - q.y;
return sqrt(dx*dx + dy*dy);
}
struct haromszog szamolas(double a, double b, double c) {
struct haromszog retval;
double s;
retval.kerulet = a + b + c;
s = retval.kerulet / 2.0;
retval.terulet = sqrt(s * (s-a) * (s-b) * (s-c));
return retval;
}
int main() {
struct pont a, b, c;
struct haromszog adat;
printf("Kérem a három pont koordinátáit ax ay bx by cx cy sorrendben:\n");
scanf("%lf %lf %lf %lf %lf %lf", &a.x, &a.y, &b.x, &b.y, &c.x, &c.y);
adat = szamolas(tavolsag(a, b), tavolsag(b, c), tavolsag(c, a));
printf("Kerület: %lf\nTerület: %lf\n", adat.kerulet, adat.terulet);
return 0;
}
|
A specifikációtól eltérő, de ugyanazt az alapproblémát megoldó program:
| [![traingle struct][yvi_triangle_struct]][ytv_triangle_struct]
|
Unió
Az union
egy kicsit máshogy működik mint a struct
.
Szintaktikailag nagyon hasonlít a struct
-ra, hasonlóan tudjuk kezelni, de ha felülírjuk az egyik adattagjának az értékét, azzal az összes többi adattag értékét "töröljük", definiálatlanná tesszük.
A union
létrehozása olyan, mint a struct
-é, csak a kulcsszó más:
| union numbers {
int egesz;
bouble valos;
};
|
Az alábbi videó az unió tulajdonságait mutatja be:
Egymásba ágyazás
Ezeket a típusokat egymásba is lehet ágyazni, például:
| union reg {
struct {
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
} bytes;
unsigned int dword;
}
|
Tehát el tudunk menteni egy (a jelenleg használt architektúrákon valószínűleg) 4 byte-os unsigned int
értéket a dword
mezőben vagy 4 darab 1 byte-os unsigned char
értéket a bytes
nevű struct
típusú mezőben.
Megjegyzés
A mezők fizikai tárolási módja miatt (az union
összes mezője "ugyanott" tárolodik a memóriában, ezért is tudja csak az egyik értékét megjegyezni) ha a union
bármelyik mezőjének (bytes
vagy dword
) értéket adunk, akkor a másik mező is "kap egy értéket" (mivel a tárolásra használt bitek ugyanazok, de legalábbis átfednek).
Ennek az "új értéknek" az értelmezése jelentősen eltérhet a másik mező szerinti értelmezéstől.
Mivel itt mindkét mező összesen ugyanakkora (4-szer 1, illetve 1-szer 4 bájt), a bytes
-ban pontosan a dword
egyes bájtjait érjük el.
Feladat
Hozzunk létre egy struct
-ot és egy union
-t ugyanazokkal az adatagokkal.
Adjunk értéket mindkettő első adattagjának és nézzük meg az adattagok értékeit.
Adjunk értéket a második adattagoknak is, majd megint nézzük meg az adattagok értékeit.
Mit tapasztalunk?
Lehetséges válaszok
Az első értékadások után a struct
és union
első adattagjából is ugyanúgy ki tudjuk olvasni a belerakott értéket, a második adattagok pedig látszólag valamilyen véletlen értékeket tartalmaznak.
Az újabb értékadás után a struct
mindkét mezőjének értéke az maradt, amit annak a mezőnek értékül adtunk, a union
első mezője viszont látszólag valami véletlenszerű értéket tartalmaz.
Ha a két mezőt ugyanolyan típusúnak deklaráltuk, akkor a union
mindkét mezőjében az előtte bármely mezőnek adott értéket találjuk.
Az azonos típusú mezők a struct
típus viselkedésében nem okoznak ilyen eltérést.
Típusdefiníció
Van lehetőségünk új típusokat is definiálni.
Az erre használatos kulcsszó a typedef
.
A definiálás módja:
typedef típus név;
Létrehozhatunk például egy vector
adattípust, 3 dimenziós valós térbeli helyvektor tárolására!
Figyelj!
Dimenziószám és dimenziószám között lehetnek különbségek.
A három dimenziós térbeli helyvektor az adattípus magas szintű (szaktudományos, matematikai) megfogalmazása, azt jelenti, hogy három egymástól független értéket kell tárolnunk.
Három egymástól független értéket absztrakt adattípusként egy három elemű egydimenziós tömbben tudunk tárolni.
Vagyis a dimenziószám jelentése a "szövegkörnyezet" függvényében eltérhet.
| typedef double vector[3];
|
Létrehozhatunk egy u16
adattípust előjeltelen unsigned short int
-ek tárolására:
| typedef unsigned short int u16;
|
Vagy épp struktúrát is, ilyen módon:
| typedef struct {
char nev[32];
int eletkor;
} hallgato;
|
Vegyük észre a különbséget a korábbi struktúra definíció és a mostani típusdefiníció között.
Itt a hallgato
nem csak egy struktúra elnevezése (ami megkülönbözteti ezt a struktúrát a többi struktúrától), hanem egy teljes típusé, így a struct
kulcsszó nélkül, önállóan használható, például az alábbi módon:
| hallgato idosebb(hallgato h1, hallgato h2) {
return h1.eletkor >= h2.eletkor ? h1 : h2;
}
|
Videó a typedef
használatáról:
A következő feladatban használjunk típusdefiníciót!
Feladat (f0200)
Problémafelvetés:
Írj egy programot, ami kiszámolja, majd irányszöggel és nagysággal megadja a
hasonlóképpen megadott fizikai erők sorozatának eredőjét a kétdimenziós
térben. Az erők sorozatának végét egy 0 nagyságú erő jelzi.
Algoritmustervezés/Megvalósítás:
A főprogram csak az input/output műveleteket végezze, a számolást külön
függvény(ek)ben oldd meg. Az adatok tárolására használj összetett
adatszerkezetet, ha van értelme.
Ötlet
Egy kétdimenziós vektort kétféleképpen lehet megadni: irányszög és nagyság párossal, vagy x és y koordináta-párral.
A kettő egyértelműen átalakítható egymásba a szinusz (sin
) és koszinusz (cos
), illetve az arkusz-tangens (atan
- inverz tangens) függvények segítségével.
Erre szükségünk is lesz, hiszen a bemenet és kimenet irányszög-nagyság vektorokkal dolgozik, vektorokat összeadni ugyanakkor az x-y koordinátapárral sokkal egyszerűbb.
Kell tehát egy-egy struct
típus a kétféle tárolásra, és egy-egy függvény az oda-vissza konverzióra.
És akkor már érdemes egy külön függvényt írni két x-y koordinátás vektor összeadására is.
Ezekben a függvényekben a megfelelő struct
típus használható visszatérési értékként.
Lehetséges megoldás (m0200.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai feladat megoldása
*
* Gergely Tamás, 2018. őszi félév.
*
* Algoritmustervezés/Megvalósítás:
* Kétféle főbb adattípusunk lesz, mindkettő a vektor reprezentálására. Az
* egyik a polárkoordináták (irányszög és nagyság, a szög fokokban), a
* másik a derékszögű koordinátarendszer (x és y koordináták) szerinti
* tárolásra. A konverziót az egyikről a másikra függvényekkel oldjuk meg.
* Az összegzéshez az (x,y) verziót használjuk (az egyszerűbb), és külön
* függvényt írunk rá.
*
* fordítás:
* gcc -o m0200 m0200.c -lm
*
* futtatás:
* ./m0200
*/
#include <math.h>
#include <stdio.h>
typedef struct {
double x, y;
} vector_xy_t;
typedef struct {
double irany, nagysag;
} vector_in_t;
vector_xy_t convert_to_xy(vector_in_t v) {
vector_xy_t retval;
retval.x = cos(v.irany * M_PI / 180.0) * v.nagysag;
retval.y = sin(v.irany * M_PI / 180.0) * v.nagysag;
return retval;
}
vector_in_t convert_to_in(vector_xy_t v) {
vector_in_t retval;
if (v.x == 0.0) {
if (v.y == 0.0) {
retval.irany = 0.0;
} else {
retval.irany = (v.y > 0.0) ? 90.0 : -90.0;
}
} else {
retval.irany = atan(v.y/v.x) * 180.0 / M_PI;
if (v.x < 0.0) {
if (v.y < 0.0) {
retval.irany -= 180.0;
} else {
retval.irany += 180.0;
}
}
}
retval.nagysag = sqrt(v.x*v.x + v.y*v.y);
return retval;
}
vector_xy_t add(vector_xy_t a, vector_xy_t b) {
vector_xy_t retval;
retval.x = a.x + b.x;
retval.y = a.y + b.y;
return retval;
}
int main() {
vector_in_t v_in;
vector_xy_t v_xy, v_sum = { .x = 0.0, .y = 0.0 };
scanf("%lf %lf", &v_in.irany, &v_in.nagysag);
while (v_in.nagysag != 0.0) {
v_xy = convert_to_xy(v_in);
v_sum = add(v_sum, v_xy);
scanf("%lf %lf", &v_in.irany, &v_in.nagysag);
}
v_in = convert_to_in(v_sum);
printf("(%lf°, %lf)\n", v_in.irany, v_in.nagysag);
return 0;
}
|
Fordítási hibák és figyelmeztetések
A fordítónk és felhasználói környezetünk segítségünkre van a program írása közben.
Ha valami szintaktikai hiba csúszik a kódunkba, azt a fordító fordítás közben jelzi nekünk (és mellesleg nem készíti el a programot).
(Egyes IDE-k, szövegszerkesztők akár már írás közben jelezhetik ezeket a hibákat.)
Ezeket a hibaüzeneteket érdemes megismerni, és megtanulni értelmezni.
A következő feladatok tele vannak szintaktikai (ha úgy tetszik, "helyesírási") hibákkal, keressük meg hol vannak ezek és milyen hibaüzenetet kapunk velük!
Feladat (f0263)
Feladat:
A felszin.c
program feladata lenne kiszámolni a térben négy pont által
meghatározott test felszínét. A programban a fordítása során a fordító több
hibát és figyelmeztetést is jelez. Javítsd ki ezeket!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai
*/
#include <stdio.h>
struct pont {
double x;
double y;
double z;
}
typedef struct pont pont_t;
int Main(int argc, char *argv[]) {
pont_t P[4];
double t[4];
double felszin;
if (argc < 5) {
fprintf(stderr, "Használat: %c '(x1,y1,z1)' '(x2,y2,z2)' '(x3,y3,z3)' '(x4,y4,z4)'\n", argv[0]);
return 1;
}
for (i = 0; i < 4; ++i) {
P(i) = get_pont(argv[i+1]);
t(i) = 0.0;
}
t[0] = terulet(P[1], P[2], P[3]);
t[1] = terulet(P[0], P[2], P[3]);
t[2] = terulet(P[0], P[1], P[3]);
t[3] = terulet(P[0], P[1], P[2]);
for (i = 0; i < 4; ++i) {
if (t[i] = 0.0)
printf("A megadott pontok egy síkba esnek.\n");
return 1;
}
}
for (i = 0; i < 4; ++i) {
felszin += t{i};
}
printf("A test felszíne: A = %.3lf\n", felszin);
return 0;
}
pont_t get_pont(const char *str) {
pont_t retval = {0.0, 0.0, 0.0};
sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
}
double tavolsag[pont_t P, pont_t Q] {
pont_t d;
d.x = P.x - Q.x;
d.y = P.y - Q.y;
d.z = P.z - Q.z;
return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
}
double terulet(pont_t A, pont_t B, pont_t C) [
double a, b, c, s;
a = tavolsag(B, C);
b = tavolsag(A, C);
c = tavolsag(A, B);
s = (a + b + c) / 2.0;
return sqrt(s * (s - a) * (s - b) * (s - c));
]
|
felszin.c
A gcc fordító kimenete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 | felszin.c:17:9: error: expected ‘;’, identifier or ‘(’ before ‘struct’
17 | typedef struct pont pont_t;
| ^~~~~~
felszin.c: In function ‘Main’:
felszin.c:20:5: warning: statement with no effect [-Wunused-value]
20 | pont_t P[4];
| ^~~~~~
felszin.c:20:11: error: expected ‘;’ before ‘P’
20 | pont_t P[4];
| ^~
| ;
felszin.c:24:39: warning: format ‘%c’ expects argument of type ‘int’, but argument 3 has type ‘char *’ [-Wformat=]
24 | fprintf(stderr, "Használat: %c '(x1,y1,z1)' '(x2,y2,z2)' '(x3,y3,z3)' '(x4,y4,z4)'\n", argv[0]);
| ~^ ~~~~~~~
| | |
| int char *
| %s
felszin.c:27:10: error: ‘i’ undeclared (first use in this function)
27 | for (i = 0; i < 4; ++i) {
| ^
felszin.c:27:10: note: each undeclared identifier is reported only once for each function it appears in
felszin.c:28:9: warning: implicit declaration of function ‘P’ [-Wimplicit-function-declaration]
28 | P(i) = get_pont(argv[i+1]);
| ^
felszin.c:28:16: warning: implicit declaration of function ‘get_pont’ [-Wimplicit-function-declaration]
28 | P(i) = get_pont(argv[i+1]);
| ^~~~~~~~
felszin.c:29:9: error: called object ‘t’ is not a function or function pointer
29 | t(i) = 0.0;
| ^
felszin.c:21:12: note: declared here
21 | double t[4];
| ^
felszin.c:31:12: warning: implicit declaration of function ‘terulet’ [-Wimplicit-function-declaration]
31 | t[0] = terulet(P[1], P[2], P[3]);
| ^~~~~~~
felszin.c:31:20: error: ‘P’ undeclared (first use in this function)
31 | t[0] = terulet(P[1], P[2], P[3]);
| ^
felszin.c:36:9: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
36 | if (t[i] = 0.0)
| ^~
felszin.c:38:13: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
38 | return 1;
| ^~~~~~
felszin.c:22:12: warning: unused variable ‘felszin’ [-Wunused-variable]
22 | double felszin;
| ^~~~~~~
felszin.c: At top level:
felszin.c:41:5: error: expected identifier or ‘(’ before ‘for’
41 | for (i = 0; i < 4; ++i) {
| ^~~
felszin.c:41:19: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘<’ token
41 | for (i = 0; i < 4; ++i) {
| ^
felszin.c:41:24: error: expected identifier or ‘(’ before ‘++’ token
41 | for (i = 0; i < 4; ++i) {
| ^~
felszin.c:44:12: error: expected declaration specifiers or ‘...’ before string constant
44 | printf("A test felszíne: A = %.3lf\n", felszin);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
felszin.c:44:45: error: unknown type name ‘felszin’
44 | printf("A test felszíne: A = %.3lf\n", felszin);
| ^~~~~~~
felszin.c:45:5: error: expected identifier or ‘(’ before ‘return’
45 | return 0;
| ^~~~~~
felszin.c:46:1: error: expected identifier or ‘(’ before ‘}’ token
46 | }
| ^
felszin.c:48:1: error: unknown type name ‘pont_t’
48 | pont_t get_pont(const char *str) {
| ^~~~~~
felszin.c: In function ‘get_pont’:
felszin.c:49:5: warning: statement with no effect [-Wunused-value]
49 | pont_t retval = {0.0, 0.0, 0.0};
| ^~~~~~
felszin.c:49:11: error: expected ‘;’ before ‘retval’
49 | pont_t retval = {0.0, 0.0, 0.0};
| ^~~~~~~
| ;
felszin.c:50:34: error: ‘retval’ undeclared (first use in this function)
50 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ^~~~~~
felszin.c: At top level:
felszin.c:53:23: error: expected ‘]’ before ‘P’
53 | double tavolsag[pont_t P, pont_t Q] {
| ^~
| ]
felszin.c:61:16: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:61:26: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:61:36: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:63:5: warning: data definition has no type or storage class
63 | a = tavolsag(B, C);
| ^
felszin.c:63:5: warning: type defaults to ‘int’ in declaration of ‘a’ [-Wimplicit-int]
felszin.c:63:9: warning: implicit declaration of function ‘tavolsag’ [-Wimplicit-function-declaration]
63 | a = tavolsag(B, C);
| ^~~~~~~~
felszin.c:63:18: error: ‘B’ undeclared here (not in a function)
63 | a = tavolsag(B, C);
| ^
felszin.c:63:21: error: ‘C’ undeclared here (not in a function)
63 | a = tavolsag(B, C);
| ^
felszin.c:64:5: warning: data definition has no type or storage class
64 | b = tavolsag(A, C);
| ^
felszin.c:64:5: warning: type defaults to ‘int’ in declaration of ‘b’ [-Wimplicit-int]
felszin.c:64:18: error: ‘A’ undeclared here (not in a function)
64 | b = tavolsag(A, C);
| ^
felszin.c:65:5: warning: data definition has no type or storage class
65 | c = tavolsag(A, B);
| ^
felszin.c:65:5: warning: type defaults to ‘int’ in declaration of ‘c’ [-Wimplicit-int]
felszin.c:66:5: warning: data definition has no type or storage class
66 | s = (a + b + c) / 2.0;
| ^
felszin.c:66:5: warning: type defaults to ‘int’ in declaration of ‘s’ [-Wimplicit-int]
felszin.c:66:9: error: initializer element is not constant
66 | s = (a + b + c) / 2.0;
| ^
felszin.c:67:5: error: expected identifier or ‘(’ before ‘return’
67 | return sqrt(s * (s - a) * (s - b) * (s - c));
| ^~~~~~
felszin.c:68:1: error: expected identifier or ‘(’ before ‘]’ token
68 | ]
| ^
felszin.c: In function ‘Main’:
felszin.c:40:5: warning: control reaches end of non-void function [-Wreturn-type]
40 | }
| ^
felszin.c: In function ‘get_pont’:
felszin.c:51:1: warning: control reaches end of non-void function [-Wreturn-type]
51 | }
| ^
|
Megoldás, 1. lépés
| felszin.c:17:9: error: expected ‘;’, identifier or ‘(’ before ‘struct’
17 | typedef struct pont pont_t;
| ^~~~~~
|
A 17. sor előtt hiányzik egy ;
karakter: praktikusan a 15. sorban nincs lezárva a struktúra-definíció.
| felszin.c: In function ‘Main’:
felszin.c:20:5: warning: statement with no effect [-Wunused-value]
20 | pont_t P[4];
| ^~~~~~
felszin.c:20:11: error: expected ‘;’ before ‘P’
20 | pont_t P[4];
| ^~
| ;
|
Ezeket az előző hiba okozta: nem volt deklarálva a struktúra.
| felszin.c:24:39: warning: format ‘%c’ expects argument of type ‘int’, but argument 3 has type ‘char *’ [-Wformat=]
24 | fprintf(stderr, "Használat: %c '(x1,y1,z1)' '(x2,y2,z2)' '(x3,y3,z3)' '(x4,y4,z4)'\n", argv[0]);
| ~^ ~~~~~~~
| | |
| int char *
| %s
|
A 24. sorban rossz a konverziós specifkáció: sztringeket, mint ami az argv[0]
is, a %s
specifikációval kell kiíranti, nem a %c
-vel.
| felszin.c:27:10: error: ‘i’ undeclared (first use in this function)
27 | for (i = 0; i < 4; ++i) {
| ^
felszin.c:27:10: note: each undeclared identifier is reported only once for each function it appears in
|
A 27. sorban használt i
változó nincs deklarálva.
A gcc csak egyszer szól érte, pedig a 28., 29., 35., 36., 41. és 42. sorokban is használva van.
Vagy for (int i = 0; ...
módon deklaráljuk, de akkor a 35. és 41. sorban is így kell tenni, vagy a függvény elején (a 19. és 23. sorok közé beszúrva) int i;
módon külön deklaráljuk.
| felszin.c:28:9: warning: implicit declaration of function ‘P’ [-Wimplicit-function-declaration]
28 | P(i) = get_pont(argv[i+1]);
| ^
|
Ez egy félrevezető üzenet a 28. sorban: a gcc szerint a P
egy függvény (mert látszólag meghívjuk), és panaszkodik, hogy nem deklaráltuk.
De mi tudjuk, hogy a P
egy tömb, tehát valójában a hiba az, hogy P(i)
helyett P[i]
-t kellene írni.
| felszin.c:28:16: warning: implicit declaration of function ‘get_pont’ [-Wimplicit-function-declaration]
28 | P(i) = get_pont(argv[i+1]);
| ^~~~~~~~
|
Ugyanaz a hibaüzenet, mint az előbb, de itt, a get_pont
-ra vonatkoztatva jogos: a függvényt korábban kellene deklarálni.
Ezt megtehetjük egy pont_t get_pont(const char *str);
sor beszúrásával a 19. sor elé, vagy a függvénydefiníció (48-51. sor) 19. sor elé mozgatásával.
| felszin.c:29:9: error: called object ‘t’ is not a function or function pointer
29 | t(i) = 0.0;
| ^
felszin.c:21:12: note: declared here
21 | double t[4];
| ^
|
A 29. sorban a t
függvényt próbáljuk meghívni, pedig a t
nem függvény, hanem tömb.
A fentihez hasonlóan t(i)
helyett t[i]
kell.
| felszin.c:31:12: warning: implicit declaration of function ‘terulet’ [-Wimplicit-function-declaration]
31 | t[0] = terulet(P[1], P[2], P[3]);
| ^~~~~~~
|
A 31. sorban használjuk a terulet
függvényt, ami a get_pont
-hoz hasonlóan még nincs deklarálva.
Javítás a fent leírtakhoz hasonlóan.
| felszin.c:31:20: error: ‘P’ undeclared (first use in this function)
31 | t[0] = terulet(P[1], P[2], P[3]);
| ^
|
A gcc szerint nincs deklarálva a P
azonosító.
Ez a hiba is a struktúra le nem zárásából adódik, a 15-17 sorbeli hiányzó ;
beszúrásával megjavul.
| felszin.c:36:9: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
36 | if (t[i] = 0.0)
| ^~
|
A gcc a 36. sorban azt javasolja, hogy ha az if
-ben értéket adunk, azt tegyük külön zárójelbe.
De megvizsgálva a helyzetet, sokkal valószínűbb, hogy nem értéket akartunk adni, hanem egyenlőséget akartunk ellenőrizni.
Tehát a javítás az =
operátor ==
-re cserélése.
| felszin.c:38:13: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
38 | return 1;
| ^~~~~~
|
A gcc arra figyelmeztet, hogy 38. sorban lévő return 1;
utasítás ránézésre a 37. sor utasításával együtt a 36. sorban található if
belsejében van,
de valójában nincs, mivel az if
(a {
hiánya miatt) csak a 37. sorbeli printf
-re vonatkozik.
A hiba oka, hogy lemaradt a {
a 36. sor végéről, ezt pótoljuk.
(A 39. sorban viszont látszik, hogy a lezáró }
ott van.)
| felszin.c:22:12: warning: unused variable ‘felszin’ [-Wunused-variable]
22 | double felszin;
| ^~~~~~~
|
A gcc szerint a 22. sorban deklarált felszin
változó nincs használva.
Ez az előző hiba, a 36. sorban elmaradt {
következménye, mert így a 40. sorban lévő }
-t a függvény kezdő {
-hez párosítja, így ami ez után van (és a felszin
használata ez után van), az szerinte nem tartozik a függvényhez.
Az előző hiba javításával ez is eltűnik.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | felszin.c: At top level:
felszin.c:41:5: error: expected identifier or ‘(’ before ‘for’
41 | for (i = 0; i < 4; ++i) {
| ^~~
felszin.c:41:19: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘<’ token
41 | for (i = 0; i < 4; ++i) {
| ^
felszin.c:41:24: error: expected identifier or ‘(’ before ‘++’ token
41 | for (i = 0; i < 4; ++i) {
| ^~
felszin.c:44:12: error: expected declaration specifiers or ‘...’ before string constant
44 | printf("A test felszíne: A = %.3lf\n", felszin);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
felszin.c:44:45: error: unknown type name ‘felszin’
44 | printf("A test felszíne: A = %.3lf\n", felszin);
| ^~~~~~~
felszin.c:45:5: error: expected identifier or ‘(’ before ‘return’
45 | return 0;
| ^~~~~~
felszin.c:46:1: error: expected identifier or ‘(’ before ‘}’ token
46 | }
| ^
|
A gcc arra panaszkodik, hogy utasításokat talált függvényen kívül.
Ezek is mind javulnak, ha a 36. sor végére beszúrjuk a {
karaktert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | felszin.c:48:1: error: unknown type name ‘pont_t’
48 | pont_t get_pont(const char *str) {
| ^~~~~~
felszin.c: In function ‘get_pont’:
felszin.c:49:5: warning: statement with no effect [-Wunused-value]
49 | pont_t retval = {0.0, 0.0, 0.0};
| ^~~~~~
felszin.c:49:11: error: expected ‘;’ before ‘retval’
49 | pont_t retval = {0.0, 0.0, 0.0};
| ^~~~~~~
| ;
felszin.c:50:34: error: ‘retval’ undeclared (first use in this function)
50 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ^~~~~~
|
Ezek mindegyike a struktúra-definíció körüli hibából fakad, és a 15-17. sori javítással eltűnnek.
| felszin.c: At top level:
felszin.c:53:23: error: expected ‘]’ before ‘P’
53 | double tavolsag[pont_t P, pont_t Q] {
| ^~
| ]
|
Az 53. sorban arra figyelmeztet a gcc, hogy tömb deklarációjában a []
jelek között egyetlen érték szerepelhet, és a P
már a második lenne, tehát kell elé a ]
.
De mi látjuk, hogy a gond valójában az, hogy a függvény definíciójában a ()
zárójelpárt kellene használni a []
helyett.
Javítsuk a hibát.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 | felszin.c:61:16: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:61:26: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:61:36: error: expected declaration specifiers or ‘...’ before ‘pont_t’
61 | double terulet(pont_t A, pont_t B, pont_t C) [
| ^~~~~~
felszin.c:63:5: warning: data definition has no type or storage class
63 | a = tavolsag(B, C);
| ^
felszin.c:63:5: warning: type defaults to ‘int’ in declaration of ‘a’ [-Wimplicit-int]
felszin.c:63:9: warning: implicit declaration of function ‘tavolsag’ [-Wimplicit-function-declaration]
63 | a = tavolsag(B, C);
| ^~~~~~~~
felszin.c:63:18: error: ‘B’ undeclared here (not in a function)
63 | a = tavolsag(B, C);
| ^
felszin.c:63:21: error: ‘C’ undeclared here (not in a function)
63 | a = tavolsag(B, C);
| ^
felszin.c:64:5: warning: data definition has no type or storage class
64 | b = tavolsag(A, C);
| ^
felszin.c:64:5: warning: type defaults to ‘int’ in declaration of ‘b’ [-Wimplicit-int]
felszin.c:64:18: error: ‘A’ undeclared here (not in a function)
64 | b = tavolsag(A, C);
| ^
felszin.c:65:5: warning: data definition has no type or storage class
65 | c = tavolsag(A, B);
| ^
felszin.c:65:5: warning: type defaults to ‘int’ in declaration of ‘c’ [-Wimplicit-int]
felszin.c:66:5: warning: data definition has no type or storage class
66 | s = (a + b + c) / 2.0;
| ^
felszin.c:66:5: warning: type defaults to ‘int’ in declaration of ‘s’ [-Wimplicit-int]
felszin.c:66:9: error: initializer element is not constant
66 | s = (a + b + c) / 2.0;
| ^
felszin.c:67:5: error: expected identifier or ‘(’ before ‘return’
67 | return sqrt(s * (s - a) * (s - b) * (s - c));
| ^~~~~~
felszin.c:68:1: error: expected identifier or ‘(’ before ‘]’ token
68 | ]
| ^
|
Amikor ennyi hiba van pár sorban, ott már nagyon valószínű, hogy a korábbi hibák miatt a gcc teljesen elvesztette a fonalat.
Itt az alap hiba a struktúra-definíció utáni ;
hiány, ami miatt a pont_t
-t nem tudja hová tenni a fordító.
Illetve a tavolsag
függvény definíciójának elrontása miatt (előző hiba az 53. sorban) ezt az azonosítót sem ismeri fel korábban deklarált függvényként.
A korábbi hibák javításával ezek nagyrészt el fognak tűnni.
| felszin.c: In function ‘Main’:
felszin.c:40:5: warning: control reaches end of non-void function [-Wreturn-type]
40 | }
| ^
|
A gcc szerint a Main
függvény úgy érhet véget a 40. sorban, hogy nem hajt végre return
utasítást.
Ez ugye megint a 36. sorban hiányzó {
miatt van, és annak beszúrásával javul.
| felszin.c: In function ‘get_pont’:
felszin.c:51:1: warning: control reaches end of non-void function [-Wreturn-type]
51 | }
| ^
|
Az 51. sorban egy hasonló hiba viszont jogos: a get_pont
függvényben nincs return
, pedig kellene.
Mondjuk egy return retval;
, a függvény végére.
A gcc fordító kimenete a javított verzión
Mint látszik, maradtak még hibák, amiket a korábbiak miatt a gcc "nem látott".
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | temp.c: In function ‘Main’:
temp.c:46:17: error: invalid operands to binary + (have ‘double’ and ‘double *’)
46 | felszin += t{i};
| ^~ ~
| |
| double *
temp.c:46:21: error: expected ‘;’ before ‘{’ token
46 | felszin += t{i};
| ^
| ;
temp.c: In function ‘get_pont’:
temp.c:54:21: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 3 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
temp.c:54:25: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 4 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
temp.c:54:29: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 5 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
temp.c: In function ‘tavolsag’:
temp.c:63:12: warning: implicit declaration of function ‘sqrt’ [-Wimplicit-function-declaration]
63 | return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
| ^~~~
temp.c:63:12: warning: incompatible implicit declaration of built-in function ‘sqrt’
temp.c:10:1: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
9 | #include <stdio.h>
+++ |+#include <math.h>
10 |
temp.c: At top level:
temp.c:67:5: error: expected expression before ‘double’
67 | double a, b, c, s;
| ^~~~~~
|
Megoldás, 2. lépés
A javítások miatt a sorszámok itt eltérhetnek a fentiektől.
| felszin.c: In function ‘Main’:
felszin.c:46:17: error: invalid operands to binary + (have ‘double’ and ‘double *’)
46 | felszin += t{i};
| ^~ ~
| |
| double *
felszin.c:46:21: error: expected ‘;’ before ‘{’ token
46 | felszin += t{i};
| ^
| ;
|
Ebben a sorban több hibát is jelez a fordító.
Mindkettő arra vezethető vissza, hogy a ` tömböt
[]helyett
{}`-vel próbáljuk meg indexelni.
Javítsuk!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | felszin.c: In function ‘get_pont’:
felszin.c:54:21: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 3 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
felszin.c:54:25: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 4 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
felszin.c:54:29: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 5 has type ‘double’ [-Wformat=]
54 | sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
| ~~^ ~~~~~~~~
| | |
| double * double
|
A sor mindhárom hibájának ugyanaz az oka: a scanf
nem double
típusú változó értéket, hanem double*
típusú változó címet vár.
Emlékezzünk: ha scanf
, akkor a változó neve elé kell egy &
.
Három helyen is.
| felszin.c: In function ‘tavolsag’:
felszin.c:63:12: warning: implicit declaration of function ‘sqrt’ [-Wimplicit-function-declaration]
63 | return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
| ^~~~
felszin.c:63:12: warning: incompatible implicit declaration of built-in function ‘sqrt’
felszin.c:10:1: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
9 | #include <stdio.h>
+++ |+#include <math.h>
10 |
|
Ez szép, itt a gcc pontosan megmondja, mit kellene csinálni.
Tegyük meg!
| felszin.c: At top level:
felszin.c:67:5: error: expected expression before ‘double’
67 | double a, b, c, s;
| ^~~~~~
|
Az At top level
mutatja, hogy a gcc szerint nem függvényben vagyunk.
Azért gondolja, mert {}
helyett []
-t használtunk a függvénytörzs "bekeretezésére".
Javítsuk!
A gcc fordító kimenete az újabb javítás után
Pedig már azt hittük, minden szép és jó...
| /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
/usr/bin/ld: /tmp/ccfBwX69.o: in function `tavolsag':
temp.c:(.text+0x3cb): undefined reference to `sqrt'
/usr/bin/ld: /tmp/ccfBwX69.o: in function `terulet':
temp.c:(.text+0x499): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
|
Megoldás, 3. lépés
| /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
|
Ez a hiba azt jelzi, hogy nincs meg a main
függvény, így a linker nem tud programot összeállítani.
Van ugyan egy Main
függvényünk, de a C érzékeny a kis- és nagybetűkre, és ugye Nemecsek Ernő óta tudjuk, hogy a Main
az nem main
.
Szóval, a sorráskódban javítsuk ki az M
-et m
-re.
| /usr/bin/ld: /tmp/ccfBwX69.o: in function `tavolsag':
temp.c:(.text+0x3cb): undefined reference to `sqrt'
/usr/bin/ld: /tmp/ccfBwX69.o: in function `terulet':
temp.c:(.text+0x499): undefined reference to `sqrt'
|
Hasonló hiba, csak ezúttal az sqrt
függvény hiányzik (amit a tavolsag
és terulet
függvényeink használnak).
Ez viszont már nem a forráskódban javítandó.
Egyszerűen adjuk meg a gcc-nek a -lm
kapcsolót, hogy ott keresse az sqrt
függvényt ahol az van: a matematikai függvénykönyvtárban.
| collect2: error: ld returned 1 exit status
|
Ebből a sorból látszik, hogy ezek már nem fordítási, hanem szerkesztési (linker) hibák.
Ami persze nem jelenti azt, hogy nem a forráskódban van a probléma.
Megoldás egyben (videó)
Ez alapján javítsuk ki magunktól a következő feladat szintaktikai hibáit!
Feladat (f0264)
Feladat:
A delta.c
program feladata lenne óra:perc:másodperc.milisec
alakban megadott
egymást követő időpontok közötti eltéréseket számolni. A program algoritmusa
alapvetően helyes, de a megvalósításában, kódolásában több hiba van. Javítsd
ki ezeket a fordító által jelzett hibák és figyelmeztetések alapján!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai
*/
#include <stdio.h>
#include <stdlib.h>
struct ido (
int hrs;
int min;
int sec;
int ms;
)
main() {
struct ido prev, curr;
beolvas(prev);
kiir(' ', prev);
while(beolvas(&curr)) {
prev = kulonbseg(prev, curr);
kiir('+', prev);
prev = curr;
}
}
bool beolvas{struct ido *t} [
return (scanf("%d:%d:%d.%d", t->hrs, t->min, t->sec, t->ms) = 4);
]
void kiir[char prefix, struct ido t] (
if (t.hrs > 0) {
printf("%c%2d:%02d:%02d.%03d\n", prefix, t.hrs, t.min, t.sec, t.ms);
return 0;
}
if (t.min > 0) {
printf("%c%5d:%02d.%03d\n", prefix, t.min, t.sec, t.ms);
return 0;
}
printf("%c%8d.%03d\n", prefix, t.sec, t.ms);
)
struct ido kulonbseg(struct ido start, struct ido stop) {
start.ms = {[(stop.hrs-start.hrs)*60+(stop.min-start.min)]*60+(stop.sec-start.sec)}*1000+(stop.ms-start.ms);
start.hrs = start.ms / 3600000;
start.ms %= 3600000;
start.min = start.ms / 60000;
start.ms %= 60000;
start.sec = start.ms / 1000;
start.ms %= 1000;
return start;
}
|
felszin.c
A gcc fordító kimenete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | delta.c:13:5: error: expected identifier or ‘(’ before ‘int’
13 | int hrs;
| ^~~
delta.c:30:1: error: unknown type name ‘bool’
30 | bool beolvas{struct ido *t} [
| ^~~~
delta.c:30:13: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
30 | bool beolvas{struct ido *t} [
| ^
delta.c:30:29: error: expected identifier or ‘(’ before ‘[’ token
30 | bool beolvas{struct ido *t} [
| ^
delta.c:32:1: error: expected identifier or ‘(’ before ‘]’ token
32 | ]
| ^
delta.c:39:5: error: expected identifier or ‘(’ before ‘if’
39 | if (t.min > 0) {
| ^~
delta.c:43:12: error: expected declaration specifiers or ‘...’ before string constant
43 | printf("%c%8d.%03d\n", prefix, t.sec, t.ms);
| ^~~~~~~~~~~~~~
delta.c:43:28: error: unknown type name ‘prefix’
43 | printf("%c%8d.%03d\n", prefix, t.sec, t.ms);
| ^~~~~~
delta.c:43:36: error: unknown type name ‘t’
43 | printf("%c%8d.%03d\n", prefix, t.sec, t.ms);
| ^
delta.c:43:43: error: unknown type name ‘t’
43 | printf("%c%8d.%03d\n", prefix, t.sec, t.ms);
| ^
delta.c:44:1: error: expected identifier or ‘(’ before ‘)’ token
44 | )
| ^
|
Megoldás (videó)
Egy kis programozás fun otthonra
Írjunk egy bombakereső játékot!
A játékot a számítógép ellen játszuk.
A számítógép induláskor feltölt egy \(10 \times 10\)-es tömböt random \(0\)-kal és \(1\)-esekkel, úgy, hogy pl. 10 darab \(1\)-es legyen a táblán, a többi mind \(0\).
Az \(1\)-esek szimbolizálják a bombákat.
A játék kezdésekor a játékos úgyszint kitölt egy ugyanekkora táblát a saját elképzelése szerint, úgy, hogy megadja, hogy melyik pozícióra kerüljenek a bombái: \([i,j]\).
Miután a random generátor feltöltötte az ellenfél tábláját, illetve a játékos is feltöltötte a sajátját, megkezdődhet a játék.
Ezután felváltva találgathat a két fél, hogy szerintük hol lehet bomba az ellenfél tábláján. A számítógép tippelhet véletlen módon is, de eljátszhatunk azzal is, hogy minél jobb ellenfelet írjunk a játékosunknak.
Az nyer, aki előbb megtalálja az ellenfél összes bombáját.
A játék végén írjuk ki, hogy ki nyerte a játszmát.
Egy kis segítség
Nyugodtan töltsük fel mindkét táblát kezdetben \(0\)-kal, majd ahova érkezik \(1\)-es, ott csak írjuk felül.
A számítógép táblájának feltöltésére egy lehetséges megoldás, hogy két számot generáltatunk: az egyik lesz az oszlop indexe, a másik pedig a sornak az indexe.
Így jön ki pl., hogy hova kerüljön \(1\)-es.
Bevezethetünk két segéd változót, amely azt figyeli, hogy ki hány bombát talált eddig.
Ha valamelyik változó értéke eléri a 10-et, meg van az összes bomba, a játék véget ér.
Ügyeljünk rá, hogy ...
Kétszer ugyanoda tippelve, ne szerezzen egyik fél sem mégegyszer pontot.
Legyegyszerűbb, ha egy találat esetén egyből felülírjuk \(0\)-val az adott pozíciót az adott tömbben.
Ellenőrizzük, a játékos által megadott pozíciókra, hogy a \(10 \times 10\)-es tömbön belül vannak-e.
A kódot kommentezzük is úgy, hogy ha más valaki olvassa az is megértse!
(Melyik változó / elágazás / ciklus / függvény /.. mire való.)
A feladat megoldását/próbálgatását erősen ajánlom mindenkinek.
Sok mindenre rá lehet jönni ilyenkor.
Próbáljunk meg a körülményekhez mérten felhasználóbarát programot készíteni!
Feladatok
Feladat (f0183)
Problémafelvetés:
Írj egy programot ami három háromdimenziós koordináta-hármasból kiszámítja
egy térbeli háromszög kerületét és területét!
Algoritmustervezés/Megvalósítás:
A megfelelő helyeken használj struct
adattípusokat.
Feladat (f0184)
Problémafelvetés:
Írj egy programot ami négy háromdimenziós koordináta-hármasból kiszámítja
egy pontok által határolt térrész (egyfajta szabálytalan "tetraéder",
oldalaikkal és csúcsaikkal érintkező négy háromszög által határolt test,
melynek csúcsai a megadott pontok) felszínét.
Algoritmustervezés/Megvalósítás:
A megfelelő helyeken használj struct
adattípusokat.
Lehetséges megoldás (m0184.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai
*/
#include <stdio.h>
#include <math.h>
struct pont {
double x;
double y;
double z;
};
typedef struct pont pont_t;
pont_t get_pont();
double tavolsag(pont_t P, pont_t Q);
double terulet(pont_t A, pont_t B, pont_t C);
int main(int argc, char *argv[]) {
pont_t P[4];
double t[4];
double felszin = 0.0;
for (int i = 0; i < 4; ++i) {
P[i] = get_pont();
t[i] = 0.0;
}
t[0] = terulet(P[1], P[2], P[3]);
t[1] = terulet(P[0], P[2], P[3]);
t[2] = terulet(P[0], P[1], P[3]);
t[3] = terulet(P[0], P[1], P[2]);
for (int i = 0; i < 4; ++i) {
if (t[i] == 0.0) {
printf("A megadott pontok egy síkba esnek.\n");
return 1;
}
}
for (int i = 0; i < 4; ++i) {
felszin += t[i];
}
printf("A test felszíne: A = %.3lf\n", felszin);
return 0;
}
pont_t get_pont() {
pont_t retval = {0.0, 0.0, 0.0};
scanf("%*[ \t\n]"); // Ha van whitespace karakter, azt nyeljük le
scanf("(%lf,%lf,%lf)", &retval.x, &retval.y, &retval.z);
return retval;
}
double tavolsag(pont_t P, pont_t Q) {
pont_t d;
d.x = P.x - Q.x;
d.y = P.y - Q.y;
d.z = P.z - Q.z;
return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
}
double terulet(pont_t A, pont_t B, pont_t C) {
double a, b, c, s;
a = tavolsag(B, C);
b = tavolsag(A, C);
c = tavolsag(A, B);
s = (a + b + c) / 2.0;
return sqrt(s * (s - a) * (s - b) * (s - c));
}
|
Feladat (f0185)
Problémafelvetés:
Írj egy programot ami komplex számokkal képes sorban alapműveleteket
elvégezni, zárójelezés és precedencia figyelembevétele nélkül. Vagyis
például a 3+2*5
eredménye nem 3+(2*5)=13
, hanem (3+2)*5=25
.
Specifikáció:
A program inputja több sorból áll. A páratlan sorokban egy-egy komplex szám,
a páros sorokban egy-egy műveleti jel szerepel, a sorvégeken kívül egyéb
whitespace karakterek nélkül. Egy komplex szám A+Bi vagy A-Bi alakban lesz
megadva, ahol A egy előjellel vagy anélkül megadott valós szám, B pedig egy
előjel nélkül megadott valós szám. A szám után közvetlenül egy 'i
' karakter
áll. A műveleti jel '+
', '-
', '*
', '/
' vagy '=
' lehet. Az '=
' a bemenet
végét jelenti. A program kimenete egy komplex szám, a műveletsorozat
eredménye, a fent leírt alakban. A műveletsorozatot fentről lefelé hajtjuk
végre, és minden művelet azonos prioritásúnak számít.
Algoritmustervezés/Megvalósítás:
Használjunk struct
adattípust a komplex számok tárolására, illetve külön
függvényeket az egyes műveletekre, egy komplex szám beolvasására illetve
kiírására is.
Feladat (f0187)
Feladat:
Fordítsd le és futtasd a rekordok.c
programot. Figyeld meg és magyarázd el,
mi a különbség a struct
és a union
között! Most alakítsd át a programot úgy,
hogy előbb hajtsd végre az összes értékadást, és csak utána a kiíratásokat.
Most mit tapasztalsz? Miért? Minden egyes kiíratáskor írasd ki az éppen
kiírt mező kezdőcímét is. Mit tapasztalsz?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | /*
* Szegedi Tudományegyetem
* Informatikai Tanszékcsoport
* Szoftverfejlesztés Tanszék
*
* Programozás Alapjai
*/
#include <stdio.h>
typedef struct {int i; double d; char c; float f;} st_t;
typedef union {int i; double d; char c; float f;} un_t;
int main() {
st_t s;
un_t u;
s.i = u.i = 12345;
printf("s.i: %d u.i: %d\n", s.i, u.i);
s.d = u.d = 3.141593;
printf("s.d: %lf u.d: %lf\n", s.d, u.d);
s.c = u.c = 'A';
printf("s.c: %c u.c: %c\n", s.c, u.c);
s.f = u.f = 2.718281;
printf("s.f: %f u.f: %f\n", s.f, u.f);
return 0;
}
|
rekordok.c
Feladat (f0226)
Problémafelvetés:
Írj egy programot, ami kiszámolja egy konvex sokszög súlypontját.
Specifikáció:
A program inputja egy n egész szám, majd n darab valós számpár (x,y)
alakban. Minden számpár a konvex sokszög egy-egy pontjának koordinátája,
valamely körüljárási irányszerinti sorrendben.
A program outputja a sokszög súlypontjának koordináta-párja. Ezt az egy és
kétcsúcsú elfajuló síkidomokra is ki kell tudni számolni.
Algoritmustervezés:
A sokszög konvexségét nem kell ellenőrízni. Egy sokszög súlypontját úgy
kaphatjuk meg, hogy nem átfedő háromszögekre bontjuk, és kiszámoljuk ezen
háromszögek súlypontjainak a háromszögek területével (a területük sokszögön
belüli arányával) súlyozott átlagát. Azaz ha például egy 3 egység területű
négyszöget egy 1 és egy 2 egység területű háromszögre bontunk fel, akkor az
első háromszög súlypontját 1/3, a másodikét 2/3 súllyal számítjuk bele az
átlagba.
További gyakorló feladatok
Feladat (f0093)
Problémafelvetés:
Írj egy programot, ami bekéri egy világos és egy sötét bábu rangját és
sakktáblán elfoglalt pozícióját, majd kiírja, hogy a világos bábu üti,
feltételesen ütheti, vagy biztosan nem üti a másik bábut, esetleg az állás
(a helyes koordináták ellenére) nem lehetséges. Helytelen koordinátákra (nem
sakktábla mező) a program ne írjon ki semmit, helyes koordinátákra pedig az
"Üti.
", "Nem üti.
", "Feltételekkel ütheti.
" és "Nem lehetséges.
" szöveg
valamelyikét.
Feladat (f0192)
Problémafelvetés:
Írj egy programot, ami bekéri egy torta piskótájának sugarát és magasságát,
majd kiszámolja a torta 1cm vastag bevonásához szükséges krém térfogatát
5%-os ráhagyással dolgozva. (A torta alját nem kell bekrémezni, csak az
oldalát és a tetejét.)
Algoritmustervezés/Megvalósítás:
A főprogram csak az input/output műveleteket végezze, a számolást külön
függvény(ek)ben oldd meg. Az adatok tárolására használj összetett
adatszerkezetet, ha van értelme.
Feladat (f0194)
Problémafelvetés:
Írj egy programot, ami megmondja, hogy egy hallgató teljesítette-e a félévet
programozás alapjai gyakorlatból.
Algoritmustervezés/Megvalósítás:
A főprogram csak az input/output műveleteket végezze, a számolást külön
függvény(ek)ben oldd meg. Készíts egy adatszerkezetet, amiben a hallgató
nevét, pontjait tároljuk. A program tároljon külön minden részpontszámot és
a hiányzásokat is.
Feladat (f0206)
Problémafelvetés:
Adott két körszerű test a kétdimenziós síkon. A testek helyzetét a
középpontjaikkal azonosítjuk. Kezdetben a felhasználó mindkét testhez
megadja:
- a középpontját \(x,y\) koordinátákkal,
- sugarát,
- kezdősebességét és annak irányát, valamint
- a test tömegét.
Megad továbbá egy \(\Delta t\) és egy \(T\) időintervallumot. A feladat a két test
kétdimenziós fizikai mozgásának szimulálása a \(0..T\) időintervallumban \(\Delta t\)
időbeosztással. Ez azt jelenti, hogy a kezdő időpontban kiszámoljuk a
testekre ható erőket, majd a test mozgását a következő \(\Delta t\) időintervallumban
úgy közelítjük, mintha a testre ebben az időintervallumban nem hatna egyéb
erő. Ezután újra kiszámítjuk az erőket, majd újra közelítjük a mozgást, stb.
A mozgás szimulálása a \(T\) időpontig vagy a két test "ütközéséig" tart. A
pontosság kedvéért a két test helyzetét (\(x,y\) koordinátáit) úgy írassuk ki,
mintha az origo, azaz a koordinátarendszer középpontja a két test közös
tömegközéppontja lenne, azaz a kiszámított koordinátaértékeket ezek szerint
korrigáljuk minden lépésben.
Algoritmustervezés/Megvalósítás:
A főprogram csak az input/output műveleteket végezze, a számolást külön
függvény(ek)ben oldd meg. Az adatok tárolására használj összetett
adatszerkezetet, ha van értelme.
Kapcsolódó linkek
Utolsó frissítés:
2022-11-25 15:25:14