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
|
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
const int MAX_NAME_SZ = 127 ;
char* get_student( char name[MAX_NAME_SZ+1] ) // get name from user input
{
std::cout << "enter name (max " << MAX_NAME_SZ << " characters): " ;
std::cin >> std::ws ; // skip white space (this also skips empty lines)
std::cin.getline( name, MAX_NAME_SZ+1 ) ;
return name ;
}
// get name from user input. buffer is allocated with new[], release it with delete[]
char* get_student() { return get_student( new char[MAX_NAME_SZ+1] {} ) ; }
struct database
{
char** data = nullptr ;
int curr_sz = 0 ; // currently in use
int reserved_sz = 0 ; // max space available
};
void destroy( database& db ) noexcept // release all memory
{
for( int i = 0 ; i < db.curr_sz ; ++i ) delete[] db.data[i] ;
delete[] db.data ;
db.data = nullptr ;
db.curr_sz = db.reserved_sz = 0 ;
}
// TO DO: copy database, assign database
// increase space available to at least new_reserved_sz
void reserve( database& db, int new_reserved_sz )
{
if( db.reserved_sz < new_reserved_sz )
{
// allocate at least double the current allocation and a minimum of 16 bytes
new_reserved_sz = std::max( { db.reserved_sz*2, new_reserved_sz, 16 } ) ;
char** new_buf = new char*[new_reserved_sz] {} ;
// copy items to the new buffer
if(db.data) std::copy( db.data, db.data+db.curr_sz, new_buf ) ;
// release the old buffer and make the database use the new buffer
delete[] db.data ;
db.data = new_buf ;
db.reserved_sz = new_reserved_sz ;
}
}
void add_item( database& db )
{
reserve( db, db.curr_sz+1 ) ; // make sure we have enough space
db.data[db.curr_sz] = get_student() ;
++db.curr_sz ;
}
bool erase( database& db, int pos ) // erase item at position pos
{
if( pos >= 0 && pos < db.curr_sz )
{
delete[] db.data[pos] ; // delete item at pos
db.data[pos] = nullptr ;
// move items after pos to the left
std::move( db.data+pos+1, db.data+db.curr_sz, db.data+pos ) ;
--db.curr_sz ;
return true ;
}
return false ; // invalid pos
}
bool erase( database& db, const char* text ) // erase first item with matching text (case-sensitive)
{
for( int i = 0 ; i < db.curr_sz ; ++i )
if( std::strcmp( db.data[i], text ) == 0 ) return erase( db, i ) ;
return false ; // no match
}
void print( const database& db )
{
std::cout << "--------------------------------\n" ;
for( int i = 0 ; i < db.curr_sz ; ++i )
std::cout << std::setw(4) << i+1 << ". " << db.data[i] << '\n' ;
std::cout << "--------------------------------\n" ;
}
int get_int( const char* prompt, int minv, int maxv ) // get input int in the specified range
{
std::cout << prompt << " [" << minv << ',' << maxv << "]: " ;
int input ;
if( std::cin >> input && input >= minv && input <= maxv ) return input ;
// input failed; clean up and try again
std::cout << "invalid input. try again\n" ;
std::cin.clear() ;
std::cin.ignore( 1'000'000, '\n' ) ;
return get_int( prompt, minv, maxv ) ;
}
enum option { ADD = 1, DELETE = 2, DISPLAY = 3, QUIT = 4 };
option get_option()
{
std::cout << '\n' << ADD << ". Add\n" << DELETE << ". Delete\n"
<< DISPLAY << ". Display\n" << QUIT << ". Quit\n" ;
return option( get_int( "enter choice", ADD, QUIT ) ) ;
}
void process_delete_command( database& db )
{
std::cout << "delete student with name : " ;
char name[MAX_NAME_SZ+1] {} ;
if( erase( db, get_student(name) ) ) std::cout << "erased '" << name << "' from the database\n" ;
else std::cout << "did not find name '" << name << "' in the database\n" ;
}
int main()
{
database db ;
option opt = QUIT ;
while( ( opt = get_option() ) != QUIT )
{
switch(opt)
{
case ADD:
add_item(db) ;
break ;
case DELETE:
process_delete_command(db) ;
break ;
case DISPLAY:
print(db) ;
break ;
case QUIT:
std::cout << "\nbye!\n" ;
}
}
destroy(db) ; // we are done; clean up and quit
}
|