Programozás alapjai gyakorlat 2014-2015/1

9. gyakorlat


    Struktúrák

C nyelven a struktúra (struct) típus több tetszőleges típusú objektum együttese (kivéve a void és a függvény típust). Ezek az objektumok önálló, a struktúrán belül érvényes nevekkel rendelkeznek.

A struktúra szerkezetét meghatározó deklaráció általános formája:

struct struktúra_azonosító {
	típus1 tag1;
	típus2 tag2;
	...
	típusN tagN;
};

A fenti típussal változót az alábbi módon készíthetünk:

struct struktúra_azonosító struktúra_változó;

Példa: Könyvtárkezelő program készítése során jól alkalmazható az alábbi adatstruktúra:

struct book {
	char szerzo[20];
	char cim[40];
	int ev;
	int ar;
};

Változók létrehozása:

struct book macska, gyerek, cprog;

Elég gyakran alkalmazott megoldás a typedef kulcsszóra épül:

typedef struct book {
	char szerzo[20];
	char cim[40];
	int ev;
	int ar;
} BOOK;

Változók létrehozása:

BOOK macska, gyerek, cprog;

Egy komolyabb példa:

F: Hozz létre típust egy háromdimenziós térbeli pozíció tárolására. Ezt
   felhasználva hozz létre egy típust, ami részecskék helyzetét, tömegét,
   nevét és töltését (pozitív/negatív/semleges) tárolja. Készíts egy
   függvényt, ami két részecskéről eldönti, hogy melyik nehezebb, és egy
   másikat, ami megmondja, hogy elektromosan vonzzák vagy taszítják egymást,
   esetleg nem hatnak egymásra. Inicializálj két részecskét, és használd a
   függvényeket.

==============================================================================

#include <stdio.h>

typedef struct {
	double x, y, z;
} pozicio;

typedef char nevtipus[30];

typedef enum {negativ = -1, semleges, pozitiv} toltestipus;

typedef struct {
	pozicio helyzet;
	double tomeg;
	nevtipus nev;
	toltestipus toltes;
} reszecske;

int tomeghasonlitas(reszecske a, reszecske b)
{
	if(a.tomeg < b.tomeg) {
		return -1;
	}
	if(a.tomeg > b.tomeg) {
		return 1;
	}
	return 0;
}

int vonzas(reszecske a, reszecske b)
{
	if(a.toltes==semleges || b.toltes==semleges) {
		return 0;
	}
	return (a.toltes==b.toltes)?1:-1;
}

int main()
{
	reszecske p={{0.0, 0.0, 0.0}, 1.0, "proton", pozitiv};
	reszecske e={{1.0, 1.0, 1.0}, 0.001, "elektron", negativ};
	printf("tomeg: %d\nvonzas: %d\n", tomeghasonlitas(p, e), vonzas(p, e));
	return 0;
}

F: Adott a síkon 3 pont, mi az általuk meghatározott háromszög területe?

==============================================================================

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

struct pont {
	float x;
	float y;
};

float tav(struct pont P, struct pont Q) {
	return sqrtf((P.x-Q.x)*(P.x-Q.x) + (P.y-Q.y)*(P.y-Q.y));
}

int main() {
	struct pont A, B, C;
	float a,b,c,s;
	scanf("%f %f", &A.x, &A.y);
	scanf("%f %f", &B.x, &B.y);
	scanf("%f %f", &C.x, &C.y);
	a=tav(B, C);
	b=tav(A, C);
	c=tav(A, B);
	s=(a+b+c)/2;
	printf("Terulet: %f\n", sqrtf(s*(s-a)*(s-b)*(s-c)));
}

F: Készítsünk komplex számok tárolására alkalmas adatszerkezetet (egész
   komponensekkel). Készítsünk továbbá olyan függvényeket, melyek feladata:
   - kiír egy komplex számot az stdout-ra,
   - összead két komplex számot, és visszaadja az eredményt
   - összeszoroz két komplex számot, és visszaadja az eredményt

==============================================================================
== BEGIN komplex.c ===========================================================

#include <stdio.h>

typedef struct komplex {
	int real;
	int imag;
} komplex;

komplex add(komplex k1, komplex k2)
{
    komplex e;
    e.real = k1.real+k2.real;
    e.imag = k1.imag+k2.imag;
    return e;
}

komplex mul(komplex k1, komplex k2)
{
    komplex e;
    e.real = k1.real*k2.real-k1.imag*k2.imag;
    e.imag = k1.imag*k2.real+k1.real*k2.imag;
    return e;
}

void printk(komplex k)
{
    printf("(%d%+di)\n", k.real, k.imag);
}

int main()
{
	komplex x1,x2,e;
	x1.real = 10;
	x1.imag = 2;
	x2.real = 20;
	x2.imag = -3;
	printk(x1);
	printk(x2);
	e = add(x1,x2);
	printk(e);
	printk(mul(x1,x2));
	return 0;
}

F: Láncolt lista. Olvassunk be egész számokat egy láncolt listába egy adott
   végjelig, majd írassuk ki őket.

==============================================================================
== BEGIN linkedlist.c ========================================================

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

#define VEGJEL 0

struct cella {
	int ertek;
	struct cella *kov;
};

int main()
{
	struct cella *elso = NULL;
	struct cella *p;
	int i;
	scanf("%d", &i);
	while(i!=VEGJEL) {
		p        = (struct cella*)malloc(sizeof(struct cella));
		p->ertek = i;
		p->kov   = elso;
		elso     = p;
		scanf("%d", &i);
	}
	for(p=elso; p!=NULL; p=p->kov) {
		printf("%d\n", p->ertek);
	}
	while(elso!=NULL) {
		p   =elso;
		elso=p->kov;
		free(p);
	}
	return 0;
}


    Únió

Ismerkedjünk meg a union típussal. Igazából nincs sok dolgunk, mivel a struct típussal kapcsolatban ismertetett formai megoldások a union típusra is alkalmazhatóak.

Egyetlen és egyben lényegi különbség az adattagok elhelyezkedése között van. Míg a struktúra adattagjai a memóriában egymás után helyezkednek el, addig az únió adattagjai közös címen kezdődnek (átlapoltak).

short a;
int b;
long long c;

	            Memóriafoglalás:
	 STRUCT                           UNION
	 
	 _______    _
	|       |    |
	|       |    | long long c
	|       |    |                   _______                         _
	|_______|   _|                  |       |                         |
	|       |    | int b            |_______|               _         | long long c
	|_______|   _|                  |_______|   _            | int b  |
	|_______|   _| short a          |_______|   _| short a  _|       _|
	 

A union szerkezetét meghatározó deklaráció általános formája:

union union_azonosító {
	típus1 tag1;
	típus2 tag2;
	...
	típusN tagN;
};

A fenti típussal változót az alábbi módon készíthetünk:

union union_azonosító union_változó;

F: Mi a különbség a struct és a union között? Deklarálj egy struct és egy
   union típust ugyanolyan mezőkkel. Adj értéket a mezőknek, majd írasd ki
   őket!

==============================================================================

#include <stdio.h>

typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;

int main()
{
	st s;
	un 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;
}

Így nem látszik semmi. De mi van, ha egyszerre íratjuk ki a mezők értékeit?

==============================================================================

#include <stdio.h>

typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;

int main()
{
	st s;
	un u;
	s.i = u.i = 12345;
	s.d = u.d = 3.141593;
	s.c = u.c = 'A';
	s.f = u.f = 2.718281;
	printf("s.i: %d  u.i: %d\n", s.i, u.i);
	printf("s.d: %lf  u.d: %lf\n", s.d, u.d);
	printf("s.c: %c  u.c: %c\n", s.c, u.c);
	printf("s.f: %f  u.f: %f\n", s.f, u.f);
	return 0;
}

F: Írasd ki a mezők kezdőcímét!

==============================================================================
== BEGIN union.c =============================================================

#include <stdio.h>

typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;

int main()
{
	st s;
	un u;
	printf("s.i: %p  u.i: %p\n", &s.i, &u.i);
	printf("s.d: %p  u.d: %p\n", &s.d, &u.d);
	printf("s.c: %p  u.c: %p\n", &s.c, &u.c);
	printf("s.f: %p  u.f: %p\n", &s.f, &u.f);
	return 0;
}


Egy kis gyakorlás

Képzeljünk el egy lelátót (legyen ez most nézőtér, pl.: moziban), amely két részre van osztva, középen egy sávval. Mindkét oldal 10x10 helyet tartalmaz. Kirajzolva a képernyőre a teljes lelátót, 1-essel vannak jelölve azok a helyek, amelyek foglaltak, és 0-val azok, amelyek szabadok. A lelátót egy random generátorral töltsük fel [0,1].

1. Rész: Egy barátommal ketten mennénk moziba. Mindketten szeretnénk a belső sávnál ülni, mert középtájról a legjobb a látvány. Úgy szeretnénk helyet fogalalni, hogy ő a nézőtér egyik felén ül a középső sáv mellett, én pedig a másik oldalon, hogy melyik sorban az mindegy. Hány olyan üreshely kombináció van és hol, ahol tudnánk a követelésinknek megfelelően helyet foglalni?

2. Rész: Úgy döntünk, hogy inkább mégse szeretnék külön oldalon ülni, illetve mindenképp egymás mellé szeretnénk helyet foglalni. Rajzoljuk ki a képernyőre a lelátót olyan formában, hogy 0-val legyen jelölve, ahol van egymás mellett két szabad hely, tehát ide foglalhatunk, és szerepeljen 1-es ott, ahova az előző kritériumok alapján ne foglaljunk jegyet.

Egy lehetséges futási eredmény:

1 0 0 1 0 1 1 1 1 0     1 0 1 0 0 1 1 0 1 1
1 1 1 1 0 1 1 1 1 0     0 0 1 0 1 0 1 1 1 0
0 1 1 0 1 1 0 0 1 1     0 1 1 1 1 1 0 0 0 0
0 1 0 0 0 0 0 0 0 0     0 1 0 0 0 1 0 1 1 1
0 0 0 1 0 1 1 1 0 1     1 0 1 1 0 0 1 1 0 0
1 1 0 1 1 1 1 0 1 0     1 0 1 0 1 0 0 0 0 0
0 1 1 0 1 1 1 0 1 1     0 1 0 1 0 0 0 1 1 0
0 1 1 0 0 0 0 0 0 0     0 1 0 1 0 1 0 0 0 1
1 1 1 1 1 1 1 1 1 0     1 0 0 0 1 1 1 1 0 1
0 0 1 1 0 0 0 1 1 1     0 0 0 0 0 0 1 0 0 1
Szabad a 2. sor 10. oszlop es a 2. sor 1. oszlop
Szabad a 4. sor 10. oszlop es a 4. sor 1. oszlop
Szabad a 8. sor 10. oszlop es a 8. sor 1. oszlop


1 0 0 1 1 1 1 1 1 1     1 1 1 0 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1     0 0 1 1 1 1 1 1 1 1
1 1 1 1 1 1 0 0 1 1     1 1 1 1 1 1 0 0 0 0
1 1 0 0 0 0 0 0 0 0     1 1 0 0 0 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1     1 1 1 1 0 0 1 1 0 0
1 1 1 1 1 1 1 1 1 1     1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1     1 1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 0 0 0 0     1 1 1 1 1 1 0 0 0 1
1 1 1 1 1 1 1 1 1 1     1 0 0 0 1 1 1 1 1 1
0 0 1 1 0 0 0 1 1 1     0 0 0 0 0 0 1 0 0 1

Egy lehetséges megoldás letöltése .



Plusz pontos házi

Megvalósítandó játék: BLACK JACK (21-ezés)

Kiírás: Egy játékos játszik a számítógép ellen. A játékot francia kártyán játszák, tehát a bejövő lapok értéke 1..11 lehet. Kezdetben mindkét játékosnak 0 lapja van. A két játékos ezután felváltva kérhet lapot. A játékostól kérjük be, hogy szeretne-e még lapot, a számítógépnek pedig legyen beállítva egy felső korlát, hogy milyen lapépérték összegre húzzon még rá. Figyeljünk rá oda, hogy attól, hogy esetleg a játékos már nem kér több lapot, attól még a számítógép kapjon, ha nem érte még el a felső korlátot. Miután mindkét játékos jelezte, hogy már nem kér több lapot, hasonlítsuk össze a lapértékek összegét, majd a Black Jack szabályai alapján hirdessünk nyertest.

Egy lehetséges futási eredmény:

<<< BLACK JACK >>>

Kersz-e lapot (1 - igen, 0 - nem)? 1
Lapjaid osszege eddig: 9

Kersz-e lapot (1 - igen, 0 - nem)? 1
Lapjaid osszege eddig: 12

Kersz-e lapot (1 - igen, 0 - nem)? 1
Lapjaid osszege eddig: 21

Kersz-e lapot (1 - igen, 0 - nem)? 0

Te pontszamod: 21
Ellenfel pontszama: 22

Nyertel!

A te lapjaid rendre:
9 3 9

Az ellenfel lapjai rendre:
3 7 5 7

Megoldások beküldésének határideje: 2014.11.02., vasárnap éjfél.

Egy lehetséges megoldás letöltése .




Házi feladat

A házi feladatot megoldani nem kötelező és bemutatni sem kell, viszont a következő gyakorlaton visszakérhető (kikérdezés, táblához hívás, stb. formájában)! Ha a hallgató megoldása ötletes, szép kivitelezésű, plusz pont adható. Amennyiben viszont nem tudja megoldani gyakorlaton a házi feladatban szereplő példákat vagy nem tud válaszolni az azzal kapcsolatban feltett kérdésekre, mínusz pont adható. Plusz és mínusz pontból is egyaránt maximum 10 pontot gyűjthet össze egy-egy hallgató.

Házi feladat 01-hazi.txt , 02-hazi.txt .




    Jövő héten 6. miniZH (2014.11.03.)

Téma:

  3. - 7. gyakorlat anyaga.

  Gyakorlásra:

    A honlapomon a 3. - 7. gyakorlathoz tartozó anyag, magyarázatokkal, példákkal.

    A gyakorlatok végén lévő házi feladat és gyakorló feladatok megoldása.

    A honlapom mellet további feladatok találhatóak a PUB-ban. (/n/pub/ProgramozasAlapjai/Gyakorlat/ - erős átfedés van az "itt" és "ott" található feladatok között).

Egyéb infó:

  A gyakorlat 8:10-kor kezdődik és a ZH-t 8:15-kor kezdhetitek írni. Előreláthatóan 75 percetek lesz a feladat megoldására és beadására (tehát 9:30-ig). A feladatot a bíró rendszeren keresztül fogjátok megkapni és beadni is, és az értékelést is a bíró fogja csinálni ott helyben. Tehát egyből látni fogjátok a pontszámokat amiket a bíró adott. Aki késik, az is csak a fenti időintervallum alatt írhatja a ZH-t (a bíró rendszer nyit, majd automatikusan zár is). Hiányozni csak igazolással lehet, de a ZH akkor sem pótolható!


     Vissza a lap tetejére.