/*
Alap C stringje: char[], 0 végű.
dinamikus: char*, malloc() - értékadással vigyázni, pointerekről van szó
Alap C stringfüggvények:
//BEMENET
gets_s(char *buffer, int buffer meret) Egy stringet olvas be a standard bemenetről, beleértve a szóközöket is.
(scanf("%s") nem jó szóköz miatt)
Használható helyette fgets(char *buffer, int buffer meret, stdin).
size_t strlen(const char * str) Megadja a string hosszát, azaz az első '\0' karakterig terjedő
karakterek számát (a null terminátort nem számítja).
char* strcpy_s(char * cél, sizeof(cél), char * forrás) A forrás string összes karakterét, beleértve a null terminátort
char* strcpy_s(char * cél, size_t buffer_meret, char * forrás) ('\0'), átmásolja a cél memóriaterületre.
Nincs bufferhossz-ellenőrzés, így buffer túlcsordulás léphet fel.
char* strncpy_s(char *cél, size_t buffer_méret, const char *forrás, size_t mennyit) A forrás stringből legfeljebb `mennyit` karaktert másol
a cél memóriaterületre.
Ellenőrzi, hogy a cél buffer elég nagy-e (`buffer_méret`
paraméter alapján), és ha nem, hibát ad vissza.
Ha a forrás rövidebb, a fennmaradó helyet nullákkal tölti fel.
Mindig biztosítja, hogy a cél string végére `'\0'` terminátor
kerüljön.
A `strncpy` biztonságosabb verziója, Linux-ban nem érhető el,
főként Windows MSVC-ben használatos.
char* strcat_s(char *cél, size_t buffer_méret, const char *forrás) A forrás stringet hozzáfűzi a cél string végéhez (beleértve a '\0' terminátort
is).
A strcat_s biztonságosabb, mint a strcat, mivel ellenőrzi a buffer méretét.
Ha a buffer nem elég nagy a forrás és a cél string összefűzéséhez, a függvény
hibát ad vissza, és az összefűzést nem hajtja végre.
A cél string bufferének méretét a buffer_méret paraméterrel kell megadni.
char* strncat_s(char *cél, size_t buffer_meret, const char *forrás, size_t mennyit) A forrás string első mennyit karakterét fűzi hozzá a cél
stringhez, és automatikusan hozzáad egy '\0' terminátort.
Biztonságosabb, mert ellenőrzi, hogy a cél bufferhossza
(`buffer_meret`) elég nagy-e a művelethez.
Ha a buffer mérete nem elegendő, a függvény hibát ad vissza,
és nem módosítja a cél tartalmát.
char* strchr(char * miben, int karakter) Megkeresi az első előfordulását a karakter-nek a miben stringben, és pointerként
tér vissza az első találat helyére.
Visszatérési érték: A találat helyének pointere, vagy NULL, ha nem található.
char* strstr(char * miben, char * mit) Megkeresi a mit string első előfordulását a miben stringben.
Visszatérési érték: Pointer a találat kezdetére, vagy NULL, ha nem található.
!!! char* strpbrk(char *str, char *karakterek) Megkeresi a str stringben az első olyan karaktert, amely megtalálható a karakterek string bármelyik elemeként.
Visszatérési érték: Pointer az első egyező karakterre a str stringen belül, vagy NULL, ha nincs ilyen karakter.
int strcmp(char * egyik, char * másik) Két stringet hasonlít össze,
Visszatérési érték:
0: azonosak.
<0: az első kisebb.
>0: az első nagyobb.
int strncmp(char * egyik,char * másik, size_t mennyit) Két string első mennyit karakterét hasonlítja össze.
Minden nagyjából ugyanaz
!!! char* strtok_s (char* mit, const char* elválasztók, char** context )
Egy stringet darabol fel az elválasztók karakterek alapján, szálbiztos módon.
Első híváskor: strtok_s(mit, elválasztók, &context).
További hívásokkor: strtok_s(NULL, elválasztók, &context)
NULL-t ad vissza, ha nincs több rész.
Biztonságosabb, mint strtok: nem használ globális állapotot, a context változóban tárolja az állapotot.
Az eredeti string itt is módosul!!!
(Joe idézet: - először megadjuk a darabolandót, és az elválasztó karaktereket
- visszakapjuk az első darabot,
- további hivásokkor mit=NULL, ha nincs már darab, NULL-t kapunk (while...)
- aztán jön Gábriel arkangyal, és megkér, hogy fáradjunk ki...)
sprintf_s(char * hova, size_t méret, char * formátum, ...) Egy stringet formáz és ment a hova bufferbe, miközben ellenőrzi a buffer méretét.
Biztonságosabb, mint sprintf, mert megakadályozza a buffer túlcsordulást.
Ha a formázott string nem fér bele a megadott méretbe, akkor hibát jelez vagy nullázza a buffer tartalmát.
snprintf(char * hova, size_t méret, char * formátum, ...) Formázott stringet készít, és egy megadott méretű bufferbe írja azt,
biztosítva, hogy ne lépje túl a buffer méretét. A '\0' lezáró karaktert
automatikusan hozzáadja, ha van elég hely.
Nem ír a buffer határain kívül,
de ha a buffer túl kicsi, a formázott string levágódik.
Visszatérési érték: A teljes formázott string hossza
(függetlenül attól, hogy elfért-e a bufferben).
Ha a visszatérési érték ≥ bufsize, a kimenet levágódott. //Megjegyzés: sprintf_s és snprintf szinte ugyanaz -
//hibakezelés kicsit más
//snprintf C99-es szabványú, szélesebb körben elterjedt
sscanf_s(char * forrás, char * formátum, &..., méretek...) Egy stringből olvas adatokat a megadott formátum szerint, biztonságosabb módon, mert ellenőrzi a buffer méretét.
Pl.
char url[50], ip[50];
eredmeny = sscanf_s("http://pelda.hu;192.168.1.1", "%[^';'];%s", url, (unsigned int)sizeof(url), ip, (unsigned int)sizeof(ip));
stdlib.h hasznos függvényei:
atoi(const char *str) – Átalakít egy karakterláncot (string) egész (int) számmá.
atol(const char *str) – ... (long int) számmá.
atof(const char *str) – ... lebegőpontos (double) számmá.
gcvt(double num, int ndigit, char *buf) – Egy double számot alakít karakterlánccá tudományos
vagy fixpontos formátumban, a kívánt számú számjeggyel.
ecvt(double num, int ndigit, int *decpt, int *sign) – Egy double számot tudományos formátumba alakít karakterláncként,
adott számjegyszámmal, és visszaadja a tizedespont pozícióját
(decpt) és az előjelet (sign).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
//NÉHÁNY ALAP STRINGFÜGGVÉNY
char string[] = "Tegnap este programoztam"; //Memóriában: Tegnap este programoztam\0
char* dinam_string1 = (char*)malloc(101 * sizeof(char)); //memset nélkül memóriaszemét van kezdetben benne pl.
//gets_s(dinam_string, sizeof(*dinam_string)); "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý9-Đř"
gets_s(dinam_string1, 101); //Pl. Pelda Bence
char* dinam_string2 = (char*)malloc(101 * sizeof(char));
memset(dinam_string2, 0, 101 * sizeof(char));
fgets(dinam_string2, 101 * sizeof(char), stdin); //pl. Pelda Eper - \n-t is beolvassa
printf("%s nevenek hossza: %zu\n\r%s nevenek hossza: %zu\n",
dinam_string1, strlen(dinam_string1),
dinam_string2, strlen(dinam_string2)); //Itt látszik is, hogy a \n miatt sort tör a program magától
//Illetve, hogy egyforma hosszúnak tűnnek
dinam_string2[strlen(dinam_string2)-1] = '\0';
strcpy_s(dinam_string1, 101*sizeof(char), dinam_string2);
printf("%s\n", dinam_string1);
strncpy_s(dinam_string2, strlen(dinam_string1), dinam_string1, 5);
printf("%s\n", dinam_string2);
strcat_s(dinam_string1, 101 * sizeof(char), dinam_string2);
printf("%s\n", dinam_string1);
strncat_s(dinam_string1, 101 * sizeof(char), dinam_string2, 3);
printf("%s\n", dinam_string1);
char* mutato = strchr(dinam_string2, 'l'); //Ha nincs talalat nullpointert ad vissza, printf() ilyenkor (null)-t ír ki.
printf("%s\n", mutato); //nullpointerrel való művelet programtörést eredményez. Pl. próbáld ki Pelda Bence és Pelda Eper helyett
//Bence Pelda és Eper Pelda-val... 43. sorban probléma
mutato = strchr(mutato, 'd');
printf("%s\n", mutato);
mutato = strchr(dinam_string2, 'x');
printf("%s\n", mutato);
mutato = strstr(dinam_string2, "ld");
printf("%s\n", mutato);
mutato = strstr(dinam_string2, "nincs");
if (!mutato) {
printf("nincs talalat mutato == NULL\n");
}
int osszehas1 = strcmp(dinam_string1, dinam_string2);
int osszehas2 = strcmp("aaa", "aaa");
int osszehas3 = strcmp("aaa", "aab");
printf("Elso pelda: %i\n\
\rMasodik pelda: %i\n\
\rHarmadik pelda: %i\n",
osszehas1,
osszehas2,
osszehas3);
int osszehas4 = strncmp("aaa", "aab", 2);
printf("Negyedik pelda: %i\n\n", osszehas4);
//2D-S KARAKTERTÖMB, TÖBBSZAVAS STRINGEK KEZELÉSE, TOKENIZÁLÁS
char** szavak;
char* pointer = NULL, * kovetkezo = NULL, *buffer; //Vigyázat az egysoros deklarációnál a pointerekkel: mindig ki kell tenni újra a *-ot
int szoszam = 0;
szavak = (char**)malloc(10 * sizeof(char*));
if (!szavak) {
printf("Memóriafoglalási hiba!\n");
return 1;
}
buffer = (char*)malloc(100 * sizeof(char));
if (!buffer) {
printf("Memóriafoglalási hiba!\n");
free(szavak);
return 1;
}
printf("Adja meg a szavakat: ");
if (gets_s(buffer, 100) == NULL) {
//if (fgets(buffer, 100, stdin) == NULL) { Másik lehetséges bekérési mód
printf("Hiba a bemenet olvasása közben.\n");
free(szavak);
free(buffer);
return 1;
}
buffer[strcspn(buffer, "\n")] = 0; //Az újsor karakter levágása ha fgets-el lenne bekérve
pointer = strtok_s(buffer, " ", &kovetkezo); //Első hívást érdemes mindig cikluson kívül
while (pointer != NULL) {
if (szoszam >= 10) {
printf("Túl sok szó lett megadva!\n");
break;
}
szavak[szoszam] = (char*)malloc(strlen(pointer) + 1);
if (!szavak[szoszam]) {
printf("Memóriafoglalási hiba!\n");
break;
}
strcpy_s(szavak[szoszam], strlen(pointer)+1, pointer);
printf("%s ", szavak[szoszam]);
szoszam++;
pointer = strtok_s(NULL, " ", &kovetkezo);
}
printf("\n\n");
for (int i = 0; i < szoszam; i++) {
free(szavak[i]);
}
free(szavak);
free(buffer);
char buffer_stat[100]; //Kimeneti statikus karaktertömb
int szam = 42;
double pi = 3.14159;
sprintf_s(buffer_stat, 100*sizeof(char), "A szam: %d, a Pi erteke: %.2f", szam, pi);
printf("%s\n", buffer_stat);
snprintf(buffer_stat, 100 * sizeof(char), "A Pi erteke: %.2f, a szam %d", pi, szam);
printf("%s\n", buffer_stat);
char input[100]; //A bemeneti szöveg tárolására
char szo[20];
//Felhasználói bemenet beolvasása
printf("Adj meg egy szöveget (pl. '42 3.14 alma'): ");
fgets(input, sizeof(input), stdin); //Egy teljes sort beolvas
//sscanf_s használata a string feldolgozására (buffer méretek megadása szükséges)
if ((input, "%d %lf %19s", &szam, &pi, szo, (unsigned int)sizeof(szo)) == 3) {
//Kiírás az eredmények ellenőrzésére
printf("Egesz szám: %d\n", szam);
printf("Lebegopontos szam: %.2f\n", pi);
printf("Szo: %s\n", szo);
}
else {
printf("Hibas bemenet! Kerlek, adj meg egy szamot, egy lebegopontos erteket es egy szot.\n");
}
//STRING <--> SZÁM KONVERZIÓS FÜGGVÉNYEK
char str1[] = "1234";
szam = atoi(str1);
printf("atoi: A string \"%s\" egész számmá alakítva: %d\n", str1, szam);
char str2[] = "987654321";
long int nagy_szam = atol(str2);
printf("atol: A string \"%s\" long int számmá alakítva: %ld\n", str2, nagy_szam);
char str3[] = "3.14159";
double tort = atof(str3);
printf("atof: A string \"%s\" lebegőpontos számmá alakítva: %f\n", str3, tort);
tort = 123.456789;
char buffer[20];
gcvt(tort, 6, buffer); //6 számjegyet használ
printf("gcvt: A szám %f karakterlánccá alakítva: %s\n", tort, buffer);
int decpt, elojel;
char* ecvtStr = ecvt(tort, 6, &decpt, &elojel);
printf("ecvt: A szám %f tudományos formátumban: %s (tizedespont helye: %d, előjel: %d)\n",
tort, ecvtStr, decpt, elojel);
return 0;
}
//Gyakorló feladatok
//1. Feladat:
//Készíts egy programot ami ékezetek nélküli neveket kér be pl. Pelda Joska azokat 2d-s karaktertömbbe tölti.
//Egészítsd ki úgy, hogy ember struktúrákba töltse be, amiknek adattagjai: vezetéknév, keresztnév
//Alakítsd át a keresztnév adattagot úgy, hogy több névvel rendelkező emberek neveit is be tudja olvasni.
//Maximum 5 neve lehessen egy embernek - Feltételezzük továbbá, hogy a vezetéknevek egyszavasak, de
//keresztnévből lehet több egy embernek
//
//2. Feladat:
//Készíts egy programot, ami \n-enként tördelve képes beolvasni egy verset egy 2d-s karaktertömbbe
//pl. (Ctrl+K+U-vel uncommenteld)
//char vers[] = "A gep szolit, kodolj hat,\n\
//Sorok kozt no az alkotas.\n\
//Logika szarnyan szall az esz,\n\
//A program el, a siker kesz.\n";
//Készíts hozzá egy programot, ami megszámolja egy stringben a magánhangzók számát
//Alakítsd ezt egy függvénnyé aminek bemeneti paramétere egy string, visszatérítési értéke a magánhangzók száma.
//
//3. Feladat:
//Készíts egy számokból, szóközökből és \n-ekből álló stringet ami analóg a 2.Feladattal.
//\n-enként tördelve olvasd be egy karaktertömbbe
//Írasd ki a legnagyobb számot egy adott sorban
//Írasd ki a legnagyobb számot az egészben
//Írasd ki hány páros/negatív/1 jegyű szám volt benne
//
//4. Feladat:
//Készítsd egy programot ami visszafele kiír egy stringet
//Készíts egy programot ami szavanként visszafele kiír egy strginet
//Készítsd egy függvényt, ami kicseréli egy string első és utolsó szavát.
//
//5. Feladat:(nemtriv.)
//Készíts egy stringet, ami szavakból és számokból áll.
//A számokat cseréld azok -1 szeresére. Az eredményt töltsd be egy másik stringbe
//
//6. Feladat:
//Készíts egy függvényt, ami egy tetszőleges stringről eldönti,
//hogy az írásjelekből vagy a nagybetűkből van e több benne
//Készíts egy másik függvényt, ami a nagybetűs szavaknak egy 2d-s
//karaktertömböt foglal, nagybetűk száma*30 mérettel, amibe betölti
//a nagybetűkkel kezdődő szavakat (az 1 betűs nagybetűs szavakat is tudja
//kezelni)
//
//7. Feladat:
//Készíts egy programot, ami számokat olvas be a bemenetről egyesével.
//Ha számjegyen és ,-n kívül akármi más is becsúszik az inputba, akkor írassa ki, hogy
//input vége, a megadott számok: ... voltak.
//
//8. Feladat:
//Készíts egy programot, ami egy előre elkészített történetet ír ki, amelyekbe inputról megadott paramétereket
//helyettesítesz be.
//Kezdődjön a futtatás azzal, hogy ',' vagy ';' karakterekkel szóközök nélkül elválasztva bekérsz egy
//nevet,életkort,évszámot,időpontot :-al elválasztva, és egy műveleti jelet
//pl. Jozsef,1965,9:54,+
//Jelenjen meg egy szöveg ezeket az adatokat behelyettesítve...
//
//9. Feladat:
//Készíts egy napirend stringet
// pl. 7:00-8:00 Reggeli\n\
// 8:00-10:00 Programozas\n\
// 10:00-11:00 Tizorai\n\
// 11:00-15:00 Programozas...
//Kérj be egy időponotot a felhasználótól.
//Írasd ki az idpont utáni napirendet
//Kérj be két időpontot. #:## formátumban
//Csak az időpontok közötti napirendet írasd ki
//Első körben kerek órákkal valósítsd meg, ha sikerült, valósítsd meg általános időpontokkal is
//
//10. Feladat:
//Készíts egy stringvezérelt menüt.
//Tipp: korábbi laboron már volt karaktervezérelt.