Programozás alapjai gyakorlat 2014-2015/1

7. gyakorlat


    Egy kis változás

Mivel nov. 20-án csütörtökön 13:00-tól TDK miatt dékáni szünet van, a 8. mini zh-t a csütörtök délutáni csoportok nem tudnák megírni. Ezért a 6. és 7. zh 10 helyett 15 pontos és 30 helyett 45 perces lesz. Az eredetileg tervezett 8. mini zh órája zh nélkül lesz megtartva.




    Mit is tanultunk a 6. gyakorlaton?

Ismétlő feladatsort nem állítottam össze. A lényeg, hogy egyszerű típusdefiniálást tudni kell létrehozni, tudni kell használni az enum-felsorolás típust, és jól kell ismerni az egyes típusok méretét és előjeles/előjeltelen formájuk alsó és felső korlátait.




    Függvények haladó

Figyeljük meg, hogy az alábbi programban, nem simán változó értékeket adunk át, hanem memória címeket ( & ). Függvényhíváskor pedig ezekre a memória címekre mutató pointereket ( * ) használunk a változók tényleges értékeinek felülírásához.

F: Számítsd ki egy háromszög területét és kerületét a három oldalhossz
segítségével. A számolást egyetlen függvény végezze.

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

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

void haromszogTKpar(double a, double b, double c, double *t, double *k){
	double s;
	*k = (a + b + c);
	s  = (*k) / 2.0;
	*t = sqrt((s-a)*(s-b)*(s-c)*s);
}

int main() {
	double a, b, c, t, k;
	printf("Adja meg az oldalakat!?:\n");
	scanf("%lf %lf %lf", &a, &b, &c);
	haromszogTKpar(a, b, c, &t, &k);

	printf("T: %lf; K: %lf;\n", t, k);
	return 0;
}

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

Nézzük meg mi történik, ha nem pointereket használunk.
F: Másodfokú egyenlet megoldása

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

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

int megoldo(double a, double b, double c,  /* együtthatók */
                double *x1, double *x2)             /* gyökök */
{
  double d;                                /* a diszkrimináns */
  int valos;                            /* van-e megoldás */

  valos = 1;
  if (a == 0.0) {
      if (b == 0.0) {                 /* az egyenlet elfajuló */
          valos = 0;
      } else {						  /* 1. fokú */
          *x1 = -(c / b);
          *x2 = *x1;
      }
  } else {
      d = b * b - 4.0 * a * c;
      if (d < 0.0) {                      /* nincs valós gyöke */
          valos = 0;
      } else {
          *x1 = (-b + sqrt(d)) / (2.0 * a);
          *x2 = (-b - sqrt(d)) / (2.0 * a);
      }
  }
  return valos;
}

int main() {
	double a, b, c, x1, x2;
	printf("Adja meg az egyutthatokat!\n?:");
	scanf("%lf", &a); scanf("%lf", &b); scanf("%lf", &c);
	if(megoldo(a, b, c, &x1, &x2))
		printf("Az egyenlet megoldasai: %lf, %lf\n", x1, x2);
	else
		printf("Az egyenletnek nincs valos megoldasa.\n");
	return 0;
}

Rekurzió: Rekurziónak nevezzük, amikor egy függvény önmagát hívja, egy bizonyos feltétel teljesüléséig. Sokkal elegánsabb megoldást kapunk és csökkenti a redundanciát a kódunkban. Használata akkor ajánlott, ha egy bizonyos függvény hívását egymás után többször végre kell hajtani. Azonban a számítási idő és a memóriaigény jelentős növekedése miatt az esetek többségében mégis az iteratív megoldás ajánlott.

F: Fibonacci-sorozat n. elemének kiszámítása rekurzív módszerrel

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

#include <stdio.h>

int fib(int n) {
	if(n==1 || n==2) {
		return 1;
	} else {
		return fib(n-1) + fib(n-2);
	}
}

int main() {
	int n;
	printf("n erteke?: ");
	scanf("%d",&n);
	printf("A fibonacci sorozat %d. eleme: %d\n",n,fib(n));
	return 0;
}

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

Kérdés: Hányszor hívódik a függvény?
F: n faktoriális kiszámítása rekurzív módszerrel

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

#include <stdio.h>
 
long factorial(int);
 
int main()
{
  int n;
  long f;
 
  printf("Enter an integer to find factorial\n");
  scanf("%d", &n); 
 
  if (n < 0)
    printf("Negative integers are not allowed.\n");
  else
  {
    f = factorial(n);
    printf("%d! = %ld\n", n, f);
  }
 
  return 0;
}
 
long factorial(int n)
{
  if (n == 0)
    return 1;
  else
    return(n * factorial(n-1));
}


    Input/Output haladó

Fontos, hogy mekkora méretű típusban mekkora/milyen értéket szeretnénk letárolni. Erre beolvasáskor és kiíratáskor is jelentős figyelmet kell fordítani.

sizeof operátor - típusok méretének meghatározása byte-okban. Pl.:

int i = sizeof(int);   // ilyenkor az i változóba bele kerül az int típus mérete. ez a C esetén 4 byte
C típus         méret(bájt)   alsó határ    felső határ
_______________________________________________________
char                 1                 ?              ?
signed char          1              -128            127
unsigned char        1                 0            255
short int            2            -32768          32767
unsigned short int   2                 0          65535
int                  4       -2147483648     2147483647
unsigned int         4                 0     4294967295
long int             4       -2147483648     2147483647
unsigned long int    4                 0     4294967295
long long            8              -263          263-1
float                4         -+3.4028234663852886E+38
double               8        -+1.7976931348623157E+308
long double          8        -+1.7976931348623157E+308

F: Írj egy programot, ami beolvas egy előjeltelen short int értéket, és
   nyolcas számrendszerbe átváltva írja ki.

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

#include <stdio.h>

int main() {
	unsigned short int v;
	scanf("%hu", &v);
	printf("%ho\n", v);
	return 0;
}
F: Írj egy programot, ami beolvas egy hexadecimális egész számot, majd 15
   karakter szélességben kiírja a decimális értékét, mindenképpen előjellel és
   vezető nullákkal.

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

#include <stdio.h>

int main() {
	unsigned int v;
	scanf("%x", &v);
	printf("%+015u\n", v);
	return 0;
}
F: Olvass be egy double és egy egész értéket, majd a valós értéket írasd ki az
   egészben megadott pontossággal.

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

#include <stdio.h>

int main() {
	double ertek;
	int pontossag;
	scanf("%lf %d", &ertek, &pontossag);
	printf("%1.*lf\n", pontossag, ertek);
	return 0;
}
F: Olvass be egy csupa kisbetűből álló, legfeljebb 20 karakteres sztringet,
   majd írasd ki 10 karakteren jobbra igazítva az első legfeljebb 8
   karakterét. A bemeneten a kisbetűket közvetlenül bármi követheti.

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

#include <stdio.h>

int main() {
	char str[21];
	scanf("%20[a-z]", str);
	printf("%10.8s\n", str);
	return 0;
}

getchar : egy darab karaktert vár a standard bemeneten (egy billentyű lenyomás).

char c = getchar();

putchar : egy darab karaktert ír ki a képernyőre.

putchar(c);
F: Írasd ki a SPACE jelig (32) tartó bemenetet úgy, hogy a számjegyeket
   törlöd belőle. A végén írd ki, hogy hány számjegyet töröltél.

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

#include <stdio.h>

int main() {
	int c, d=0;
	while((c=getchar())!=32) {
		if('0'<=c && c<='9') {
			d++;
		} else {
			putchar(c);
		}
	}
	printf("\n--\n%d torolve\n", d);
	return 0;
}

A C nyelv szabványos könyvtára tartalmaz függvényeket karaktersorozatok (sztringek) egyetlen hívással történő beolvasására (gets) és kiírására (puts).

gets : A gets függvény egy sort (<Enter> lenyomásáig) olvas a szabványos inputról, majd a karaktereket az argumentumban megadott sptr mutató által kijelölt területre másolja:

char* gets(char *sptr);

puts : A puts függvény az argumentumban megadott sztringet a szabványos kimenetre (a képernyőre) írja. A függvény egy nem negatív szám visszaadásával jelzi a sztring sikeres kiíratását, ellenkező esetben pedig EOF (-1) értékkel tér vissza.

int puts(char *sptr);
F: Olvass be egy sztringet, majd írasd ki a képernyőre
   a gets és a puts parancsok használatával.

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

#include <stdio.h>

int main() {
	char str[80];
	
	puts("Sztring beolvasasa:");
	gets(str);
	puts(str);
    
	return 0;
}


    Input/Output műveletek FILE-ból/ba

F: Írj egy programot, ami beolvas két egész számot, majd kiírja az összegüket
   és a szorzatukat.

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

#include <stdio.h>

int main() {
  int a, b;
  scanf("%d %d", &a, &b);
  printf("Osszeg: %d\nSzorzat: %d\n", a + b, a * b);
  return 0;
}
F: Módosítsuk úgy a programot, hogy használja az stdin, stdout, fscanf és
   fprintf függvényeket.

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

#include <stdio.h>

int main() {
  int a, b;
  fscanf(stdin, "%d %d", &a, &b);
  fprintf(stdout, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);
  return 0;
}

/* 
   látható, hogyha elhagynánk az fscanf és az fprintf elejéről az f betűket, 
   valamint a zárójelekből az stdin és stdout függvényeket, 
   az előző feladattal ekvivalens megvalósítást kapnánk
*/

A fájlok adatfolyamként történő kezelése során egy FILE * típusú ún. filemutató azonosítja az állományt. (Ezt az állományt az STDIO.H file deklarálja.)

FILE *nev;

Ahhoz, hogy a háttértáron levő file tartalmához hozzáférjünk, a file-t meg kell nyitnunk. A file megnyitását a fopen függvény hívásával végezhetjük el, melynek prototípusa:

FILE * fopen(const char * filename, const char *mode);

avagy meglévő FILE * esetén

FILE * vmi;
vmi = fopen(const char * filename, const char *mode);

A filename helyére a beolvasandó file neve kerül, tehát egy sztring. (pl.: "be.txt")

A mode úgyszint egy sztring, amely a file elérését és típusát határozza meg. (pl.: "r")

A lehetséges elérési módok:

    "r"		- Létező file megnyitása olvasásra.
    "w"		- Új file megnyitása írásra. Ha file már létezik, akkor a tartalma elvész.
    "a"		- File megnyitása hozzáírásra. A nyitás után a file végén lesz az aktuális file-pozíció. Ha a file nem létezik, akkor az fopen létrehozza azt.
    "r+"	- Létező file megnyitása írásra és olvasásra (update).
    "w+"	- Új file megnyitása írásra és olvasásra (update). Ha a file már létezik, akkor a tartalma elvész.
    "a+"	- File megnyitása a file végén végzett írásra és olvasásra (update). Ha a file nem létezik, akkor az fopen létrehozza azt.

Amikor többé nincs szükségünk a megnyitott file(ok)-ra, akkor kell használnunk az fclose hívást, amely lezárja a file-t.

F: Módosítsuk úgy az előző programot, hogy valódi fájlokat használjon.

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

#include <stdio.h>

int main() {
  int a, b;
  FILE *infile;   //beolvasáshoz
  FILE *outfile;  //kiíratáshoz
  infile = fopen("be.txt", "r");   //bementi fájl olvas
  outfile = fopen("ki.txt", "w");  //
  
  fscanf(infile, "%d %d", &a, &b);
  fprintf(outfile, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);

  fclose(infile);
  fclose(outfile);
  return 0;
}

A be.txt-nek léteznie kell, viszont a ki.txt-t a program létrehozza magától, amennyiben nem volt ellőállítva.

Ha a megadott állományt nem sikerült megnyitni, vagy ha a FILE struktúrának nem sikerült helyet foglalni a memóriában, NULL lesz a függvényérték.

F: Hibakóddal lépjen ki a program, ha valamelyik fájl megnyitása nem sikerült.

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

#include <stdio.h>

int main() {
  int a, b;
  FILE *infile;
  FILE *outfile;
  if(!(infile = fopen("be.txt", "r"))) {
  	return 1;
  }
  if(!(outfile = fopen("ki.txt", "w"))) {
  	fclose(infile);
  	return 1;
  }
  
  fscanf(infile, "%d %d", &a, &b);
  fprintf(outfile, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);

  fclose(infile);
  fclose(outfile);
  return 0;
}



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 letöltése .




    Jövő héten nincs miniZH (2014.10.20.)

A gyakorlat témája:

  Konzultációs óra. Nem lesz új anyag, sem katalógus. Viszont bátran be lehet jönni kérdezni, gyakorolni.


     Vissza a lap tetejére.