1. Homepage of Dr. Zoltán Porkoláb
    1. Home
    2. Archive
  2. Teaching
    1. Timetable
    2. Bolyai College
    3. C++ (for mathematicians)
    4. Imperative programming (BSc)
    5. Multiparadigm programming (MSc)
    6. Programming (MSc Aut. Sys.)
    7. Programming languages (PhD)
    8. Software technology lab
    9. Theses proposals (BSc and MSc)
  3. Research
    1. CodeChecker
    2. CodeCompass
    3. Templight
    4. Projects
    5. Conferences
    6. Publications
    7. PhD students
  4. Affiliations
    1. Dept. of Programming Languages and Compilers
    2. Ericsson Hungary Ltd

Imperatív programozás 12.

A string- és filekezelő könyvtár használata

Ez alkalommal egy telefonkönyv programot írunk be. Segítségével bemutatjuk a stringkezelés és az alapvető fájlkezelés függvényeit.

Ezt az alkalmazást ad-hoc írtuk meg a hallgatók segítségvel. Lejjebb a 2019-es megvalósítást lehet megtalálni, ami eléggé eltér a 2020-astól.

Implementáció diamikusan növekvő memóriával (2020)

A 2020-as implementáció egy dinamikusan allokált tömböt tartalmaz, ahol elhelyezzük az egyes bejegyzéseket. A bejegyzések (név,telefonszám) pointer párok, magukat a neveket és telefonszámokat dinamikusan allokáljuk, a phonebook tömbben csak a pointer-párok vannak. A bejegyzéseket a nevek szerint növekvő sorrendben tároljuk el.

Beszúráskor megkeressük azt a helyet, ahova az ábécé sorrend szerint el kell helyeznünk az új bejegyzést, a hátrább levő bejegyzéseket egy hellyel hátrébb csúsztatva helyet csinálunk az új bejegyzésnek, és a keletkezett helyre rakjuk az új elemet. Szükség esetén megnöveljük a dinamikus tömböt.

Törlésnél a törlendő elem által mutatott név és telefonszám területeket felszabadítjuk és a mögöttes elemeket feltoljuk a keletkezett “lyuk” helyére.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 1024   /* a maximális parancssor hossza*/
#define DEFAULT_NAME "phonebook.txt" /* default fájlnév*/

void add( char *name, char *phone);
void del( char *name);
void print( char *name);
void help(void);
void clean(void);
void quit(void);
void list(void);
void save(void);
void load(void);
void saveAs( char *fname);
void loadFrom( char *fname);

typedef void (*command_t)(); /* fenti függvények típusa */

struct COMMANDS   /* egy parancsot reprezentáló hármas: */
{
  char      *name;  /* a parancs neve                   */
  command_t  func;  /* végrehajtandó akció: fv. pointer */
  int        npar;  /* a parancs paramétereinek száma   */
};

static struct COMMANDS commands[] = {   /* parancsok */
      {	"add",      add,      2 }, 
      { "del",      del,      1 },
      { "print",    print,    1 },
      { "list",     list,     0 },
      { "save",     save,     0 },
      { "saveAs",   saveAs,   1 },
      { "load",     load,     0 },
      { "loadFrom", loadFrom, 1 },
      {	"clean",    clean,    0 },
      {	"help",     help,     0 },
      {	"quit",     quit,     0 }
};

typedef struct ENTRY  /* egy bejegyzés a telefonkönyvben */
{
  char *name;   /* pointer a dinamikusan allokált névre  */
  char *number; /* pointer a dinamikusan allokált számra */ 
}
entry_t;

int capacity = 0;  /* allokált memória mérete (elemszám) */
int size = 0;  /* ennyi elem van ténylegesen (elemszám)  */
entry_t *phonebook = NULL;  /* ptr a lefoglalt memóriára */

/* a szokásos módszer a tömb elemeinek meghatározására */
static int nComm = sizeof(commands)/sizeof(commands[0]);

/* segédfüggvények */
void grow();           /* megnöveli a lefoglalt memóriát */
int findCommand(char *buffer);
int findParams(char *buffer, int ci, char **p1, char **p2);
entry_t *find( char *name);

int main()
{
  char buffer[BUFSIZE];   
  char *param1;
  char *param2;

  grow();    /* kezdeti memóriafoglalás */
  printf("PB> ");
  while ( fgets( buffer, BUFSIZE, stdin) )   /* EOF-ig */
  {
    int ci = findCommand( buffer); 	  
    if ( -1 != ci && -1 != findParams( buffer, ci, &param1, &param2) )
    {
      /* megtaláltuk a parancsot és paramétereit */
      switch( commands[ci].npar )  /* ennyi paraméteres */
      {
      /* meghívjuk a parancsot a szükséges paraméterekkel */
      case 0: commands[ci].func();                break;
      case 1: commands[ci].func(param1);          break;	      
      case 2: commands[ci].func(param1, param2);  break;	      
      default: fprintf( stderr, "more parameters are "
                       "not implemented yet\n");  break;
      }	       
    }
    printf("PB> ");
  }
  return 0;
}

/* ha capacity == 0, akkor lefoglalja a kezdeti hosszt,
   egyébként kétszeresére növeli a lefoglalt méretet   */ 
void grow(void)
{
  static const int startcap = 4;  /* kezdeti hossz */
  if ( 0 == capacity )  /* első alkalom */
  {
    phonebook = (entry_t *) 
                        malloc(startcap*sizeof(entry_t));
    capacity = startcap;
  }
  else /* lefoglalt memória kétszeresére növelése */
  {
    phonebook = (entry_t *) 
           realloc(phonebook, 2*capacity*sizeof(entry_t));
    capacity *= 2;
  }
  if ( NULL == phonebook ) /* nincsen memória */
  {
    fprintf( stderr, "Out of memory\n");	  
    exit(1);	  
  }
}

/* megkeresi a parancsot a felhasználói inputban és 
   - visszatér a commands tömbbeli indexével
   - vagy -1-el, ha nincsen ilyen parancs            */
int findCommand( char *buffer)
{
  char command[BUFSIZE];

  if  (1 == sscanf(buffer,"%s",command)) /* az első szó */	
  {
    int i;
    for ( i = 0; i < nComm; ++i)  /* keressük a tömbben */
    {
      if ( 0 == strcmp( commands[i].name, command ) )	  
      {
        return i;  /* megtaláltuk az i-edik indexen */
      }
    }
    /* nem találtuk meg */
    printf( "%s: unknown command\n", command);	    
  }
  return -1; /* nem volt parancs vagy ismeretlen */
}

/* megkeresi a ci-ik indexhez tartozó parancs paramétereit,
   ha megtalálja, akkor ráállítja a p1 ill. p2 pointereket,
       és visszaadja a paraméterek számát,
   ha nem találja meg, akkor -1-el tér vissza           */
int findParams( char *buffer, int ci, char **p1, char **p2)
{
  int req = commands[ci].npar;  /* ennyi paraméter kell */
  strtok( buffer, " \t\n");     /* átlépjük a parancsot */

  if ( 0 == req ) /* 0 paraméteres parancs              */
    return 0;         /* készen vagyunk */
  else if ((*p1 = strtok( NULL, " \t\n"))) /* szóhatárig */
  {
   /* sikerül megtalálni az első paramétert, p1 mutat rá */ 
    if ( 1 == req )  /* 1 paraméteres parancs            */
    {
      return 1;      /* készen vagyunk */
    }
    /* további paraméter kell */
    if ((*p2 = strtok( NULL, "\t\n"))) /* ha nincsen ' ' */
    {                 /* az elválasztók között, akkor a  */ 
      return 2;	      /* telefonszámon belül megengedett */
    }                 /* a space karakter használata     */
  }
  /* nem találtuk meg a szükséges paramétereket, hibaüz. */ 
  fprintf( stderr, "usage: %s %s %s\n", commands[ci].name,
       req > 0 ? "name" : "",   /* van első paraméter    */
       req > 1 ? "phone" : ""); /* van második paraméter */
  return -1;
}

/* megkeresi a name első előfordulását a telefonkönyvben,
   ha nem talál ilyet, akkor NULL-al tér vissza          */
entry_t *find(char *name)
{
  int i;
  for ( i = 0; i < size; ++i)
  {
    if ( 0 == strcmp( phonebook[i].name, name) )
      return phonebook+i; /* pointer a bejegyzésre */    
  }  
  return NULL;
}

/* beszúr egy új elemet a név ábécé sorrend szerinti helyé-
   re, a mögöttes elemeket hátramozgatja egy bejegyzéssel, 
   ha szükséges, megnöveli a dinamikus memória méretét   */
void add(char *name, char *number)  
{ 
  int remaining;
  entry_t newEntry;

  int i = 0; 
  /* keressük azt a pozíciót, amely először nagyobb a
     beszúrandó névnél, ha nincs ilyen, akkor a 
     dinamikus tömb végére pozícionálunk */
  while (i < size && 0 >= strcmp(phonebook[i].name,name))
    ++i;  	    	    

  remaining = size - i;	  /* ennyi elem van még hátrébb */
  /* dinamikus helyet foglalunk a névnek és tel. számnak */
  newEntry.name   = (char *) malloc( strlen(name)+1 );
  newEntry.number = (char *) malloc( strlen(number)+1 );
  if ( NULL == newEntry.name  ||  NULL == newEntry.number )
  {
    fprintf( stderr, "Out of memory\n");
    exit(1);
  }  
  strcpy( newEntry.name, name);   /* eltároljuk a nevet  */
  strcpy( newEntry.number,number);/* eltároljuk a számot */
  
  if ( size == capacity )  /* ha teli a dinamikus tömb */
    grow();                /* akkor megnöveljük */

  /* hogy helyet csináljunk az új elemnek hátrébb toljuk az 
     inzertálási pozíció után következő elemeket eggyel  */
  memmove( phonebook+i+1, phonebook+i, 
        /* bájtokban számol */ remaining*sizeof(entry_t));
  ++size;              /* egy elemmel több van eltárolva */
  phonebook[i] = newEntry; /* elemet ténylegesen beírjuk */        
}

/* ha megtaláljuk az elemet, akkor töröljük a dinamikus
   memóriákat, ahol a név, és a telefonszám tárolva volt,
   és feltömörítjük a bejegyzéseket, azaz felcsúsztatjuk 
   a mögöttes elemeket a keletkezett lyuk eltüntetésére */
void del( char *name)
{
  entry_t *ptr = find(name); /* pointer a bejegyzésre */
  if ( NULL == ptr ) /* nincsen ilyen név eltárolva */
  {
    printf( "Del: %s not found\n", name);    
  }
  else /* megtaláltuk */
  {
    /* ennyi elem van a megtalált pozíció után */
    int remaining = (phonebook+size) - ptr;  
    /* felszabadítjuk a dinamikus memóriát */
    free(ptr->name);  
    free(ptr->number);
    /* feltömörítjük a maradék elemeket */
    memmove( ptr, ptr+1, remaining*sizeof(entry_t));
    --size;  /* csökkent az elemek száma */
  }
}

void print( char *name)
{
  entry_t *ptr = find(name);
  if ( NULL == ptr )
  {
    printf( "Print: %s not found\n", name);    
  }
  else
  {
    printf( "%s: %s\n", ptr->name, ptr->number);    
  }
}

void list(void)
{
  int i;
  printf("========================\n");
  for ( i = 0; i < size; ++i)
  {
    printf( "%s: %s\n", phonebook[i].name, 
                        phonebook[i].number);    
  }  
  printf("========================\n");
}

/* töröljük az összes elemet */
void clean()
{
  int i;
  for ( i = 0; i < size; ++i)
  {
    free(phonebook[i].name);
    free(phonebook[i].number);
  }
  free(phonebook);
  capacity = 0;
  size = 0;
}

void save(void)
{
  return saveAs( DEFAULT_NAME); 
}

void load(void)
{
  return loadFrom( DEFAULT_NAME);  
}

void saveAs( char *name)
{
  FILE *fp = fopen( name, "w");
  if ( NULL == fp )
  {
    fprintf( stderr, "Can't open %s for write\n", name);
    return;
  }
  else
  {
    int i;
    for ( i = 0; i < size; ++i )
    {
      fprintf( fp, "%s:%s\n", phonebook[i].name, 
                              phonebook[i].number);	    
    }
    fclose(fp);
  }
}

/* töröljük a kurrens elemeket, beolvasunk egy fájlt és 
   hozzáadjuk ez elemeit az üres telefonkönyvhöz */
void loadFrom( char *name)
{
  FILE *fp = fopen( name, "r");
  if ( NULL == fp )
  {
    fprintf( stderr, "Can't open %s for read\n", name);
    return;
  }
  else
  {
    char buffer[BUFSIZE];
    clean(); /* töröljük a meglevő elemeket */
    while ( fgets(buffer, BUFSIZE, fp) ) /* a fájl sorai */
    {
      /* kéne legyen benne egy ':' karakter */
      char *ptr = strchr(buffer, ':');
      if ( ptr )  /* megtaláltuk */
      {
        char *name   = buffer;  /* a név a ':' előtt  */
	*ptr = '\0';            /* terminálja a nevet */
        char *number = ptr+1;	/* a szám a ':' után  */      
	ptr = strchr( number, '\n'); 
	if ( ptr ) 
          *ptr = '\0'; /* felülírjuk a sorvégi '\n'-t */		
        printf( "add %s %s\n", name, number);	
	add( name, number);  /* hozzáadjuk a könyvhöz */
      }      
      else
      {
        fprintf( fp, "Bad file format %s\n", buffer);
        /* break; nem akarunk továbbmenni hiba esetén */
      }
    }
    fclose(fp);
  }
}

void help() 
{
  int i;
  printf("commands:\n");
  for ( i = 0; i < nComm; ++i)
  {
    printf( "%s %s %s\n", 
		commands[i].name,	  
		commands[i].npar > 0 ? "name" : "",
		commands[i].npar > 1 ? "phone" : "");
  }    
}

void quit(void) 
{ 
  clean(); /* felszámolja a lefoglalt memóriát 
              csak, hogy elemző szoftverek, mint
              valgrind ne adjanak hibajelzést */ 
  exit(0); 
}

Implementáció láncolt listával (2019)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INPUTSIZE  80 /* max input line */
#define DEFAULT_NAME "phonebook.txt" /* default filenév */

/* lista elemek a telefonkönyv bejegyzésekre */
typedef struct ELEM
{
  char        *name; 
  char        *phone;
  struct ELEM *next;  
  struct ELEM *prev;
}
elem_t;

/* maga a telefonkönyv típusa */
typedef struct LIST
{
  elem_t *first;
  elem_t *last;
  int     size;  
}
list_t;

/* a telefonkönyv */
list_t phoneBook = { NULL, NULL, 0};

/* az egyes parancsok fv-re mutató pointer típusa */
typedef int (*comfunc_t)(); 

/* az egyes parancsok */
typedef struct COMMAND
{
  char     *comStr;  /* neve */
  int       nPars;   /* paraméterszáma */
  comfunc_t comFunc; /* a fv pointer */ 
} 
command_t;

/* a parancsok deklarációja */
int help(void);
int quit(void);
int list(void);
int add( char *name, char *phone);
int del( char *name);
int print( char *name);
int save(void);
int saveas( char *fname);
int load(void);
int loadfrom( char *fname);

/* segédfüggvények */
command_t *findCommand( char *buffer);
int findParams( command_t *comPtr, char **pars);
int insert( elem_t *before, char *name, char *phone);
void erase( elem_t *ptr);

/* a parancsok */
static command_t commands[] = {
  { "help",  0, help  },
  { "quit",  0, quit  },
  { "list",  0, list  },
  { "add",   2, add   },
  { "del",   1, del   },
  { "print", 1, print }, 
  { "save",  0, save  },
  { "saveas",1, saveas},
  { "load",  0, load  },
  { "loadfrom", 1, loadfrom }  
};

/* a parancsok száma */
const int nCommands = sizeof(commands)/sizeof(commands[0]);

int main()
{
  char buffer[INPUTSIZE];

  printf("PB> ");
  while ( NULL != fgets( buffer, INPUTSIZE, stdin) )
  {
    command_t *comPtr;	  
    if ( (comPtr = findCommand( buffer)) )	  
    {
      char *pars[2] = { NULL, NULL};	  
      if( findParams( comPtr, pars) )
      {
        switch(comPtr->nPars)
        {
        case 0: comPtr->comFunc();                  break;
        case 1: comPtr->comFunc(pars[0]);           break;		
        case 2: comPtr->comFunc(pars[0], pars[1]);  break;		
        default: /* more par not implemented yet */ break;
        }					  		  
      }	
    }    
    printf("PB> ");
  }
  return 0;
}

command_t *findCommand( char *buffer)
{
  int   i; 
  char *beg = strtok( buffer, " \t\n");

  if ( NULL == beg )    
     return 0; 

  for ( i = 0; i < nCommands; ++i)
  {
    if ( 0 == strcmp( commands[i].comStr, beg) )
    {
      return &commands[i];      
    }	    
  }	  
  fprintf( stderr, "Unknown command: %s\n", buffer);
  return 0;
}

int findParams( command_t *comPtr, char **params)
{
  char  *par1, *par2;	
  if ( 0 == comPtr->nPars )
  {	  
    return 1;	   
  }
  else if ( NULL == (par1 = strtok( NULL, " \t\n")) )
  {
    fprintf( stderr, "Too few parameters: %s NAME\n", 
             comPtr->comStr);
    return 0;     
  }
  else if ( 1 == comPtr->nPars )
  {	   
    params[0] = par1;
    return 1;
  }
  else if ( NULL == (par2 = strtok( NULL, "\t\n")) ) 
  {
    /* space not here, so phone number can include space */
    fprintf( stderr, "Too few parameters: %s NAME PHONE\n", 
             comPtr->comStr);
    return 0;     
  }
  else if ( 2 == comPtr->nPars )
  {
    params[0] = par1;
    params[1] = par2;
    return 1;       
  }	   
  else
  {
    /* more parameters are not implemented yet */    
    return 0;
  }    
}

int help(void)
{
  int i = 0;
  printf( "Usage: command par1 par2\n  commands: ");  
  for ( i = 0; i < nCommands; ++i)
  {
    printf( "%s, ", commands[i].comStr);  
  }	
  printf("\n");
  return 1;
}

int quit(void)
{
  exit(0);
}

int list(void)
{
  elem_t *ptr = phoneBook.first;
  printf("======= entries =======\n");
  while ( ptr )
  {
    printf( "%s:\t%s\n", ptr->name, ptr->phone);
    ptr = ptr->next;    
  }
  printf("=======================\n");
  return 1;
}

int saveas(char *fname)
{
  elem_t *ptr;	
  FILE *fp = fopen( fname, "w"); 
  if ( NULL == fp )
  {
    fprintf( stderr, "Can open %s for write\n", fname);	  
    return 0;
  }
  ptr = phoneBook.first;
  while ( ptr )
  {
    fprintf( fp, "%s:%s\n", ptr->name, ptr->phone);
    ptr = ptr->next;    
  }
  fclose(fp);
  return 1;
}

int save(void)
{
  return saveas( DEFAULT_NAME); 
}

int load(void)
{
  return loadfrom( DEFAULT_NAME);  
}

int loadfrom( char *fname)
{
  char *name;
  char *phone;
  char  buffer[INPUTSIZE];
  FILE *fp = fopen( fname, "r"); 

  if ( NULL == fp )
  {	  
    fprintf( stderr, "Can open %s for read\n", fname);	  
    return 0;
  }
  while ( NULL != fgets( buffer, INPUTSIZE, fp) )
  { 
    if ( NULL == strchr( buffer, ':') )
    {
      fprintf( stderr, "Bad file format: %s\n", buffer);
      return 1;      
    }
    name = strtok( buffer, ":");
    phone = strtok( NULL, "\n");
    add( name, phone);
  }
  return 1;
}

int add(char *name, char*phone)
{
  elem_t *ptr = phoneBook.first;

  while ( ptr )
  {
    if ( 0 == strcmp( ptr->name, name) )
    {	    
      printf( "add: %s already in phonebook\n", name);
      return 0;
    }
    else if ( 0 > strcmp( ptr->name, name) )
    {	    
      ptr = ptr->next;    
    }
    else 
    {
      /* insert before */
      return insert( ptr->prev, name, phone); 
    }	    
  }
  /* insert last */	 
  return insert( phoneBook.last, name, phone); 
}

int insert( elem_t *before, char *name, char *phone)
{      	
  elem_t *newPtr = (elem_t*) malloc(sizeof(elem_t));	    
  if ( NULL == newPtr )
  {
    fprintf(stderr, "add: no memory\n");
    return 0;    
  }
  if ( 0 == phoneBook.size )
  {
    newPtr->next = newPtr->prev = NULL;
    phoneBook.first = phoneBook.last = newPtr;    
  }	  
  else 
  {	  
    newPtr->prev = before;
    newPtr->next = before ? before->next : phoneBook.first;           
    if ( newPtr->prev ) newPtr->prev->next = newPtr; 
    else phoneBook.first = newPtr;
    if ( newPtr->next ) newPtr->next->prev = newPtr; 
    else phoneBook.last = newPtr;      
  }
  ++phoneBook.size;  
  newPtr->name  = (char *) malloc( strlen(name)+1); 
  newPtr->phone = (char *) malloc( strlen(phone)+1); 
  strcpy( newPtr->name,  name);	  
  strcpy( newPtr->phone, phone);
  return 1;
}

void erase( elem_t *ptr)
{
  if ( ptr->prev )
    ptr->prev->next = ptr->next;
  if ( ptr->next ) 
    ptr->next->prev = ptr->prev;
  if ( phoneBook.first == ptr )
    phoneBook.first = ptr->next;  
  if ( phoneBook.last  == ptr ) 
    phoneBook.last  = ptr->prev;  
  --phoneBook.size;
  free(ptr);
}

int del(char *name)
{
  elem_t *ptr = phoneBook.first;

  while ( ptr )
  {
    if ( 0 == strcmp( ptr->name, name) )
    {	    
      free(ptr->name);
      free(ptr->phone);
      erase(ptr);
      return 1;
    }
    ptr = ptr->next;
  }
  printf("del: %s not found\n", name);
  return 1;
}

int print(char *name)
{
  elem_t *ptr = phoneBook.first;

  while ( ptr )
  {
    if ( 0 == strcmp( ptr->name, name) )
    {	    
      printf( "%s:\t%s\n", ptr->name, ptr->phone);
      return 1;
    }
    ptr = ptr->next;
  }
  printf("print: %s not found\n", name);
  return 0;
}