Kreditne kartice¶
Autor zadatka: Rade Radišić <radisic.rade@uns.ac.rs>
Napisati program koji kontroliše validnost brojeva kreditnih kartica Iz ulazne datoteke učitati u jednostruko spregnutu listu sledeće podatke:
ime
(jedna reč, do 20 karaktera)prezime
(jedna reč, do 30 karaktera)broj_kartice
(jedna reč, do 10 karaktera)
Novi elementi liste dodaju se na njen kraj.
Program prima ime ulazne datoteke kao argument komandne linije.
Podatke iz ulazne datoteke, potrebno je ispisati u dve različite izlazne datoteke, u zavisnosti od toga da li su kartice validne ili ne.
Imena datoteka su validne-kartice.txt
i nevalidne-kartice.txt
.
Prilikom ispisa u izlaznu datoteku, koristiti format "%-8s %-11s %s\n"
.
Validnost kartice proverava se pomoću Lunovog (Luhn) algoritma na sledeći način:
String se obrađuje od poslednjeg elementa ka prvom
Svaki karakter se konvertuje u celobrojnu vrednost, a svaki drugi treba pomnožiti sa 2
Ukoliko broj koji je pomnožen sa 2 dvocifren, sabiraju se njegove pojedinačne cifre
Sve dobijene brojeve treba sumirati, kartica je validna ukoliko je dobijena suma deljiva sa 10
Na standardni izlaz ispisati izveštaj koji sadrži broj validnih, nevalidnih kartica, kao i procenat uspešnosti (odnos validnih u odnosu na ukupan broj kartica izražen u procentima).
U slučaju sledećih grešaka prilikom rada programa, izaći sa odgovarajućim kodom greške:
Nedovoljan ili suvišan broj argumenata, kod greške
1
(EXIT_FAILURE)Neuspešno dinamičko zauzeće memorije, kod greške
2
Neuspešno otvaranje ulazne datoteke, kod greške
3
Neuspešno otvaranje izlazne datoteke za validne kartice, kod greške
4
Neuspešno otvaranje izlazne datoteke za nevalidne kartice, kod greške
5
Primer ulazne datoteke kartice.txt
:
Joakim Davidovic 7413468278
Tamara Zoric 5016398943
Darija Stefanovic 5220974231
Vedran Crncevic 7787933709
Djordje Matijevic 9501431151
Visnja Gajic 8929550930
Dusica Kovac 2292961261
Kristina Babic 2025850351
Velimir Stojanovic 2222179034
Za primer poziva programa:
./a.out kartice.txt
Očekivani ispis na standardnom izlazu je:
Izvestaj
Broj validnih: 7
Sa greskom: 2
Procenat uspesnosti: 77.78%
Sadržaj izlazne datoteke validne-kartice.txt
je sledeći:
Joakim Davidovic 7413468278
Darija Stefanovic 5220974231
Vedran Crncevic 7787933709
Visnja Gajic 8929550930
Dusica Kovac 2292961261
Kristina Babic 2025850351
Velimir Stojanovic 2222179034
Sadržaj izlazne datoteke nevalidne-kartice.txt
je sledeći:
Tamara Zoric 5016398943
Djordje Matijevic 9501431151
Primer rešenja¶
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4
5#define MAX_IME 21
6#define MAX_PREZIME 31
7#define MAX_BROJ_KARTICE 11
8
9typedef struct kartica_st {
10 char ime[MAX_IME];
11 char prezime[MAX_PREZIME];
12 char broj_kartice[MAX_BROJ_KARTICE];
13 struct kartica_st *sledeci;
14} KARTICA;
15
16FILE *safe_fopen(char *, char *, int);
17void ucitaj_kartice(FILE *, KARTICA **);
18void ispisi_kartice(FILE *, FILE *, KARTICA *, int *, int *);
19
20void inicijalizacija(KARTICA **);
21KARTICA *napravi_cvor(char *, char *, char *);
22void dodaj_na_kraj(KARTICA **, KARTICA *);
23void obrisi_listu(KARTICA **);
24
25int provera_broja(char *);
26
27int main(int argc, char **argv) {
28 KARTICA *glava;
29
30 if(argc != 2) {
31 printf("Primer poziva programa: %s kartice.txt\n", argv[0]);
32 exit(1);
33 }
34
35 inicijalizacija(&glava);
36
37 FILE *ulazna = safe_fopen(argv[1], "r", 3);
38 ucitaj_kartice(ulazna, &glava);
39 fclose(ulazna);
40
41 FILE *izlazna_validni = safe_fopen("validne-kartice.txt", "w", 4);
42 FILE *izlazna_nevalidni = safe_fopen("nevalidne-kartice.txt", "w", 5);
43 int broj_validnih = 0, broj_nevalidnih = 0;
44 ispisi_kartice(izlazna_validni, izlazna_nevalidni, glava, &broj_validnih, &broj_nevalidnih);
45 printf("Izvestaj\n\n");
46 printf("Broj validnih: %d\n", broj_validnih);
47 printf("Sa greskom: %d\n", broj_nevalidnih);
48 printf("Procenat uspesnosti: %.2lf%%\n", (double)broj_validnih / (broj_validnih + broj_nevalidnih) * 100);
49 fclose(izlazna_validni);
50 fclose(izlazna_nevalidni);
51
52 obrisi_listu(&glava);
53
54 return 0;
55}
56
57FILE *safe_fopen(char *ime, char *rezim, int kod_greske) {
58 FILE *fp = fopen(ime, rezim);
59
60 if(fp == NULL) {
61 printf("Greska prilikom otvaranja %s datoteke!\n", ime);
62 exit(kod_greske);
63 }
64
65 return fp;
66}
67
68void ucitaj_kartice(FILE *pulazna, KARTICA **pglava) {
69 char tmp_ime[MAX_IME];
70 char tmp_prezime[MAX_PREZIME];
71 char tmp_broj_kartice[MAX_BROJ_KARTICE];
72
73 while(fscanf(pulazna, "%s %s %s",
74 tmp_ime,
75 tmp_prezime,
76 tmp_broj_kartice) != EOF) {
77 KARTICA *novi = napravi_cvor(
78 tmp_ime,
79 tmp_prezime,
80 tmp_broj_kartice);
81 dodaj_na_kraj(pglava, novi);
82 }
83
84}
85
86void ispisi_kartice(FILE *izlazna_validni, FILE *izlazna_nevalidni, KARTICA *glava,
87 int *pbroj_validnih, int *pbroj_nevalidnih) {
88 KARTICA *tekuci = glava;
89 FILE *izlazna;
90 int validan_broj;
91
92 while(tekuci != NULL) {
93 if(provera_broja(tekuci->broj_kartice)) {
94 izlazna = izlazna_validni;
95 (*pbroj_validnih)++;
96 } else {
97 izlazna = izlazna_nevalidni;
98 (*pbroj_nevalidnih)++;
99 }
100
101 fprintf(izlazna, "%-8s %-11s %s\n", tekuci->ime, tekuci->prezime, tekuci->broj_kartice);
102
103 tekuci = tekuci->sledeci;
104 }
105}
106
107void inicijalizacija(KARTICA **pglava) {
108 *pglava = NULL;
109}
110
111KARTICA *napravi_cvor(char *ime, char *prezime, char *broj_kartice) {
112 KARTICA *novi = (KARTICA *)malloc(sizeof(KARTICA));
113
114 if(novi == NULL) {
115 printf("Greska prilikom zauzimanja memorije!\n");
116 exit(2);
117 }
118
119 strcpy(novi->ime, ime);
120 strcpy(novi->prezime, prezime);
121 strcpy(novi->broj_kartice, broj_kartice);
122 novi->sledeci = NULL;
123
124 return novi;
125}
126
127void dodaj_na_kraj(KARTICA **pglava, KARTICA *novi) {
128 if(*pglava == NULL) {
129 *pglava = novi;
130 } else {
131 KARTICA *tekuci = *pglava;
132
133 while(tekuci->sledeci != NULL) {
134 tekuci = tekuci->sledeci;
135 }
136
137 tekuci->sledeci = novi;
138 }
139}
140
141void obrisi_listu(KARTICA **pglava) {
142 KARTICA *tmp;
143
144 while(*pglava != NULL) {
145 tmp = *pglava;
146 *pglava = (*pglava)->sledeci;
147 tmp->sledeci = NULL;
148 free(tmp);
149 }
150}
151
152int provera_broja(char *broj_kartice) {
153 int i, duzina = strlen(broj_kartice), suma = 0, je_drugi = 0;
154
155 for(i = duzina - 1;i >= 0;i--) {
156 int broj = broj_kartice[i] - '0';
157
158 if(je_drugi) {
159 broj *= 2;
160 }
161
162 // ako je broj dvocifren, ovo ce pomoci da se dobiju sume njegovih cifara (npr. 18 -> 1 + 8)
163 // ako je jednocifren, broj / 10 ce biti 0, a broj % 10 ce biti sam broj
164 suma += broj / 10;
165 suma += broj % 10;
166
167 je_drugi = !je_drugi;
168 }
169
170 return suma % 10 == 0;
171}