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;
Egyszerűbb példa egy személy megvalósítására:
// !
#include <stdio.h>
// ember struktúra
struct ember {
char nev[20];
int igszam;
int kor;
};
// kiíratás
void szemelykiiras(struct ember szemely){
printf(" Nev: %s\n", szemely.nev);
printf("Ig.szam: %d\n", szemely.igszam);
printf(" Kor: %d\n", szemely.kor);
}
int main (){
// személy létrehozása
struct ember BelaVagyok;
// szémélyhez tartozó attribútumok feltöltése
scanf("%s",&BelaVagyok.nev);
scanf("%d",&BelaVagyok.igszam);
scanf("%d",&BelaVagyok.kor);
// személy adatainak kiírása fgv segítségével
szemelykiiras(BelaVagyok);
return 0;
}
Ugyanez typedef-el:
// !
#include <stdio.h>
// ember struktúra
typedef struct {
char nev[20];
int igszam;
int kor;
} ember;
// kiíratás
void szemelykiiras(ember szemely){
printf(" Nev: %s\n", szemely.nev);
printf("Ig.szam: %d\n", szemely.igszam);
printf(" Kor: %d\n", szemely.kor);
}
int main (){
// személy létrehozása
ember BelaVagyok;
// szémélyhez tartozó attribútumok feltöltése
scanf("%s",&BelaVagyok.nev);
scanf("%d",&BelaVagyok.igszam);
scanf("%d",&BelaVagyok.kor);
// személy adatainak kiírása fgv segítségével
szemelykiiras(BelaVagyok);
return 0;
}
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;
}
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;
}
Új dinamikus változó létesítése
p=malloc(sizeof(E));
A malloc(S) függvény lefoglal egy S méretű memóriaterületet a program számára. A sizeof(E) megadja, hogy egy E típusú változó mekkora helyet igényel a memóriában. A malloc(sizeof(E)) hatására tehát létrejön egy új E típusú érték tárolására (is) alkalmas változó, és ez a változó lesz a p értéke.
Pointer dereferencia
*p
A * művelet segítségével érhetjük el a p értékét vagyis a dinamikus változót. A *p változóhivatkozás a p értékére, vagyis a dinamikus változóra hivatkozik, tehát a *p értéke a dinamikus változó értéke lesz.
Dinamikus változó törlése
free(p);
A művelet hatására a p-hez tartozó memóriaterület felszabadul ezáltal a dinamikus változó megszűnik. A művelet végrehajtása után a p pointerhez nem tartozik érvényes változó, ezért a *p változóhivatkozás végrehajtása jobb esetben azonnali futási hibát eredményez. (Rosszabb esetben pedig olyan lappangó hibát, aminek az eredménye a program egy teljesen más pontján jelenik meg.)
A címképző művelet
p = &i;
A művelet meghatározza egy változóhoz tartozó memória mező címét. Ha egy p pointer típusú változó értéke az i változóhoz tartozó memória címe, akkor azt mondjuk, hogy a p i-re mutat. Ez a referencia szerinti értékátadás.
// !
P: Nézzük meg, mi a különbség p, q, illetve *p és *q értéke között.
==============================================================================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p, *q;
p = malloc(sizeof(int));
q = malloc(sizeof(int));
*p = 3;
*q = 3;
printf("p es q %s\n", p == q ? "megegyezik" : "nem egyezik meg");
printf("*p == %d, *q == %d\n", *p, *q);
*p = 4;
printf("*p == %d, *q == %d\n", *p, *q);
free(p);
p = q;
printf("p es q %s\n", p == q ? "megegyezik" : "nem egyezik meg");
printf("*p == %d, *q == %d\n", *p, *q);
*p = 4;
printf("*p == %d, *q == %d\n", *p, *q);
free(p);
return 0;
}
P: Futtassuk le a következő programot, és értelmezzük! Melyik érték melyik
értékkel egyenlő, és miért ?
==============================================================================
#include <stdio.h>
int main()
{
int a = 10;
int *pa;
pa = &a;
printf("%d %#x\n", a, (int)pa);
printf("%#x %#x\n", (int)&a, (int)&pa);
printf("%d\n", *pa);
return 0;
}
// !
F: Írj egy csere() függvényt, ami megcseréli két int típusú változó értékét.
==============================================================================
#include <stdio.h>
void csere(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int x = 3, y = 4;
printf("A fuggveny elott: x = %d, y = %d\n", x, y);
csere(&x,&y);
printf("A fuggveny utan: x = %d, y = %d\n", x, y);
return 0;
}
// !
F: Deklarálj egy 20 elemű int tömböt, majd töltsd fel értékekkel az inputról.
Deklarálj egy pointert, és a beolvasást azon keresztül valósítsd meg.
==============================================================================
#include <stdio.h>
#define N 20
int main()
{
int t[N], *p, i;
for(i=0; i<N; i++) {
p=&(t[i]);
scanf("%d", p);
}
for(i=0; i<N; i++) {
printf("%d\n", t[i]);
}
return 0;
}
F: Először olvasd be a tömb méretét, és foglalj neki dinamikusan helyet!
==============================================================================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *t, *p, i, N;
scanf("%d", &N);
t=(int*)malloc(N*sizeof(int));
for(i=0; i<N; i++) {
p=&(t[i]);
scanf("%d", p);
}
for(i=0; i<N; i++) {
printf("%d\n", t[i]);
}
free(t);
return 0;
}
// !
F: Olvass be 5 darab maximum 99 karakter hosszú szót úgy, hogy mindegyiknek
pontosan annyi helyet foglalsz, amennyi kell! A sztringeket írasd ki, majd
szabadítsd fel a lefoglalt területet!
==============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buff[100];
char *ptr_tomb[5];
int i;
for(i=0; i<5; i++) {
scanf("%s", buff);
ptr_tomb[i] = (char*)malloc(strlen(buff)+1);
strcpy(ptr_tomb[i], buff);
}
for(i=0; i<5; i++) {
puts(ptr_tomb[i]);
}
for(i=0; i<5; i++) {
free(ptr_tomb[i]);
}
return 0;
}
char Honap[][20]
![]()
char *honap[]
![]()
F: Olvasd be egy tömb méretét, foglalj neki dinamikusan helyet, majd olvasd be
az elemeit!
==============================================================================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *t, *p, i, N;
scanf("%d", &N);
t=(int*)malloc(N*sizeof(int));
for(i=0, p=t; i<N; i++, p++) {
scanf("%d", p);
}
for(i=0, p=t; i<N; i++) {
printf("%d\n", *(p++));
}
free(t);
return 0;
}
F: Adott egy kétdimenziós tömb. Pointer segítségével járjuk be az összes
elemét.
==============================================================================
#include <stdio.h>
#define SIZE 3
int main()
{
int tomb[SIZE][SIZE] = {{0, 1, 2 },
{3, 4, 5 },
{6, 7, 8 } };
int i,j;
int *pa = NULL;
pa = tomb; /* pa = &tomb[0][0] */
for(i = 0; i< SIZE*SIZE; i++)
printf("%2d ", pa[i]);
printf("\n");
for(i = 0; i< SIZE*SIZE; i++)
printf("%2d ", *(pa+i));
printf("\n");
for(i = 0; i< SIZE*SIZE; i++, pa++)
printf("%2d ", *pa);
printf("\n");
/* vigyázat! mivel pa-t növeltük a for ciklusban, ezért a ciklus után már
* nem a tömb legelső elemére fog mutatni!
*/
return 0;
}
// !
F: Dinamikus kétdimenziós tömb létrehozása
==============================================================================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p, **t;
int N=3, M=4;
int i, j, v=0;
/* V1: egydimenziós tömb */
p=malloc(N*M*sizeof(int));
for(i=0; i<N; i++) {
for(j=0; j<M; j++) {
p[i*M+j]=v++;
}
}
free(p);
/* V2: sorokat külön-külön */
t=malloc(N*sizeof(int*));
for(i=0; i<N; i++) {
t[i]=malloc(M*sizeof(int));
}
for(i=0; i<N; i++) {
for(j=0; j<M; j++) {
t[i][j]=v++;
}
}
for(i=0; i<N; i++) {
free(t[i]);
}
free(t);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
const int maxsize = 100;
/* Kétdimenziós tömbök */
float tomb_statikus[100][100];
float tomb_valtozo_meretu_de_a_gcc_nem_szereti[maxsize][maxsize];
/*
* Mivel a program futása során tudjuk meg a maxsize -t (tegyük fel, hgoy így van)
* dinamikusan kell (így a leghelyesebb, így ragaszkodunk a szabványhoz, és így lesz hordozható a kódunk )
* helyet foglalni a kétdimenziós tömbünknek.
*
* A kétdimenziós tömb olyan egydimenziós tömb, amelynek minden eleme egy egydimenziós tömb.
*
* egydimenziós tömböt tudunk dinamikus létrehozni :
* float *tomb = (float*)calloc(meret, sizeof(float));
* -> tehát az első egydimenziós tömb elemeit (egydimenziós tömböket) létre tudjuk hozni.
* azaz a deklarációnk nézhetne így is ki : float *tomb[meret] (hiszen ez egy pointerekból álló tömb.)
* Ezzel nem kerültük ki a meret kiírását ->
* csináljunk egy pointert erre a tömbre : float **tomb.
*
* És KÉSZ!
*
* */
/* Egy olyan pointer, amely egy pointerre mutat, amely egy float tipusú változó címét tudja tárolni. */
float **tomb_dinamikus;
/* Foglaljuk le a helyet a külső tömbnek, azaz hozzunk létre egy olyan egydimenziós tömböt,
* amelynek az elemei olyan pointerek, melyek float változók címeit tudják tárolni*/
tomb_dinamikus = (float**)calloc(maxsize, sizeof(float*));
/* Magyarázat : (float**) : mivel calloc egy void* -al tér vissza, helyes, ha típuskonverziót hajtunk végre.
* mi a típusa tomb_dinamikus -nak? float**.
* sizeof(float*) : minden egyes indexén a tomb_dinamikus tömbnek egy
* float-ra mutató pointert akarunk tárolni.
* Ezért az alaptípusának a mérete float*, tehát ennek a méretét kell megadnunk.
* */
/* Foglaljunk helyet a most létrehozott tömb elemeinek (hiszen azok is pointerek) */
for(i = 0; i< maxsize; i++)
tomb_dinamikus[i] = (float*)calloc(maxsize, sizeof(float));
/* Magyarázat : (float*) : mivel calloc egy void* -al tér vissza, helyes, ha típuskonverziót hajtunk végre.
* mi a típusa tomb_dinamikus[i] -nek? float* .
* sizeof(float) : minden tomb_dinamikus[i] egy float-ra mutató pointer.
* Ezért az alaptípusának a mérete float, tehát ennek a méretét kell megadnunk.
* */
tomb_dinamikus[2][5] = 12.45;
printf("%f\n",tomb_dinamikus[2][5]);
/* Ha már nem használjuk a tömbünket, fel kell szabadítani az általunk lefoglalt memóriaterületet.
*
* Először a pointereket tartalmazó tömbben lévő pointereket kell felszabadítanunk, majd utána a tömbnek lefoglalt memóriaterületet.
* */
for(i = 0; i< maxsize; i++)
free(tomb_dinamikus[i]);
free(tomb_dinamikus);
return 0;
}
Leírás elérhető .pdf formátumban: akasztofa_feladatkiiras.pdf
Küldés STUD-os email címről, melynek tárgya: [progalap2015][09][plusz], tartalma pedig maga a kód, vagy a csatolt .c fájl.
Beküldési határidő: keddieknek és csütörtökieknek is egyaránt 2015. 11. 06., éjfél .
Egy lehetséges futási eredmény:
_ _ _ _ _ _ _ Tippelj egy betut: l Eltalaltad az adott karaktert, lephetsz tovabb! l _ _ _ _ _ _ Tippelj egy betut: v Nem talalt! Meg 5 lehetoseg az adott karakterre! l _ _ _ _ _ _ Tippelj egy betut: m Nem talalt! Meg 4 lehetoseg az adott karakterre! l _ _ _ _ _ _ Tippelj egy betut: o Eltalaltad az adott karaktert, lephetsz tovabb! l o _ _ _ _ _ Tippelj egy betut: v Eltalaltad az adott karaktert, lephetsz tovabb! l o v _ _ _ _ Tippelj egy betut: a Eltalaltad az adott karaktert, lephetsz tovabb! l o v a _ _ _ Tippelj egy betut: t Nem talalt! Meg 5 lehetoseg az adott karakterre! l o v a _ _ _ Tippelj egy betut: r Nem talalt! Meg 4 lehetoseg az adott karakterre! l o v a _ _ _ Tippelj egy betut: e Nem talalt! Meg 3 lehetoseg az adott karakterre! l o v a _ _ _ Tippelj egy betut: g Eltalaltad az adott karaktert, lephetsz tovabb! l o v a g _ _ Tippelj egy betut: o Eltalaltad az adott karaktert, lephetsz tovabb! l o v a g o _ Tippelj egy betut: n Nem talalt! Meg 5 lehetoseg az adott karakterre! l o v a g o _ Tippelj egy betut: k Gratulalok! Kitalaltad a keresett szot, amely "lovagok" volt!
Egy lehetséges megoldás letöltése .
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ó.
A házi feladat és további gyakorló példák elérhetőek a PUB-ban ( /n/pub/ProgramozasAlapjai/Gyakorlat/ )
Bárkinek bármi kérdése adódik a feladatokkal kapcsolatban írjon nyugodtan! ( Gyakoroljatok sokat! )
Téma:
3. - 9. gyakorlat anyaga.
Gyakorlásra:
A honlapomon a 3. - 9. 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ó:
Előreláthatóan 45 percetek lesz a feladatok megoldására és beadására (tehát 8:55-ig/12:45-ig). A feladatokat 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, mivel 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.