Author Topic: New thread especially for students of C and C++  (Read 98645 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #15 on: March 13, 2009, 09:50:02 AM »
Now backing up some, for beginners in C++ ...

Here are some steps to develop a C++ program using 2-D arrays ... (as a spread sheet) ... that leads up to an OOP version 'class Stock' ... (that attempts to show that C++ classes are a safe way ... instead of using global variables... to get simple function calls.)

This program asks for input ... and then displays all the inventory of shirts.

There are shirts for 6 teams ... and each team has 4 sizes ... small, medium, large and extra-large.  The program shows the totals for each size, for each team, and the grand total of shirts in stock.

Here is a 1st step working shell to get started ...

Code: [Select]
#include <iostream>

using namespace std;

const int NUM_TEAMS = 6; // reset when all debuggin down ...keep small for now
const int NUM_SIZES = 4;
const char header[] = "This program will prompt for the number of shirts "
                      "in stock\n";

// using a global array for simplicity of function calls (for now ...)
int stock[NUM_SIZES][NUM_TEAMS]; // here ... a 4x6 array to keep stock

// function for debugging ...
void show()
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
            cout << stock[i][j] << "  ";
        cout << endl;
    }
}

int main()
{
    cout << header << endl << endl;

    char *shirt_sizes[] = { "small", "medium", "large", "extra-large" };
   
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            cout << "Size " << shirt_sizes[i] << ", enter the number of "
                 << "t-shirts for team " << j+1 << ": " << flush;
            cin >> stock[i][j];
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    show();

    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.sync();
    cin.get();
}

step 2 ... (see comments in program)

Code: [Select]
// part of the formatted output is added in this 2nd step ...
// (we still need to show the sum of each column in our 'output')

// Note: here, we are no-longer using a global array for 'stock' ...
// since we are doing all our work inside main (scope)

#include <iostream>
#include <iomanip>

using namespace std;

const int NUM_TEAMS = 6; // reset when all debuggin down ... keep small for now
const int NUM_SIZES = 4;
const char header[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

int main()
{
    cout << header << endl << endl;
    int stock[NUM_SIZES][NUM_TEAMS]; // here ... a 4x6 array
    char *shirt_sizes[] = { "Small", "Medium", "Large", "X-large" };
   
    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            cout << "Size " << shirt_sizes[i] << ", enter the number of "
                 << "t-shirts for team " << j+1 << ": " << flush;
            cin >> stock[i][j];
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    // show report ...
    int w1=10, w2=6;
    cout << right << setw(21) << " " << "INVENTORY REPORT ...\n\n"
         << right << setw(21) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl << endl;
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << shirt_sizes[i];
        int tot = 0;
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
            tot += stock[i][j];
        }
        cout << setw(w2) << right << tot << endl;
        grand_tot += tot;
    }
   
    cout << "\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl;
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.sync();
    cin.get();
}

Step 3 ...

Code: [Select]
// Here ... we add the function to sum the columns 'sumCols( colNum )'
// and we add this new output when we show the report ...

#include <iostream>
#include <iomanip>

using namespace std;

const int NUM_TEAMS = 6; // reset when all debuggin down ... keep small for now
const int NUM_SIZES = 4;
const char header[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// placed in global scope (to avoid having to pass a 2-D array to functions)
int stock[NUM_SIZES][NUM_TEAMS]; // here ... a 4x6 array

int sumCols( int colNum )
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += stock[row][colNum];
    }
    return sum;
}



int main()
{
    cout << header << endl << endl;

    char *shirt_sizes[] = { "Small", "Medium", "Large", "X-large" };
   
    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            cout << "Size " << shirt_sizes[i] << ", enter the number of "
                 << "t-shirts for team " << j+1 << ": " << flush;
            cin >> stock[i][j];
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    // show report ...
    int w1=10, w2=6;
    cout << right << setw(21) << " " << "INVENTORY REPORT ...\n\n"
         << right << setw(21) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl << endl;
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << shirt_sizes[i];
        int tot = 0;
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
            tot += stock[i][j];
        }
        cout << setw(w2) << right << tot << endl;
        grand_tot += tot;
    }
   
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        cout << setw(w2) << sumCols(j);
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl;
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.sync();
    cin.get();
}

Step 4a ...

Code: [Select]
// This (potentially) final version, shows a syntax to pass 2-D arrays ...
// (so array is NOT in global scope here ... ( it has 'main' scope )

// NOTE: the attempt here to use 'automatic-self-formatting' ... if the
// program main data structure, a 2D array, were to have its dim's updated
// for a new 'store' ...

// NOTE: the use of more fully descriptive names for all variables, as an aid to
// 'self-documentation' ... to also readily SEE the the LOGIC and the top-down
// FLOW of the program ...(You do not have to add/read EXTRA comments, IF the
// variable names are SELF-EXPLAINING ...)

// SINCE ... we are taking in so many integers from the keyboard ...
// We REALLY SHOULD BE validating each number ... so we won't crash ...
// especially ... after entering almost all the data .. and then, to have to
// enter it all perfectly, from the top, AGAIN! ... So, done here to show how.

// Also ... moved 'shirt_sizes' array into global scope,
// (as it really should be there as a const array of C strings),
// but also to make for easy calling from inside the 'getInteger(..)' function,
// as well as calling it from 'main' function.

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

// NOTE: the convention of *consistent use* of ALL_CAPS for GLOBAL_CONSTANTS ...
// so ... each time you SEE_ALL_CAPS in the program ...
// you AUTOMATICALLY_KNOW that  ... that is a GLOBAL_CONST_VAR
const int NUM_SIZES = 4;
const int NUM_TEAMS = 6; // reset when debugging done (keep small for testing)
const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// to sum any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCols( int array[NUM_SIZES][NUM_TEAMS], int colNumber )
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += array[row][colNumber];
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
       
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
   
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{
    // recall ... 'seeing' all_caps implies a var like HEADER is a global const
    cout << HEADER << endl << endl;

    // Ok ... HERE is our 'MAIN STORE' of stuff ...
    // using 'const' variables the COMPILER knows their value at COMPILE TIME
    // So this array gets DIM'ED then ... (i.e at COMPILE TIME)
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's

    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    // show report ...
    int w1=10, w2=6, w3=21;
    // On each line below ... first space over ... w3-6, and w3 spaces ...
    // Need to 'play with spacing' to get it 'just right' for each program,
    // (especially if the number of col's in an array is variable ... NOT, as
    //  in the case here.  But if the global const (and array size) were to be
    // adjusted, then this 'play with spacing' would need to also be re-done.)
    // It is sometimes possible to use 'calulations' in a running program
    // to auto-matically ... space and format appropriately ... if data
    // structure sizes are 'updated' in a new version of a program ...
    // The rudiments, of this, were attemted here, via using w1, w2, w3 var's
    // which can easily change all the relevant formatting they control ...
    // by just changing the one parameter value ...
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
   
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        int tot = 0;
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
            tot += stock[i][j];
        }
        cout << setw(w2) << right << tot << endl;
        grand_tot += tot;
    }
   
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function sumCols( aryName, colNumber )
        cout << setw(w2) << sumCols( stock, j);
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl

         << "\nPress 'Enter' to exit ... " << flush;
    //cin.sync(); // not needed here ... since we 'flushed' in each 'getInteger'
    cin.get();
}

... and 4b

Code: [Select]
// ** Just to show we can leave off the first Dimension **
// ** (in the header line), when passing 2-D arrays **
// Just one functional change here ... See the header line 20 lines below
// with this comment: ** ..... see above ..... **

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// to sum any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCols( int array[][NUM_TEAMS], int col ) // ** ..... see above ..... **
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += array[row][col];
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
       
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
   
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{
    // recall ... 'seeing' all_caps implies a var like HEADER is a global const
    cout << HEADER << endl << endl;

    // Ok ... HERE is our 'MAIN STORE' of stuff ...
    // using 'const' variables the COMPILER knows their value at COMPILE TIME
    // So this array gets DIM'ED then ... (i.e at COMPILE TIME)
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's

    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    // show report ...
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
   
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        int tot = 0;
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
            tot += stock[i][j];
        }
        cout << setw(w2) << right << tot << endl;
        grand_tot += tot;
    }
   
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function sumCols( aryName, colNumber )
        cout << setw(w2) << sumCols( stock, j);
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl

         << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}

Continued on the next page ...
« Last Edit: March 13, 2009, 11:10:39 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #16 on: March 13, 2009, 10:17:11 AM »
And 4typedef ...

Code: [Select]
// This demo's 'the ease' available in C/C++ by using typedef ...
// see the 4 places in this progran marked // *** // below ...

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6; // reset when all debugging done (keep small for testing)

// Now .. Grid2D specifies a 4x6 2-D array of int's
typedef int Grid2D[NUM_SIZES][NUM_TEAMS]; // *** // (0)

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
typedef char* CString; // *** // (1)
const CString SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// to sum any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCols( Grid2D grid, int col ) // *** // (2)
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += grid[row][col];
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
       
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
   
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{
    // recall ... 'seeing' all_caps implies a var like HEADER is a global const
    cout << HEADER << endl << endl;

    // Ok ... HERE is our 'MAIN STORE' of stuff ...
    // using 'const' variables the COMPILER knows their value at COMPILE TIME
    // So this array gets DIM'ED then ... (i.e at COMPILE TIME)

    Grid2D stock; // ... as a 4x6 array of int's // ** // (3)

    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
    // show report ...
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
   
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        int tot = 0;
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
            tot += stock[i][j];
        }
        cout << setw(w2) << right << tot << endl;
        grand_tot += tot;
    }
   
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function sumCols( aryName, colNumber )
        cout << setw(w2) << sumCols( stock, j);
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl

         << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}

Step 5a ...

Code: [Select]
// A demo using a total functional approach  ... (for demo purposes)
// But sometimes, (as demo'd here), using functions is NOT really so efficent.

// Note: here, in our function headers, we elect to provide ONLY the minimum
// info necessary to the compiler, at compile time, when passing a 2-D array ...
// i.e. we leave the first 2-D array dimension empty ...
// ( as per the new header shown below ... )

// int sumCol( int array[][NUM_TEAMS], int numRows, int col )

// We can now pass in the number of rows at *RUN time* ...
// This function is now more portable with one more run time variable that
// can be altered by the running program.

// If we consider a 2-D array as a 'spread-sheet' ...
// One might like functions to ...
// 1. sum down a col (which function we did in the last program)
// 2. sum across a row (which we did in the previous versions during output)
// 3. sum all ... (which we did during output in the previous versions)

// Here we will demo an implementation of 2. ...
// (and remove the code that did this before ... during output.)

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;
const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };


// to sum any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCol( int array[][NUM_TEAMS], int numRows, int colNumber )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += array[row][colNumber];
    }
    return sum;
}


// added here in 'xxxStock5a.cpp' ...
// to sum any row in a 2-D array ... the ROW ITSELF is passed in ... and
// the sum is returned ...
int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}


// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
       
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
   
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{
    // recall ... 'seeing' all_caps implies a var like HEADER is a global const
    cout << HEADER << endl << endl;

    // Ok ... HERE is our 'MAIN STORE' of stuff ...
    // using 'const' variables the COMPILER knows their value at COMPILE TIME
    // So this array gets DIM'ED then ... (i.e at COMPILE TIME)
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's

     ///////////////////////////////////////////////////////////////////////////
    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
   
     ///////////////////////////////////////////////////////////////////////////
    // show report ...
    int w1=10, w2=6, w3=21;
    // On each line below ... first space over ... w3-6, and w3 spaces ...
    // Need to 'play with spacing' to get it 'just right' for each program,
    // (especially if the number of col's in an array is variable ... NOT, as
    //  in the case here.  But if the global const (and array size) were to be
    // adjusted, then this 'play with spacing' would need to also be re-done.)
    // It is sometimes possible to use 'calulations' in a running program
    // to auto-matically ... space and format appropriately ... if data
    // structure sizes are 'updated' in a new version of a program ...
    // The rudiments, of this, were attemted here, via using w1, w2, w3 var's
    // which can easily change all the relevant formatting they control ...
    // by just changing the one parameter value ...
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
   
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        int row_tot = sumRow( stock[i], NUM_TEAMS ); // now call function sumRow(..)
        cout << setw(w2) << right << row_tot << endl;
        grand_tot += row_tot;
    }
   
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function sumCols( aryName, numRows, colNumber )
        cout << setw(w2) << sumCol( stock, NUM_SIZES, j);
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl

         << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}

Step 5b ...

Code: [Select]
// A total functional approach ...(but not so efficent for this simple program)

// Treating a 2-D array as a 'spread-sheet' ...

// Recall ... In 'xxxStock5a.cpp' we added the function to sum a row,
// where we passed THAT ROW IT-SELF as a 1-D array to be summed ...

// Close attention may be needed here to grasp this 'simple concept' ...
// In order to sum a column ... can we use a function that gets the column value
// in a particuler row ?
// Yes we can ... That change is added here ... (just to demo a concept).
// We need two new functions ... one is a slightly changed sumCol(...)


#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;
const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };


// added here in 'xxxStock5b.cpp' ... just for 'concept demo' purposes ...
// returns the value in a 1-D array at index = i
int getVal_i( int ary[], int i )
{
    return ary[i];
}


// changed here in 'xxxStock5b.cpp' ... just for 'concept demo' purposes ...
// now calls a function that returns the value of a 1-D array at index specified
// sums any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCol( int array[][NUM_TEAMS], int numRows, int colNumber )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += getVal_i(array[row], colNumber);

    return sum;
}


// added in 'xxxStock5a.cpp' ...
// to sum any row in a 2-D array ... the ROW itself is passed in ... and
// the sum is returned ...
int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}


// uses utility global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
        
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
    
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{
    // recall ... 'seeing' all_caps implies a var like HEADER is a global const
    cout << HEADER << endl << endl;

    // Ok ... HERE is our 'MAIN STORE' of stuff ...
    // using 'const' variables the COMPILER knows their value at COMPILE TIME
    // So this array gets DIM'ED then ... (i.e at COMPILE TIME)
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's

     ///////////////////////////////////////////////////////////////////////////
    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
    
     ///////////////////////////////////////////////////////////////////////////
    // show report ...
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
        
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
    
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    
    int grand_tot = 0;
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call function sumRow(..) ...
        int row_tot = sumRow( stock[i], NUM_TEAMS );
        cout << setw(w2) << right << row_tot << endl;
        grand_tot += row_tot;
    }
    
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function sumCol( aryName, numRows, colNumber )
        cout << setw(w2) << sumCol( stock, NUM_SIZES, j);
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')<< grand_tot << endl

         << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}

Continued on next page ...
« Last Edit: March 13, 2009, 10:31:12 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #17 on: March 13, 2009, 10:24:08 AM »
Step 5c ...

Code: [Select]
// A total functional approach ... (but not so efficent for this simple program)

// Treating a 2-D array as a 'spread-sheet' ...

// Here in 'xxxStock5c.cpp' we will implement the 3rd new function ...
// 'sumAll' the values in our 2-D grid ... a common spread-sheet function also.

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;
const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };


// added in 'xxxStock5b.cpp' ... just for 'concept demo' purposes ...
// returns the value in a 1-D array at index = i
int getVal_i( int ary[], int i )
{
    return ary[i];
}


// changed in 'xxxStock5b.cpp' ... just for 'concept demo' purposes ...
// now calls a function that returns the value of a 1-D array at index specified
// sums any col in a 2-D array ... the col# is passed in, the sum is returned
int sumCol( int array[][NUM_TEAMS], int numRows, int col )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += getVal_i(array[row], col);
        // just a demo to ?help? show that this is the same thing as
        // array[row][col]
        // and that here ... 2-D arrays are just 'an array of arrays' object

    return sum;
}


// added in 'xxxStock5a.cpp' ...
// to sum any row in a 2-D array ... the ROW itself is passed in ... and
// the sum is return ...
int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}


// HERE we add, in 'xxxStock5c.cpp' ... sumAll( ... )
// and the grand sum is returned
int sumAll( int ary[][NUM_TEAMS], int numRows, int numCols )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += sumRow( ary[row], numCols );
    }
    return sum;
}


// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }
       
        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }
   
        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}



int main()
{

     ///////////////////////////////////////////////////////////////////////////
    // show header ...
    cout << HEADER << endl << endl;


     ///////////////////////////////////////////////////////////////////////////
    // our main 'store' to keep all stock ...
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's


     ///////////////////////////////////////////////////////////////////////////
    // take-in info ...
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }


     ///////////////////////////////////////////////////////////////////////////
    // show report ...
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";
         
    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;
   
    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
   
    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( stock[i], NUM_TEAMS ) << endl;
    }
   
    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( stock, NUM_SIZES, j );
    }
   
    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll(stock, NUM_SIZES, NUM_TEAMS ) << endl

         << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}

Step 5d ...

Code: [Select]
// demo of inventory being stored in a 2-D array ...
// a total functional approach ... (potentially final version)

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
const char *SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// function prototypes ...

int getVal_i( int ary[], int i );
int sumCol( int ary[][NUM_TEAMS], int numRows, int col );
int sumRow( int ary[], int numCols );
int sumAll( int ary[][NUM_TEAMS], int numRows, int numCols );
int getInteger( int min, int i, int j );
void updateStock( int ary[][NUM_TEAMS], int numSizes, int numTeams );
void displayAllStockAndTotals( int ary[][NUM_TEAMS], int numSizes, int numTeams );



int main() // ********************* main begin ****************************** //
{
    // show header ...
    cout << HEADER << endl << endl;

    // reserve space for the main 'store' to keep all the stock ...
    int stock[NUM_SIZES][NUM_TEAMS]; // ... as a 4x6 array of int's

    // update stock ...
    updateStock( stock, NUM_SIZES, NUM_TEAMS );

    // show report ...
    displayAllStockAndTotals( stock, NUM_SIZES, NUM_TEAMS  );
   
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
} // ******************************* main ends ****************************** //


// function definitions ...

int getVal_i( int ary[], int i )
{
    return ary[i];
}

int sumCol( int ary[][NUM_TEAMS], int numRows, int col )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += getVal_i(ary[row], col);

    return sum;
}

int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int sumAll( int ary[][NUM_TEAMS], int numRows, int numCols )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += sumRow( ary[row], numCols );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

// take-in info ...
void updateStock( int ary[][NUM_TEAMS], int numSizes, int numTeams )
{
    for( int i=0; i<numSizes; ++i)
    {
        for( int j=0; j<numTeams; ++j)
        {
            ary[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

// display all in stock and all totals ...
void displayAllStockAndTotals( int ary[][NUM_TEAMS], int numSizes, int numTeams )
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < numTeams; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < numSizes; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < numTeams; ++j )
        {
            cout << right << setw(w2) << ary[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( ary[i], numTeams ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < numTeams; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( ary, numSizes, j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll(ary, numSizes, numTeams ) << endl;
}

Step 5dtypedef

Code: [Select]
// This demo helps to show the 'array of array' stucture of 2-D arrays,
// (with the help of 'typedef')

// A demo of inventory being stored in a 2-D array ... using functions
// Here: a store stocks 4 sizes of shirts for each of 6 different team designs

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

// AryTeams NOW specifies a type that is:
// an array of int's with NUM_TEAM elements
typedef int AryTeams[NUM_TEAMS];

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
typedef char* CString;
const CString SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// function prototypes ...

int sumCol( AryTeams ary[], int numRows, int col );
int sumRow( int ary[], int numCols );
int sumAll( AryTeams[], int numRows );
int getInteger( int min, int i, int j );
void takeStock( AryTeams ary[] );
void displayAllStockAndTotals( AryTeams ary[] );



int main() // ********************* main begin ****************************** //
{
    // show header ...
    cout << HEADER << endl << endl;

    // our main 'store' to keep all stock ... (An array of arrays)
    // reserve space for NUM_SIZE elements, each element is an AryTeam
    AryTeams stock[NUM_SIZES];

    // update stock ...
    takeStock( stock );

    // show report ...
    displayAllStockAndTotals( stock );
   
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
} // ******************************* main ends ****************************** //


// function definitions ...

int sumCol( AryTeams ary[], int numRows, int col )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += ary[row][col];
       
    return sum;
}

int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int sumAll( AryTeams ary[], int numRows  )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += sumRow( ary[row], NUM_TEAMS );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

void takeStock( AryTeams ary[] )
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            ary[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

void displayAllStockAndTotals( AryTeams ary[] )
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << ary[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( ary[i], NUM_TEAMS ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( ary, NUM_SIZES, j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll( ary, NUM_SIZES ) << endl;
}
« Last Edit: March 13, 2009, 10:42:14 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #18 on: March 13, 2009, 10:45:51 AM »
Step 5dGlobalArray ...

Code: [Select]
// This demo helps to show the simpilicty that may be obtained sometimes by
// using global variables ...

// A demo of inventory being stored in a 2-D array ... using functions
// Here: a store stocks 4 sizes of shirts for each of 6 different team designs

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

// AryTeams NOW specifies a type that is:
// an array of int's with NUM_TEAM elements
typedef int AryTeams[NUM_TEAMS];

// our main 'store' to keep all stock ... (An array of arrays)
// reserve space for NUM_SIZE elements, each element is an AryTeam
AryTeams stock[NUM_SIZES]; // in Global Scope to make for simple functiom calls

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
typedef char* CString;
const CString SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// function prototypes ...

int sumCol( AryTeams ary[], int numRows, int col );
int sumRow( int ary[], int numCols );
int sumAll( AryTeams ary[], int numRows );
int getInteger( int min, int i, int j );
void takeStock();
void displayAllStockAndTotals();



int main() // ********************* main begin ****************************** //
{
    // show header ...
    cout << HEADER << endl << endl;

    // update stock ...
    takeStock();

    // show report ...
    displayAllStockAndTotals();
   
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
} // ******************************* main ends ****************************** //


// function definitions ...

int sumCol( AryTeams ary[], int numRows, int col )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += ary[row][col];
       
    return sum;
}

int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int sumAll( AryTeams ary[], int numRows  )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += sumRow( ary[row], NUM_TEAMS );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

void takeStock()
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

void displayAllStockAndTotals()
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( stock[i], NUM_TEAMS ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( stock, NUM_SIZES, j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll( stock, NUM_SIZES ) << endl;
}

Step 5dGlobalArraySimpler ...

Code: [Select]
// This demo helps to show the simpilicty that may be obtained sometimes by
// using global variables ...

// A demo of inventory being stored in a 2-D array ... using functions
// Here: a store stocks 4 sizes of shirts for each of 6 different team designs

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

// AryTeams NOW specifies a type that is:
// an array of int's with NUM_TEAM elements
typedef int AryTeams[NUM_TEAMS];

// our main 'store' to keep all stock ... (An array of arrays)
// reserve space for NUM_SIZE elements, each element is an AryTeam
AryTeams stock[NUM_SIZES]; // in Global Scope to make for simple functiom calls

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";

// a utility ragged-array of C strings ... to aid output
typedef char* CString;
const CString SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };

// function prototypes ...

int sumCol( AryTeams ary[], int numRows, int col );
int sumRow( int ary[], int numCols );
int sumAll( AryTeams ary[], int numRows );
int getInteger( int min, int i, int j );
void takeStock();
void displayAllStockAndTotals();



int main() // ********************* main begin ****************************** //
{
    // show header ...
    cout << HEADER << endl << endl;

    // update stock ...
    takeStock();

    // show report ...
    displayAllStockAndTotals();
   
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
} // ******************************* main ends ****************************** //


// function definitions ...

int sumCol( AryTeams ary[], int numRows, int col )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
        sum += ary[row][col];
       
    return sum;
}

int sumRow( int ary[], int numCols )
{
    int sum = 0;
    for( int col=0; col<numCols; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int sumAll( AryTeams ary[], int numRows  )
{
    int sum = 0;
    for( int row=0; row<numRows; ++row )
    {
        sum += sumRow( ary[row], NUM_TEAMS );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

void takeStock()
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

void displayAllStockAndTotals()
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( stock[i], NUM_TEAMS ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( stock, NUM_SIZES, j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll( stock, NUM_SIZES ) << endl;
}

Step 5 class Stock ...

Code: [Select]
// class Stock

// This demo seeks to show the similarity of the previous program, that used
// global variables, and this one, that demo's (global) 'class Stock' ...

// Inventory of shirts, stored in a 2-D array, is managed using a C++ class
// Here: a store stocks 4 sizes of shirts for each of 6 different team designs

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;
const char * SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };
const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";
class Stock
{
public:
    Stock(){} // default constructor
    void takeStock();
    void displayAllStockAndTotals();
private:
    // our main 'store' to keep all stock ... (An array of arrays)
    int stock[NUM_SIZES][NUM_TEAMS];
    // private member functions ...
    int getInteger( int min, int i, int j );
    int sumCol( int col );
    int sumRow( int ary[] );
    int sumAll();
};


int main() // ********************* main begin ****************************** //
{
    cout << HEADER << endl << endl;     // show header ...
    Stock s200903;                      // instantiate a Stock object ...
    s200903.takeStock();                // update stock ...
    s200903.displayAllStockAndTotals(); // show report ...

    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();

} // ******************************* main ends ****************************** //


// private member function definitions ...

int Stock::sumCol( int col )
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
        sum += stock[row][col];
       
    return sum;
}

int Stock::sumRow( int ary[] )
{
    int sum = 0;
    for( int col=0; col<NUM_TEAMS; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int Stock::sumAll()
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += sumRow( stock[row] );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int Stock::getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

// public member function definitions

void Stock::takeStock()
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

void Stock::displayAllStockAndTotals()
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( stock[i] ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
   
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll() << endl;
}
« Last Edit: March 27, 2009, 05:00:47 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #19 on: March 13, 2009, 11:36:43 AM »
Step 5 (last part)

The 'Last Step' ... class Stock ... with a static const member ... (NOTE the syntax for future reference.)

Code: [Select]
// class Stock ... with static member ...

// This demo seeks to show the similarity of the previous program, that used
// global variables, and this one, that demo's (global) 'class Stock' ...

// Inventory of shirts, stored in a 2-D array, is managed using a C++ class
// Here: a store stocks 4 sizes of shirts for each of 6 different team designs

#include <iostream>
#include <iomanip>

using namespace std;

// Globals ...

const char HEADER[] = "This program will prompt for the number of shirts "
                      "in stock\n"
                      "for each of the 4 sizes for each of the 6 teams ...";
const int NUM_SIZES = 4;
const int NUM_TEAMS = 6;

class Stock
{
public:
    Stock(){} // default constructor
    void takeStock();
    void displayAllStockAndTotals();
private:
    // our main 'store' to keep all stock ... (An array of arrays)
    int stock[NUM_SIZES][NUM_TEAMS];
    // private member functions ...
    int getInteger( int min, int i, int j );
    int sumCol( int col );
    int sumRow( int ary[] );
    int sumAll();
    // note the syntax for static const variables ...
    static const char* SHIRT_SIZES[];
};
// static var's MUST be given their inital values 'outside' ...(NOT 'inline')
const char* Stock::SHIRT_SIZES[] = { "Small", "Medium", "Large", "X-large" };


int main() // ********************* main begin ****************************** //
{
    cout << HEADER << endl << endl;     // show header ...
    Stock s200903;                      // instantiate a Stock object ...
    s200903.takeStock();                // update stock ...
    s200903.displayAllStockAndTotals(); // show report ...

    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();

} // ******************************* main ends ****************************** //


// private member function definitions ...

int Stock::sumCol( int col )
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
        sum += stock[row][col];
       
    return sum;
}

int Stock::sumRow( int ary[] )
{
    int sum = 0;
    for( int col=0; col<NUM_TEAMS; ++col )
    {
        sum += ary[col];
    }
    return sum;
}

int Stock::sumAll()
{
    int sum = 0;
    for( int row=0; row<NUM_SIZES; ++row )
    {
        sum += sumRow( stock[row] );
    }
    return sum;
}

// uses global array SHIRT_SIZES ...
int Stock::getInteger( int min, int i, int j )
{
    for( ;; ) // forever loop ... until return a good value ...
    {
        int tmp;
        cout << "For size < " << setw(7) << SHIRT_SIZES[i] << " >, enter "
             << "the number of t-shirts for team " << j+1 << ": " << flush;
        cin >> tmp;
        if( !cin.good() )
        {
            cin.clear(); // clear error flags ...
            cin.sync(); // flush cin stream ...
            cout << "\nBad data entered ... Integers only please.\n" << flush;
            continue; // right now from the top of the for loop ...
        }

        if( tmp < min )
        {
            cout << "\nNumbers must be greater than " << min << " ...\n" << flush;
            cin.sync(); // flush cin stream ...
            continue; // right now from the top of the for loop ...
        }

        // if we reach here ... an integer was entered as the first
        // non-whitespace char's ... so ... first
        cin.sync(); // 'flush' ....
        return tmp; // return the good number
    }
}

// public member function definitions

void Stock::takeStock()
{
    for( int i=0; i<NUM_SIZES; ++i)
    {
        for( int j=0; j<NUM_TEAMS; ++j)
        {
            stock[i][j] = getInteger( 0, i, j ); // valid numbers 0,1,2, ...
        }
        cout << endl; // to space out each 'size' entry ...
    }
}

void Stock::displayAllStockAndTotals()
{
    int w1=10, w2=6, w3=21;
    cout << right << setw(w3-6) << " " << "*** Shirt Inventory Report ***\n\n"
         << right << setw(w3) << " " << "Team-College-Number\n\n";

    cout << left << setw(w1) << "Size"
         << right;
    for( int i = 0; i < NUM_TEAMS; ++i )
    {
        cout << setw(w2) << i+1;
    }
    cout << setw(w2) << "Total" << endl;

    // now ... print a solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');

    for( int i = 0; i < NUM_SIZES; ++i )
    {
        cout << left << setw(w1) << SHIRT_SIZES[i]; // *all_caps* => 'global const'
        for( int j = 0; j < NUM_TEAMS; ++j )
        {
            cout << right << setw(w2) << stock[i][j];
        }
        // now call call our function to sum this 'ith' row ...
        cout << setw(w2) << right << sumRow( stock[i] ) << endl;
    }

    // now ... print the same (as above) solid line divider ...
    cout << setw(52) << setfill('_') << '_' << endl << setfill(' ');
    cout << endl << left << setw(w1) << "Team total"
         << right;
    for( int j = 0; j < NUM_TEAMS; ++j )
    {
        // now call function to sum the 'jth' col ...
        cout << setw(w2) << sumCol( j );
    }

    cout << "\n\nThe grand total of shirts in stock is "
         << right << setw(14) << setfill('.')
         // now call the function to sum All ...
         << sumAll() << endl;
}

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #20 on: March 25, 2009, 12:11:01 PM »
And while we are at 'class' ... and static (variable) or const static class members ...

Here is a class Time and (extended) class ExtTime that stores the time zones (PST, MST, CST, EST) ... that shows how the extended class ExtTime INHERITS the protected and public members of class Time ...

Code: [Select]
// class Time, class ExtTime, also demos a (const) static class member

// this version 2010-05-23

#include <iostream>
#include <string>
#include <cstdlib> // re. exit

void myAssert( bool condition, char text[] )
{
    if( !condition )
    {
        std::cerr << text <<  "\nPress 'Enter' to exit ... " << std::flush;
        std::string dummy;
        getline( std::cin, dummy );
        exit(1);
    }
}

int getInt( char prompt[], int max );

class Time
{
public:
    Time(int h=0, int m=0);
    void setHour();     //sets hour from keyboard ...
    void setMinute();   //sets minute from keyboard ...
    int getHour() { return hour; }
    int getMinute() { return minute; }
    void incHour();
    void incMinute();
    void printTime();

protected: //these are 'only protected' so that they will be known in 'ExtTime'
    int hour, minute;

    void normalize(); // 'protected' as they are used ONLY BY 'Time' & 'ExeTime'
};

class ExtTime : public Time
{
public:
    ExtTime(int h=0, int m=0, std::string z="EST");
    void setZone(); //sets zone from keyboard ...
    void printTime();
    void printAll4RelativeTimes();

private:
    std::string zone;
    const static std::string myZones[];// = { "EST", "CST", "MST",  "PST" };
};

// Note: static members MUST be initialed OUTSIDE the class header declarations
const std::string ExtTime::myZones[] = { "EST", "CST", "MST",  "PST" };

int main() // * * * * * * * * * * * * MAIN BEGINS * * * * * * * * * * * * * * //
{
    using std::cout;
    using std::endl;
    using std::flush;
    using std::cin;

    cout << "Testing ExtTime ...\n";
    ExtTime tx;
    tx.setHour();
    tx.setMinute();
    tx.setZone();
    tx.printTime(); cout << endl;
    tx.printAll4RelativeTimes(); cout << endl;

    ExtTime tz(123, 759, "CST");
    tz.printTime(); cout << endl;
    tz.printAll4RelativeTimes(); cout << endl;

    cout << "\nTesting Time ...\n";
    Time myTime(13, 59+60*10+1); cout << endl;
    myTime.printTime(); cout << endl;

    myTime.setHour();
    myTime.setMinute();
    int h = myTime.getHour();
    int m = myTime.getMinute();
    cout << "The hour is " << h << " and the minute is " << m << endl;
    myTime.printTime(); cout << endl;

    myTime.incHour();
    myTime.incMinute();
    cout << "The time after adding 1 hour and 1 minute is\n";
    myTime.printTime();

    cout << "\n\nPress 'Enter' to exit ... " << flush;
    cin.sync();
    cin.get();
}// * * * * * * * * * * * * * * * * * MAIN ENDS * * * * * * * * * * * * * * * //


Time::Time(int h, int m) : hour(h), minute(m)
{
    normalize();
}

ExtTime::ExtTime(int h, int m, std::string z) : Time(h, m), zone(z)
{
    normalize();
}

void ExtTime::setZone()
{
    using std::cout;
    using std::endl;
    using std::flush;
    using std::cin;

    for( ;; ) // loop forever ... until 'return' with a good 'zone'
    {
        cout << "Enter zone: " << flush;
        zone = "";
        getline( cin, zone );

        //if( zone=="EST" || zone=="CST" || zone=="MST" || zone=="PST" ) break;
        for( int i = sizeof myZones/sizeof myZones[0] -1; i >=0 ; --i )
        {
            if( zone == myZones[i] ) return; // exit this function right now ...
        }

        // if reach here ... an invalid zone was entered ...

        //cout <<"Valid zones are EST, CST, MST, PST ..." << endl;
        cout <<"Valid zones are ";
        int i;
        for( i = sizeof myZones/sizeof myZones[0] -1; i >0 ; --i )
            cout << myZones[i] << ", ";
        cout << myZones[i] << endl;
    }
}

void Time::setHour()
{
    hour = getInt("Enter the hour", 23);
}

void Time::setMinute()
{
    minute = getInt("Enter the minute", 59);
}

void Time::incHour()
{
    ++hour;
    normalize();
}

void Time::incMinute()
{
    ++minute;
    normalize();
}

void Time::printTime()
{
    using std::cout;
    cout << "The time is ";
    if(hour<10) cout << "0";
    cout << hour << ":";
    if(minute < 10) cout << "0";
    cout << minute;
}

void ExtTime::printTime()
{
    Time::printTime();
    std::cout << " " << zone << std::endl;
}

void ExtTime::printAll4RelativeTimes()
{
     // Note: the presumption here is that the ZONES are already validated on
     // input ... and are ONE of the known zones in the following array 'myZones'
    int baseZoneIndex;
    //std::string myZones[] = { "EST", "CST", "MST",  "PST" };
    for( int i = sizeof myZones/sizeof myZones[0] -1; i >=0 ; --i )
        if( zone == myZones[i] )
        {
            baseZoneIndex = i;
            break;
        }
    // Ok ... we have the base zone index ... It must be ONE of 0, 1, 2 or 3

    int PST_hour = hour - 3 + baseZoneIndex;
    if( PST_hour < 0 ) PST_hour += 24;

    Time tmp( PST_hour, minute );

    // Now ... print out all the times ... indicating the current 'local' zone
    for( int i = sizeof myZones/sizeof myZones[0] -1; i >=0 ; --i )
    {
        tmp.Time::printTime();
        std::cout << " " << myZones[i];
        if( i == baseZoneIndex ) std::cout << " *local time* ";
        std::cout << std::endl;
        tmp.incHour();
    }
}

void Time::normalize()
{
    myAssert( (hour >= 0 && minute >= 0),
              "Error: invalid negative values ... ");
    hour += minute/60;
    minute = minute%60;
    hour = hour%24;
}

int getInt( char prompt[], int max )
{
    using std::cout;
    using std::flush;
    using std::cin;
    for( ;; ) // loop forever ... until return with a valid value ...
    {
        int tmpInt;
        cout << prompt << " : " << flush;
        cin  >> tmpInt;
        if( cin.good() && 0 <= tmpInt && tmpInt <= max )
        {
            cin.sync(); // flush cin ... and then ...
            return tmpInt; // return a valid value ...
        }
        // else ... if reach here ... have an invalid value ...
        cin.clear(); // clear error flags ... if any
        cin.sync(); // flush cin stream ...
        cout << "Valid input in range 0.." << max << " ... ";
    }
}

Or just some simpler class Time, Date ... or DateTime ... ( that shows some simple inheritance )

Code: [Select]
// this version 2010-05-17

#include <iostream>

using namespace std;

class Time //////////////////////// TIME ///////////////////////////////////////
{
public:
    Time(int hour=0, int minute=0);
    int get_hr() const;
    int get_min() const;
    void set_min(int hour);
    void set_hr(int minute);
    void print() const;
protected:
    int hr;
    int min;
};

Time::Time(int hour, int minute) : hr(hour), min(minute) {}
int Time::get_hr()const { return hr; }
int Time::get_min()const { return min; }
void Time::set_hr(int hour) { hr = hour; }
void Time::set_min(int minute) { min = minute; }
void Time::print() const
{
    if (hr < 10)  cout << "0";
    cout << hr << ":";
    if (min < 10) cout << "0";
    cout << min;
}

class Date //////////////////////// DATE ///////////////////////////////////////
{
public:
    Date(int year=2000, int month=1, int day=1);
    int get_y() const;
    int get_m() const;
    int get_d() const;
    void set_y(int year);
    void set_m(int month);
    void set_d(int day);
    void print() const;
protected:
    int y;
    int m;
    int d;
};

Date::Date(int year, int month, int day) : y(year), m(month), d(day) {}
int Date::get_y() const { return y; }
int Date::get_m() const { return m; }
int Date::get_d() const { return d; }
void Date::set_y(int year) { y = year; }
void Date::set_m(int month) { m = month; }
void Date::set_d(int day) { d = day; }
void Date::print() const
{
    if (y<9)  cout << "200";
    else if (y<99) cout << "20";
    else if (y<999) cout << "2";
    cout << y << "-";
    if (m < 10) cout << "0";
    cout << m << "-";
    if (d < 10) cout << "0";
    cout << d;
}

class DateTime : public Date, Time ////////////////// DATETIME /////////////////
{
public:
    DateTime(int year=2000, int month=1, int day=1, int hour=0, int minute=0);
    void print() const;
};

DateTime::DateTime(int year, int month, int day, int hour, int minute)
: Date(year, month, day), Time(hour, minute) {}
void DateTime::print() const
{
    Date::print();
    cout << " ";
    Time::print();
}

int main() //////////////////////////// MAIN ///////////////////////////////////

{
    Date newYearsDay2008(2008,1,1);
    cout << "New Year's Day 2008 was ";
    newYearsDay2008.print();

    // default constructor ...
    Time newYearsTime2008;
    cout << "\n\nNew Year's Time 2008 was ";
    newYearsTime2008.print();

    Date momsDay(2008,5,11);
    cout << "\n\nMother's Day 2008 was ";
    momsDay.print();
    
    DateTime newBirth(1982, 6, 11, 11, 0);
    cout << "\n\nNew Birth Event 1982 was ";
    newBirth.print();
  
    cout << "\n\nPress 'Enter' to continue ... " << flush;
    cin.get();
}
« Last Edit: May 24, 2010, 02:02:09 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #21 on: March 25, 2009, 12:35:44 PM »
Carrying on class ... now it's time to demo polymorphism and virtual class members ... (also the old C way of random file read/write of a fixed record size ... just so that you can say ... you did 'see it') ...

This project will first be presented as a driver (main) function ... Then, the xxx.h files will be listed in the same order as they are called, (and loaded into the driver file memory space - before being compiled ALL together)  ...with the driver main function file stuff ...

This is a mini data base (start) with random access binary files for an Insurance Brokerage ... that records Client (personal) info ... and Insurance (common stuff) Info ...  for all 3 (polymorph) types of insurance sold ... Home, Auto and Life.  Notice how the virtual methods/(functions) are included (higher up ... in class Insurance) so that they can be called from there, via a pointer, to point to the particular get/set info function needed for Home, Auto or Life ... Insurance

virtual void setAllInfo() =0;
   
virtual void showAllInfo() =0;

The classes Home, Auto, Life each inherit class Insurance ... and class Insurance inherits class Client ... and class Date is used to hold insurance policy start and stop dates.

There are some utility functions that I may yet incorporate as protected member functions in class Client (at the top of the hierarchy ... so that these functions can be used where needed in the other 'lower down' classes ...


Code: [Select]
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
//#include <cstring>
#include <cstdlib>

using namespace std;

const char* POLY_TYPE[] = { "HOME", "AUTO", "LIFE" };
const char* FILE_NAME[] = {"HomeData.dat", "AutoData.dat", "LifeData.dat" };
void showAllInFile( int );
int ranRead( int, int );

#include "ok_more_getPosInt_getStr.h"
#include "date.h"
#include "cli_ins_hom_aut_lif.h"


int main() //////////////////////// MAIN ///////////////////////////////////////
{
int position;
int choice;
int iType;

    // if file does not exist ... then create an empty file ...

    for(int i= 0; i<3; ++i )
    {
        ifstream fin( FILE_NAME[i], ios::in |ios::binary );
    if( !fin )
    {
            ofstream fout( FILE_NAME[i], ios::out |ios::binary );
            fout.close();
        }
        else
        {
            fin.close();
            cout << POLY_TYPE[i] << " accounts presently on file ...\n";
            showAllInFile(i);
        }
    }

    cout << ":::::TAKE-IN-INFO-LOOP:::::\n\n";
    do
    {
        iType = getPosInteger
        ( "Insurance Type (1=Home, 2=Auto, 3=Life, 4=Exit-Input-Loop): ", 0 );

        if( iType == 4) break;
        if( iType<1 || iType>3 ) continue;

        Home H; MotorVehicle M; Life L; Insurance* Ins;
        if( iType == 1 ) Ins = &H;
        else if( iType == 2 ) Ins = &M;
        else if( iType == 3 ) Ins = &L;

        int pNum =  getPosInteger( "Enter Policy Number: ", 0 );
        position = ranRead( pNum, iType );
    if( position )
        {
            cout << "The policy number already exists at position "
                 << position << endl;
            continue;
        }

        Ins->setPolicyNum( pNum );
        Ins->setPolicyType( iType );

        do{ Ins->setAllInfo(); }while( !ok() );
        do{ Ins->setAllInsInfo(); }while( !ok() );
        do{ Ins->setAllClientInfo(); }while( !ok() );

        cout << "\n\nYOUR INFORMATION WILL NOW BE SAVED ... \n";

        ofstream fout( FILE_NAME[iType-1], ios::in | ios::binary | ios::ate );
        if( iType == 1 )
            fout.write(reinterpret_cast <const char *>(&H),sizeof(H));
        else if( iType == 2 )
            fout.write(reinterpret_cast <const char *>(&M),sizeof(M));
        else if( iType == 3 )
            fout.write(reinterpret_cast <const char *>(&L),sizeof(L));
        fout.close();
        cout << "Was saved ok ... " << endl;

    }while( more() );

    cout << "\n:::::SEARCH-FOR-LOOP:::::\n\n";
    do
    {
        iType = getPosInteger
        ("Policy Number Lookup (1=Home, 2=Auto, 3=Life, 4=Exit-Look-Up-Loop): ",
          0);
        if( iType == 4 ) break;
        if( iType<1 || iType>3 ) continue;

        int tmpPolicyNum = getPosInteger( "Policy Number to view details: ", 0 );
        position = ranRead( tmpPolicyNum, iType );
        if(position) cout << " ... Found at 'position' " << position << endl;
    }while( more() );

} /////////////////////////////// END MAIN /////////////////////////////////////


void showAllInFile(int i)
{
    Insurance* Ins; Home H; MotorVehicle M; Life L;
    if( i < 0 || i > 2 ) return ;

    if( i == 0 ) Ins = &H;
    else if( i == 1 ) Ins = &M;
    else if( i == 2 ) Ins = &L;

    ifstream fin( FILE_NAME[i], ios::in |ios::binary );

    if( i == 0 )
        fin.read(reinterpret_cast <char*> (&H), sizeof(H));
    else if( i == 1 )
        fin.read(reinterpret_cast <char*> (&M), sizeof(M));
    else if( i == 2 )
        fin.read(reinterpret_cast <char*> (&L), sizeof(L));


    while( fin && !fin.eof() )
    {
        Ins->showAllClientInfo();
        Ins->showAllInsInfo();
        Ins->showAllInfo();
        cout << endl;

        if( i == 0 )
            fin.read(reinterpret_cast <char*> (&H), sizeof(H));
        else if( i == 1 )
            fin.read(reinterpret_cast <char*> (&M), sizeof(M));
        else if( i == 2 )
            fin.read(reinterpret_cast <char*> (&L), sizeof(L));
    }
    fin.close();
    cout << endl;
}

// returns position 1...n   OR   0 if not found
int ranRead( int PolicyNum, int iType )
{
    int position=0;

    ifstream fin( FILE_NAME[iType-1], ios::in |ios::binary );
    if( !fin )
    {
        cerr << "File " << FILE_NAME[iType-1]
             << " Not Found ... Press 'Enter' to continue ... " << flush;
        cin.sync();
        cin.get();
        exit(1);
    }

    bool found = false;
    Insurance* Ins; Home H; MotorVehicle M; Life L;
    if( iType == 1 )
    {
        Ins = &H;
        fin.read(reinterpret_cast <char*> (&H), sizeof(H));
        while( fin && !fin.eof() )
        {
            if(Ins->getPolicyNum() == PolicyNum)
            {
                position = fin.tellg()/sizeof(H);
                found = true;
                break;
            }
            fin.read(reinterpret_cast <char*> (&H), sizeof(H));
        }
    }
    else if( iType == 2 )
    {
        Ins = &M;
        fin.read(reinterpret_cast <char*> (&M), sizeof(M));
        while( fin && !fin.eof() )
        {
            if(Ins->getPolicyNum() == PolicyNum)
            {
                position = fin.tellg()/sizeof(M);
                found = true;
                break;
            }
            fin.read(reinterpret_cast <char*> (&M), sizeof(M));
        }
    }
    else if( iType == 3 )
    {
        Ins = &L;
        fin.read(reinterpret_cast <char*> (&L), sizeof(L));
        while( fin && !fin.eof() )
        {
            if(Ins->getPolicyNum() == PolicyNum)
            {
                position = fin.tellg()/sizeof(L);
                found = true;
                break;
            }
            fin.read(reinterpret_cast <char*> (&L), sizeof(L));
        }
    }

    if( !found )
    {
        cout << "\nRecord Not Found!!\n";
    }
    else
    {
        Ins->showAllClientInfo();
        Ins->showAllInsInfo();
        Ins->showAllInfo();
        cout << endl;
    }

    return position;
}
« Last Edit: March 27, 2009, 03:14:49 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #22 on: March 25, 2009, 12:43:14 PM »
Now ... the xxx.h files ... in the order that they are loaded into the driver main function (as per above program) ...

Code: [Select]
// ok_more_getPosInt_getStr.h


bool more() // defaults to 'yes'
{
    std::cout << "\nMore ... (y/n) ? " << std::flush;
    int reply = std::cin.get();
    std::cin.sync();
    return( !(reply=='n' || reply=='N') );
}

bool ok() // defaults to 'no'
{
    std::cout << "\nOk ... (y/n) ? " << std::flush;
    int reply = std::cin.get();
    std::cin.sync();
    return( reply=='y' || reply=='Y' );
}

int getPosInteger( char* prompt, int min ) // returns a 'valid' integer greater than 'min'
{
    int tmp;
    for( ;; ) // loop forever ... until return a valid value ...
    {
        std::cout << prompt << std::flush;
        tmp = -1;
        std::cin >> tmp;
        if( !std::cin.good() || tmp <= min )
        {
            std::cin.clear(); // clear arror flag (if any) ...
            std::cin.sync(); // flush cin stream ...
            std::cout << "\nError! Enter integers greater than " << min
                      << " only: " << std::endl;
            continue; // continue right now from the top of the forever loop ...
        }

        // else if reach here ...
        std::cin.sync();
        return tmp; // return a valid value ...
    }
}

void getStr( char buf[], int max )
{
    for( ;; )
    {
        std::string tmp;
        getline( std::cin, tmp );
        if( tmp.length() < max ) // copy into c[]
        {
int i;
            for(i=0; i<(int)tmp.length(); ++i) buf[i] = tmp[i];
buf[i] = 0; // null terminate
            return;
        }

        //else ... if reach here ... the string input was too loog ... so
        std::cout << std::setw(max-1) << std::setfill('x') << 'x'
                  << std::setfill(' ')
                  << " Max " << max-1 << " characters ... try again:"
                  << std::endl;
    }
}



Code: [Select]
// "date.h"

class Date
{
private:
int day;
int month;
int year;
public:
Date(); //set all data to zero
Date (int d, int m, int y);
Date (Date&); //copy constructor -  copies a date
~Date(); // destructor

//accessors
int getDay();
int getMonth();
int getYear();

//mutators
void setDay(int d);
void setMonth(int m);
void setYear(int y);

void showDate();
};


Date:: Date() //default constructor
{
day = 0;
month = 0;
year = 0;
}

Date:: Date(int d, int m, int y) //primary constructor
{
day = d;
month = m;
year = y;
}

Date:: Date(Date& d) //copy construtor
{
day = d.day;
month = d.month;
year = d.year;
}

Date:: ~Date() // destructor
{
    //cout<< "Date Object Destroyed\n";
}

int Date:: getDay()
{
return day;
}
int Date:: getMonth()
{
return month;
}
int Date:: getYear()
{
return year;
}

void Date:: setDay(int d)
{
day = d;
}
void Date:: setMonth(int m)
{
month = m;
}
void Date:: setYear(int y)
{
year = y;
}

void Date:: showDate()
{
cout << setfill('0')
         << setw(2)<< day << "/"
         << setw(2) << month << "/"
         << setw(2) << year << setfill(' ');
}


Code: [Select]
// "cli_ins_hom_aut_lif.h"

class Client ///////////////////////////// Client //////////////////////////////
{
protected:
    char FirstName[25];
    char LastName[25];
    char Address1[32];
    char Address2[32];
    char Gender[7];
    int Age;

public:
    Client();
    ~Client();

    //Accessors
    char* getFirstName();
    char* getLastName();
    char* getAddress1();
    char* getAddress2();
    char* getGender();
    int getAge();

    void setAllClientInfo();
    void showAllClientInfo();
};

Client::Client()
{
    FirstName[0]=0;
    LastName[0]=0;
    Address1[0]=0;
    Address2[0]=0;
    Gender[0]=0;
    Age = 0;
}
Client::~Client() { /* cout<<"Client Object Destroyed!\n"; */ }

char* Client::getFirstName() { return FirstName; }
char* Client::getLastName() { return LastName; }
char* Client::getAddress1() { return Address1; }
char* Client::getAddress2() { return Address2; }
char* Client::getGender() { return Gender; }
int Client::getAge() { return Age; }

void Client::setAllClientInfo()
{
    cout << "\n:::::CLIENT INFORMATION:::::\n\n";

    cout << "Please Enter Your First Name: ";
    getStr( FirstName, sizeof(FirstName) );
    cout << "Please Enter Your Last Name: ";
    getStr( LastName, sizeof(LastName) );

    Age = getPosInteger( "Please Enter Age: ", 0 );

    cout << "Please Enter Gender: ";
    getStr( Gender, sizeof(Gender) );
    cout << "Please Enter First Line Of Address: ";
    getStr( Address1, sizeof(Address1) );
    cout << "Please Enter Second Line Of Address: ";
    getStr( Address2, sizeof(Address2) );
}
void Client::showAllClientInfo()
{
    cout <<"\n" << LastName << ", " << FirstName << ", "
         << Gender << ", " << Age << ", "<<Address1 << ", " <<Address2;

}////////////////////////////////////// END CLIENT /////////////////////////////

class Insurance: public Client ///////// INSURANCE /////////////////////////////
{
protected:
    int PolicyNum;
    int PolicyType; // 1 = Home; 2 = Auto; 3 = Life
    Date EffectiveDate;
    Date ExpiryDate;
    int Premium;

public:
    Insurance();
    ~Insurance();

    int getPolicyNum();
    int getPolicyType();
    int getPremium();

    void setEffectiveDate(Date&);
    void setExpiryDate(Date&);
    void setPolicyType(int);
    void setPolicyNum(int);

    virtual void setAllInfo() =0;
    void setAllInsInfo();
    void showAllInsInfo();
    virtual void showAllInfo() =0;
};

Insurance::Insurance() : EffectiveDate(0,0,0), ExpiryDate(0,0,0)
{ PolicyNum=0; PolicyType=0; Premium=0; }
Insurance::~Insurance()
{ /* cout<<"Insurance Object Destroyed!\n"; */ }

int Insurance::getPolicyNum() { return PolicyNum; }
int Insurance::getPolicyType() { return PolicyType; }
int Insurance::getPremium() { return Premium; }

void Insurance::setEffectiveDate(Date& Edate)
{
    EffectiveDate.setDay(Edate.getDay());
    EffectiveDate.setMonth(Edate.getMonth());
    EffectiveDate.setYear(Edate.getYear());
}
void Insurance::setExpiryDate(Date& Exdate)
{
    ExpiryDate.setDay(Exdate.getDay());
    ExpiryDate.setMonth(Exdate.getMonth());
    ExpiryDate.setYear(Exdate.getYear());
}

void Insurance::setPolicyType( int tNum ) { PolicyType = tNum; }
void Insurance::setPolicyNum( int pNum) { PolicyNum = pNum; }

void Insurance::setAllInsInfo()
{
    int y, m, d;
    for( ;; )
    {
        cout << "\n:::::INSURANCE INFORMATION:::::\n\n";
        cout << "For Policy#: " << PolicyNum << endl;

        cout << "Enter date yy/mm/dd for policy to become effective: ";
        y=m=d=0;
        char c;
        cin >>y>>c>>m>>c>>d;
        if( !cin.good() )
        {
            cin.clear();
            cin.sync();
            cout << "Entry error ...\n" << flush;
            continue;
        }
       
        Date efd( d, m, y );
        setEffectiveDate( efd );

        cout << "Enter date yy/mm/dd for policy to expire: ";
        y=m=d=0;
        cin >>y>>c>>m>>c>>d;
        if( !cin.good() )
        {
            cin.clear();
            cin.sync();
            cout << "Entry error ...\n" << flush;
            continue;
        }
       
        break;
    }
   
    Date exd( d, m, y );
    setExpiryDate( exd );

    Premium = getPosInteger
    ( "Insurance Annual Premium (rounded to nearest dollar) $", 0 );

}

void Insurance::showAllInsInfo()
{
    // char* POLY_TYPE[] = { "Home", "Auto", "Life" }; // now a global const
    cout << "\nPolicy Number    : " << PolicyNum;
    // 1 = Home; 2 = Auto; 3 = Life
    cout << "\nPolicy Type      : " << POLY_TYPE[PolicyType-1];
    cout << "\nEffective Date   : ";
    EffectiveDate.showDate();
    cout << "\nExpiry Date      : ";
    ExpiryDate.showDate();
    cout << "\nPremium          : " << Premium;

} ///////////////////////////// END INSURANCE //////////////////////////////////

class Home : public Insurance //////////////////// HOME ////////////////////////
{
private:
    int HomeValue;
    char RoofType[15];
    char Question1[4];//is a bugler alarm installed
    char Question2[4];//is a fire alarm installed

public:
    Home()
    {
        HomeValue = 0;
        RoofType[0]=0;
        Question1[0]=0;
        Question2[0]=0;
    }
    ~Home() { /* cout<<"Home Object Destroyed!\n"; */ }

    //Accessors
    int getHomeValue() { return HomeValue; }
    char* getRoofType() { return RoofType; }
    char* getQuestion1() { return Question1; }
    char* getQuestion2() { return Question2;}

    void setAllInfo()
    {
        cout << "\n:::::HOME INSURANCE INFORMATION:::::\n\n";

        HomeValue = getPosInteger( "Please Enter Home Value: $", 0 );

        cout << "Enter Roof Type: ";
        getStr( RoofType, sizeof(RoofType) );
        cout << "Is a Burgler Alarm Installed? ";
        getStr( Question1, sizeof(Question1) );
        cout << "Is a Fire Alarm Installed? ";
        getStr( Question2, sizeof(Question2) );
    }

    void showAllInfo()
    {
        cout << "\nHome Value       : $" << HomeValue;
        cout << "\nRoof Type        : " << RoofType;
        cout << "\nBurgler Alarm Installed: " << Question1;
        cout << ", Fire Alarm Installed: " << Question2;
    }
}; /////////////////////////////// END HOME ////////////////////////////////////


class MotorVehicle : public Insurance ///////////////// AUTO ///////////////////
{
private:
    char Model[20];
    char Make[15];
    int Year;
    char LicenseNum[10];
    char ChassisNum[10];
    int EstimatedValue;
    char FuelType[9];
    char BodyType[9];
    char CCRating[4];
    int SeatCapacity;
    char Question1[4];//was ... involved in an accident during the last year
    char Question2[4];//does ... have a burgler alarm installed

public:
    MotorVehicle()
    {
        Model[0]=0;
        Make[0]=0;
        Year = 0;
        LicenseNum[0]=0;
        ChassisNum[0]=0;
        EstimatedValue = 0;
        FuelType[0]=0;
        BodyType[0]=0;
        CCRating[0]=0;
        SeatCapacity = 0;
        Question1[0]=0;
        Question2[0]=0;
    }

    ~MotorVehicle() { /* cout<<"Vehicle Insurance Destroyed!"; */ }

    void setAllInfo()
    {
        cout << ":::::MOTOR VEHICLE INSURANCE INFORMATION:::::\n\n";

        cout << "Please Enter Make of Vehicle: ";
        getStr( Make, sizeof(Make) );
        cout << "Please Enter Model of Vehicle: ";
        getStr( Model, sizeof(Model) );

        Year = getPosInteger( "Please Enter Vehicle Year: ", 0 );

        cout << "Enter License#: ";
        getStr( LicenseNum, sizeof(LicenseNum) );
        cout << "Enter Chassis#: ";
        getStr( ChassisNum, sizeof(ChassisNum) );

        EstimatedValue = getPosInteger
        ( "Please Enter A Estimated Value Of The Vehicle: $", 0 );

        cout << "Enter Fuel Type: ";
        getStr( FuelType, sizeof(FuelType) );
        cout << "Enter Body Type: ";
        getStr( BodyType, sizeof(BodyType) );

        SeatCapacity = getPosInteger( "Enter Seat Capacity: ", 0 );

        cout << "Enter CC Ratings: ";
        getStr( CCRating, sizeof(CCRating) );
        cout << "Was The Vehicle Involved In An Accident During The Last Year? ";
        getStr( Question1, sizeof(Question1) );
        cout << "Does The Vehicle Have A Burgler Alarm Installed? ";
        getStr( Question2, sizeof(Question2) );
    }

    void showAllInfo()
    {
        cout << "\nMake of Vehicle  : " << Make;
        cout << "\nModel of Vehicle : " << Model;
        cout << "\nVehicle Year     : " << Year;
        cout << "\nEnter License#   : " << LicenseNum;
        cout << "\nEnter Chassis#   : " << ChassisNum;
        cout << "\nEstimated Value  :$" << EstimatedValue;
        cout << "\nFuel Type        : " << FuelType;
        cout << "\nBody Type        : " << BodyType;
        cout << "\nSeat Capacity    : " << SeatCapacity;
        cout << "\nCC Ratings       : " << CCRating;
        cout << "\nAccident in Year : " << Question1;
        cout << "\nAlarm Installed  : " << Question2;
    }
}; /////////////////////////////////////// END AUTO ////////////////////////////

class Life :public Insurance ////////////// LIFE ///////////////////////////////
{
private:
    char Occupation[20];
    char Question1[4];//Is The Insured Person A Smoker?
    char Question2[4];//Is accidential Death And Disenberment Coverage Required?
    int EstimatedValue;

public:
    Life()
    {
        Occupation[0]=0;
        Question1[0]=0;
        Question2[0]=0;
        EstimatedValue = 0;
    }

    ~Life() { /* cout<<"\nLife Insurance Destroyed!\n"; */ }

    void setAllInfo()
    {
        cout << ":::::LIFE INSURANCE INFORMATION:::::\n\n";

        cout << "Occupation? ";
        getStr( Occupation, sizeof(Occupation) );
        cout << "Is The Insured Person A Smoker? ";
        getStr( Question1,sizeof(Question1) );
        cout << "Is Accidential Death And Disenberment Coverage Required? ";
        getStr( Question2, sizeof(Question2) );

        EstimatedValue = getPosInteger( "Estimated Coverage Required? ", 0 );
    }

    void showAllInfo()
    {
        cout << "\nOccupation       : " << Occupation;
        cout << "\nSmoker           : " << Question1;
        cout << "\nADAD Coverage    : " << Question2;
        cout << "\nLife Coverage    : " << EstimatedValue;
    }
};
« Last Edit: March 27, 2009, 05:07:14 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #23 on: March 27, 2009, 05:49:13 PM »
Taking another little break in pace ... C this fun stuff for C beginners ... (  some common beginning problems ... eh :)  ) ... but NO longer a problem ?


How do you ask for more in C  ... in a loop

C this ...

Code: [Select]
/* validating numeric entry in C and use of 'do( ... )while( more() );' loop */

#include <stdio.h>
#include <ctype.h>

int more() /* defaults to yes ... unless 'n' or 'N' are entered */
{
    int reply;
    printf("\nMore ... (y/n) ? ");
    reply = toupper( getchar() );
    if( reply = '\n' )
        while( getchar() != '\n' ) ; /* flush stdin ...*/
    return reply != 'N';
}

int main() /* testing more() ...*/
{
    int i, numGood;
    do
    {
        printf("Enter a positive integer : ");
        numGood = scanf("%d", &i );
        while( getchar() != '\n' ) ; /* flush stdin ... */
        if( numGood != 1 || i < 0 )
        {
            if( numGood != 1) puts("\nEntry error! INTEGERS only please ...");
            if( i < 0 ) puts("\nEntry error! POSITIVE integers only please ...");
            continue;
        }

        printf("Yeah ... you can read and type.  You entered %d\n", i);
       
    }while( more() );
   
    return 0;
}


This demonstrates using more() in a real student problem ...

When given a 4 digit integer such as 5432, I want to parse each individual number out of the whole number and add them together. For example: 5432 becomes 5 + 4 + 3 + 2 = 14

Oops ... this is coded in C++ ... but, by now, you may be able to easily convert the cout's to C stdio io's.  Enjoy ... the fun with recursion ...

Code: [Select]
// some fun with recursion ...
// finding the sum of digits in a number
// 5432 becomes 5 + 4 + 3 + 2 = 14


#include <iostream>
using namespace std;

void showSumAndDigits( int num, int& sum )
{
    if(num == 0)
    {
        cout << sum << " = ";
        return;
    }
   
    int nextDigit = num%10;
    sum += nextDigit;
    showSumAndDigits( num/10, sum );
    if( num/10 )
        cout << " + ";
    cout << nextDigit;
}

void showDigitsFindSum( int num, int& sum )
{
    if(num == 0) return;

    int nextDigit = num%10;
    sum += nextDigit;
    showDigitsFindSum( num/10, sum );
    if( num/10 )
        cout << " + ";
    cout << nextDigit;
}


void showNumDigitsSum( int num )
{
    int sum = 0;
    cout << "Recursive sum of digits in " << num << " becomes ";
    showDigitsFindSum( num, sum );
    cout << " = " << sum;
}



int main()
{
    cout << "Enter a number to see the digits added : " << flush;
    int num, sum = 0;
    cin >> num;
    int numCopy = num;
    while(num)
    {
        int nextDigit = num%10;
        sum += nextDigit;
        cout << "Next digit: " << nextDigit << " Next sum: " << sum << endl;
        num /= 10;
    }
   
    cout << "\n\nRecursive sum of digits in " << numCopy << " becomes ";
    sum = 0;
    showSumAndDigits( numCopy, sum );
   
    cout << "\n\nshowNumDigitsSum( " << numCopy << " ) ... \n";
    showNumDigitsSum(numCopy);
   
    cout << "\n\nPress 'Enter' to exit ... " << flush;
    cin.sync();
    cin.get();
}


An other common student question ...

I have been asked to change the code so that a program asks repeatedly for a new number of Fibonacci numbers until the user decides to quit. The user's decision to continue or not is taken within a simple user-defined function. Design this 'more' function to take no parameters, but to return a boolean value ... (but in C we use type int and return 0=false or 1 or some non zero value for true). The function should return 'true' when the user types 'Y' or 'y', false when the user enters 'N' or 'n' ... (but default to 'yes/true' ... that is ... if any key, including just the 'Enter'Return key is pressed ... excepting 'n' or 'N' ... the function will return 'true' / 'yes'.  But ... to get 'false' / 'no' ... one MUST actually enter 'n' or N').

Here is a start ... (that also demo's a C way to validate numeric input) ...

Code: [Select]
/* validating numeric entry in C and use of 'do( ... )while( more() );' loop */

#include <stdio.h>
#include <ctype.h>

int more() /* defaults to yes ... unless 'n' or 'N' are entered */
{
    int c, reply;
    printf("\nMore ... (y/n) ? ");
    reply = c = toupper( getchar() );
    while( c != '\n' ) c = getchar(); /* flush stdin ...*/
    return reply != 'N';
}

int main() /* testing more() ...*/
{
    int i, numGood;
    do
    {
        printf("Enter a positive integer : ");
        numGood = scanf("%d", &i );
        while( getchar() != '\n' ) ; /* flush stdin ... */
        if( numGood != 1 || i < 0 )
        {
            if( numGood != 1) puts("\nEntry error! INTEGERS only please ...");
            if( i < 0 ) puts("\nEntry error! POSITIVE integers only please ...");
            continue;
        }

        printf("Yeah ... you can read and type.  You entered %d\n", i);

    }while( more() );
   
    return 0;
}


The Fibonacci Number series ... may also be found by recursive function calls ... ( but the most frequent, real use of recursion, that I know, is for Quick Sort ... which we may get to ... yet :) )

Code: [Select]
#include <stdio.h>

#define START_VAL 10

#define info "The following will find the Fibonacci series ...\n\n" \
             "Notice that it will take progressively longer to\n" \
             "find the next term, if you ask for much more than about\n" \
             "40 or so terms ...depending on the speed of your CPU.\n\n" \
             "Also ... there is an upper limit (46) to the number of terms\n" \
             "that may be accurately found, depending on the number of bits\n" \
             "in an 'int' used by your Compiler, (if 32 bits, as often, in 2008).\n\n"
/*
    Fibonacci series:  with recursive calls
    F(1) = 1
    F(2) = 1
    F(3) = F(2) + F(1) = 1 + 1 = 2
    F(4) = F(3) + F(2) = 2 + 1 = 3

    by D.W.Zavitz
    http://developers-heaven.net/forum/index.p...opic,127.0.html
    http://developers-heaven.net/forum/index.p...opic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

int fib( int n )
{
    /*
        To handle the special cases: fib(2)=1; fib(1)=1;
        THIS SPECIAL definition for fib(2) and fib(1) ...
        is properly HANDLED by the next statement:
    */
    if (n <= 2 ) return 1;

    /*
        The following will push onto the 'stack memory'
        ALL (function) pairs like this:
        <fib(n-1), fib(n-2)>, .... <fib(3),fib(2)>,  <fib(2),fib(1)>
        BUT WE then have put on the stack
        THAT fib(2) is 1 and fib(1) is 1 ....
        So ... (popping the stack on return ...)
        'pop' (i.e. TAKE) from the TOP of stack ...
        starting with fib(1) = 1 and fib(2) =1

        WE NOW KNOW how to RETURN all these values:

        fib(1)= 1; // special well defined case
        fib(2)= 1; // special well defined case
        fib(3) = fib(2)+fib(1) = 2; // recursively defined cases begin ...
        fib(4) = fib(3)+fib(2) = 3;
        fib(5) = fib(4)+fib(3) = 5;
        fib(6) = fib(5)+fib(4) = 8;
        .
        .
        .
        fib(n) = fib(n-1) + fib(n-2)
    */

    else return fib(n-1) + fib(n-2);
}

int more() /* defaults to yes ... unless 'n' or 'N' are entered */
{
    int c, reply;
    printf("\nMore ... (y/n) ? ");
    reply = c = toupper( getchar() );
    while( c != '\n' ) c = getchar(); /* flush stdin ...*/
    return reply != 'N';
}


int main()
{
    puts( info );
    int i, j, numGood;
    printf("Fibronacci series for the first %d numbers.\n", START_VAL);
    for( i=1; i<=START_VAL; ++i ) printf("%d ", fib(i));
    puts("\n");
    do{
        j = -1;
        printf("Your number please : ");
        numGood = scanf("%d", &j);
        while( getchar() != '\n' ) ; /* flush stdin ... */
        if( numGood ==1 && j > 0 )
        {
            if( j > 40 ) { puts("You've got to be kidding ... eh?"); continue; }
            for( i=1; i<=j; ++i ) printf("%d ", fib(i));
        }
        else
        {
            puts("\nValid input is 'only integers greater than 0' ...");
        }
       
    }while( more () );

    return 0;
}


Future ... (Quick Sort vs other sorts ?) ... but now, an analysis of 3 versions of Quick Sort ...

First version ...

Code: [Select]
/*
    Analysis of quick sort of an array of a few 'random' int's ...
    (using dynamic memory to hold the arrays) ...
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX 14 /* change here ... to whatever number you desire ... */

/* forward declarations ... */

void qSort(int a[], int left, int right);
int partition(int a[], int left, int right);
void swap(int* a, int* b);

void pause(char* message);


/*******************************************************************************
    begin main ...
*******************************************************************************/
int main()
{
    int i, tmp;
    int* ary = (int*) malloc( sizeof(int) * MAX );
    srand( time(NULL) );
    for(i = 0; i<MAX; ++i) ary[i] = rand()%MAX + 1;
    for(i = 0; i<MAX; ++i) printf("%d ", ary[i]);
    printf("Unsorted ... ");
    pause("continue");
   
    qSort(ary, 0, MAX-1);
    for(i = 0; i<MAX; ++i) printf("%d ", ary[i]);
    printf("Quick sorted ... ");   
    pause("continue");
   
    puts("\nMostly sorted ...");
    /* swap first and last ... */
    tmp = ary[0];
    ary[0] = ary[MAX-1];
    ary[MAX-1] = tmp;
   
    for(i = 0; i<MAX; ++i) printf("%d ", ary[i]);
    printf("One-un-sorted ... ");
    pause("continue");
   
    qSort(ary, 0, MAX-1);
    for(i = 0; i<MAX; ++i) printf("%d ", ary[i]);
    printf("Quick sorted ... ");   
    pause("EXIT");   
   
    free(ary);
    return 0;
}
/*******************************************************************************
    ... end main
*******************************************************************************/


void qSort(int a[], int left, int right)
{
    if(left >= right) return;
    int pivot = partition(a, left, right);
    qSort(a, left, pivot-1);
    qSort(a, pivot+1, right);
}

int partition(int a[], int left, int right)
{
    static int count =0;
int first = left, pivot = right--;
int i, tmp;
while(left <= right)
{
while(a[left] < a[pivot]) left++;
while( right >= first && a[right] >= a[pivot]) right--;
if(left < right)
{
/* swap( &a[left], &a[right] ); */
/* swap done 'inline' here ... */
tmp = a[left];
a[left] = a[right];
a[right] = tmp;

left++;

for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
printf("... %2d left=%2d pivot=%2d right=%2d\n",++count,left,pivot,right);
}
}

/* when we reach here ... left > right ... */

/* swap done 'inline' here ... */
if(left != pivot) /* swap( &a[left], &a[pivot] ); */
{
tmp = a[left];
a[left] = a[pivot];
a[pivot] = tmp;

        for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
printf("*** %2d left=%2d pivot=%2d right=%2d\n",++count,left,pivot,right); 
    }
   
return left;
}

void swap(int* a, int* b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void pause(char* message)
{
    printf("Press Enter to %s ...", message);
    while( getchar() !='\n' ) ; /* flush stdin ... */
}


Three methods of qsort compared ...

Code: [Select]
/*
    Analysis of quick sort of an array of a few 'random' int's ...
    (using dynamic memory to hold the arrays) ...
*/

/* this version 2010-05-17 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define debug 0    /* if you set these to 1 ... */
#define display 0  /* make sure you reduce MAX to about 14 or so ...*/

#define MAX 100000 /* change here ... to whatever number you desire ... */

/* forward declarations ... */

int count; /* global variable */

/* compare method 2 ...*/
void qSort2(int a[], int left, int right);
/* with method 1 ...*/
void qSort(int a[], int left, int right);
int partition(int a[], int left, int right);
void swap(int* a, int* b);

void pause( char* message );
void show( int a[] );

/* for method 3 ... stdlib.h qsort( ... ) ... */
int compare( const void* x, const void* y )
{
    return( *(int*)x - *(int*)y );
}

/*******************************************************************************
    begin main ...
*******************************************************************************/
int main()
{
    int* ary = (int*) malloc( sizeof(int)*MAX );
    int* ary2 = (int*) malloc( sizeof(int)*MAX );
    if( ary == NULL || ary2 == NULL )
    {
        fputs( "Error: malloc failed ... Press 'Enter' to EXIT ... ", stderr );
        getchar();
        return 1;
    }
    else
    {
        time_t t1, t2;
        int i, tmp, bot, top;
        srand( time(NULL) );
        for(i = 0; i<MAX; ++i) ary[i] = rand()%MAX + 1;
        /* get a copy of array 'ary' into array 'ary2' ...*/
        for(i = 0; i<MAX; ++i) ary2[i] = ary[i];

        /* show unsorted array ... */
        printf("Unsorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0;
        top=MAX-1;
        t1 = clock();
        qSort(ary, bot, top);
        t2 = clock();

        /* show after qsort ... */
        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );
        //pause("continue");


        /* swap first and last ... */
        tmp = ary[0];
        ary[0] = ary[MAX-1];
        ary[MAX-1] = tmp;

        printf("Two-un-sorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0, top=MAX-1;
        t1 = clock();
        qSort(ary, bot, top);
        t2 = clock();

        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );
        //pause("continue to 2");



        for(i = 0; i<MAX; ++i) ary[i] = ary2[i];
        puts("\n\nversion 2 ...");

        printf("\nUnsorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0, top=MAX-1;
        t1 = clock();
        qSort2(ary, bot, top);
        t2 = clock();

        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );
        //pause("continue");


        /* swap first and last ... */
        tmp = ary[0];
        ary[0] = ary[MAX-1];
        ary[MAX-1] = tmp;

        printf("Two-un-sorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0, top=MAX-1;
        t1 = clock();
        qSort2(ary, bot, top);
        t2 = clock();

        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );



        for(i = 0; i<MAX; ++i) ary[i] = ary2[i];
        puts("\n\nversion 3 ...");

        printf("\nUnsorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0, top=MAX-1;
        t1 = clock();
        qsort(ary, MAX, sizeof(int), compare);
        t2 = clock();

        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );
        //pause("continue");


        /* swap first and last ... */
        tmp = ary[0];
        ary[0] = ary[MAX-1];
        ary[MAX-1] = tmp;

        printf("Two-un-sorted:\n");
        show( ary );
        //pause("continue");

        count=bot=0, top=MAX-1;
        t1 = clock();
        qsort(ary, MAX, sizeof(int), compare);
        t2 = clock();

        printf("Quick sorted:\n");
        show( ary );
        printf( "time for sort was %ld\n", t2-t1 );

        pause("EXIT");

        free(ary2);
        free(ary);
        return 0;
    }
}
/*******************************************************************************
    end main
*******************************************************************************/


void qSort2(int a[], int left, int right)
{
    int lft=left, rht=right;
    int tmp, comp = a[(lft+rht)/2];
    do
    {
        while(a[lft] < comp) ++lft;
        while(a[rht] > comp) --rht;
        if(lft <= rht) // swap
        {
#if debug
            int i;
            for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
printf("... %2d lft=%2d comp=%2d rht=%2d\n",++count,lft,comp,rht);
#endif
            tmp = a[lft];
            a[lft] = a[rht];
            a[rht] = tmp;
            ++lft; --rht;
        }
    }while(!(lft>rht));
    if(left < rht) qSort2( a, left, rht);
    if(lft < right) qSort2( a, lft, right);
}

void qSort(int a[], int left, int right)
{
    if(left >= right) return;
    int pivot = partition(a, left, right);
    qSort(a, left, pivot-1);
    qSort(a, pivot+1, right);
}

int partition(int a[], int left, int right)
{
    int tmp;
    int first = left, pivot = right--;
while(left <= right)
{
while(a[left] < a[pivot]) left++;
while( right >= first && a[right] >= a[pivot]) right--;
if(left < right)
{
/* swap( &a[left], &a[right] ); */
tmp = a[left];
a[left] = a[right];
a[right] = tmp;

left++;
#if debug
            int i;
for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
printf("... %2d left=%2d pivot=%2d right=%2d\n",
                   ++count,left,pivot,right);
#endif
}
}

/* when we reach here ... left > right ... */

if(left != pivot) //swap( &a[left], &a[pivot] );
{
tmp = a[left];
a[left] = a[pivot];
a[pivot] = tmp;
#if debug
        int i;
        for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
printf("*** %2d left=%2d pivot=%2d right=%2d\n",
               ++count,left,pivot,right);
#endif
    }

return left;
}

void swap(int* a, int* b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void pause( char* message )
{
    printf("Press Enter to %s ...", message);
    while( getchar() !='\n' ) ; /* flush stdin ... */
}

void show( int a[] )
{
#if display
    int i;
    for(i = 0; i<MAX; ++i) printf("%d ", a[i]);
    putchar( '\n' );
#endif
}


Here is a demo of qsort (of arrays) in C ... of int's, C string's, struct's ...
(and also demo's sorts that ignore case - click on following link to jump there now)

http://developers-heaven.net/forum/index.php/topic,106.msg277.html#msg277
« Last Edit: February 17, 2014, 02:01:57 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #24 on: March 27, 2009, 08:45:03 PM »
Finally ... C a linked list ... (with an insertion sort method that adds new list elements by inserting them in ABC...abd... sorted order.

Also ... uses typedef char* CString ....  A CString holds a whole line of input ... and using a 'list' of lines ... you can have as many lines as you may wish ... as much as available memory permits ...  in your 'insertion-sorted list'.  This *IS* an often seen student problem ... but no more a problem ... eh :)

Code: [Select]
/* ListOfStr.c */ /* this version 2010-09-07 */

/*
    latest rev. maintained at:
    http://developers-heaven.net/forum/index.php/topic,106.msg257.html#msg257
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. strlen, strcpy, strcmp ... */

/* make this big enough so ALL C strings DO have the 'fgets' '\n' char at end */
#define BUFFER_SIZE 1024

typedef char* CString;
typedef struct ListOfStr
{
    CString str;                /* 'str' holds the address of a new C string ... */
    struct  ListOfStr* next;    /* points to the next C string ... */
}ListOfStr;

typedef ListOfStr* pListOfStr;  /* to hold the address of a C string */


/* prototypes ... */

/* INSERTS C string 'data' into 'list' in 'ABC...abc...' order */
pListOfStr insert_list( char data[], pListOfStr list );

/* erase/free up all memory in list */
pListOfStr erase_list( pListOfStr list );

/* show all the (insert_list-sorted) 'text lines' in the 'list' */
void print_list( pListOfStr p );

/* utility function to return a copy ... in NEWly allocated memory */
CString newCopy( char str[] );

void myAssert( int condition, char text[] )
{
    if( !condition )
    {
        fprintf( stderr, "%s.  Press 'Enter' to exit ... ", text );
        getchar();
        exit(1);
    }
}



int main() /* * * * * * * * * * * * * * MAIN BEGINS * * * * * * * * * * * * * */
{
    /* in the following ... list is declared as a pointer to ListOfStr ... */
    pListOfStr list = NULL; /* 'list' ... holds the address of the list's HEAD */

    char buffer[BUFFER_SIZE];
    char prompt[] = "Enter line of text to insert_list into list (or Ctrl Z to end) : ";

    while( printf( prompt ) && fgets(buffer, BUFFER_SIZE, stdin) != NULL  )
        list = insert_list( buffer, list );

    print_list( list );

    list = erase_list( list ); /* ... and re-sets list to NULL ... */

    printf( "\nPress 'Enter' ... to continue ... " );
    getchar();
    return 0;

}/* * * * * * * * * * * * * * * * * * MAIN ENDS * * * * * * * * * * * * * * * */



/* pass in the address of the 'head' ... and the line to insert_list ...*/
pListOfStr insert_list( char data[], pListOfStr list )
{
    pListOfStr p, q;

    /* create a new node */
    p = (pListOfStr) malloc( sizeof(ListOfStr) );
    myAssert( (p != NULL), "Error: malloc failed to allocate memory (1)" );

    /* save address of new memory (copy of data) into the new node ... */
    p->str = newCopy( data );

    /* first, we handle the case where 'data' should be the first element */
    if( list == NULL || strcmp(data, list->str) < 0 )
    {
        /* yes ... this IS the first element */
        /* so set to be the first element */
        p->next = list;
        return p;
    }

    /* if program reaches here, search the linked list for the right location */
    q = list;
    while( q->next != NULL && strcmp(q->next->str, data) <= 0 )
        q = q->next;

    p->next = q->next;
    q->next = p;
    return list;
}

pListOfStr erase_list( pListOfStr list )
{
    pListOfStr p;
    while( list != NULL )
    {
        p = list->next;
        free( list->str );
        free( list );
        list = p;
    }
    return list; /* i.e. return NULL; */
}

/*
    Note: all these lines (strings) have a '\n' char at the end ... except
    maybe, the last line ... (if we reached EOF without a '\n' char there.)
*/
void print_list(pListOfStr p)
{
    for( ; p != NULL; p = p->next ) printf( p->str );
}

/* utility function to return a copy ... in NEWly allocated memory */
CString newCopy( char str[] )
{
    CString nCopy = (CString) malloc( strlen(str)+1 );
    myAssert( (nCopy != NULL), "Error: malloc failed to allocate memory (2)" );

    strcpy( nCopy, str );
    return nCopy; /* REMEMBER to *free* this new string when done with it ... */
}


Here is a C safe way to input strings of ANY length from the keyboard ... (that you could use in the above) ...
(Note: but may need to update to check for fail to allocate memory ...)

Code: [Select]
/* c_safe_getline.c */ /* this version 2010-09-07 */

#include <stdio.h>
#include <stdlib.h>

/* safe C line input from keyboard ... SAFE for ANY line LENGTH */
/* REMEMBER to free the new memory ... when done with it ...  */
char* c_safe_getline()
{
    int c, buf_len = 256, len = 0;
    char* buffer = (char*) malloc( buf_len ); /* good to check if memory allocated */

    /* eats up WHOLE line ... including '\n' */
    while( (c = getchar()) != '\n' )
    {
        if( len == buf_len-1 ) /* good up t0 value buf_len-2*/
        {
            buf_len += buf_len;
            buffer = (char*) realloc( buffer, buf_len ); /* good to check if allocated ok ...*/
        }
        buffer[len++] = c;
    }

    buffer[len] = 0; /* confirm NULL terminated ... */
    return (char*) realloc( buffer, len+1  ); /* but ... good to check if allocated ok */
}

char* get_line( char prompt[] )
{
    printf( prompt );
    return c_safe_getline();
}

/*
    defaults to 'yes' ... i.e. user must enter 'n' or 'N' for 'No'
    returns '1' for 'Yes' or '0' for 'No' ...
*/
int more()
{
    int c, reply;

    printf( "\nMore ... y/n ? " );
    reply = c = getchar();
    while( c != '\n' )
        c = getchar(); /* flush stdin ... */

    if( reply == 'n' || reply == 'N' )
        return 0; /* No more ... */

    /* else ...*/
    return 1; /* Yes more ... */
}


int main() /* to test 'char* c_safe_getline()' */
{
    char* s;
    do
    {
        s = get_line( "Enter line: " );
        printf( "You entered: '%s'\n", s );
        free( s );

    }while( more() );

    return 0;
}


And ... using the c_safe_getline() ... in the insert sort list example above ...

Code: [Select]
/* ListOfStr2.c */ /* this version 2010-09-07 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re.  strcmp */
#include <ctype.h> /* re. tolower */

typedef struct ListOfStr
{
    char* str; /* 'str' holds the address of a new C string ... */
    struct ListOfStr* next; /* points to the next C string ... */
} ListOfStr ;

typedef ListOfStr* pListOfStr; /* holds base address of a list of C strings */


/* prototypes ... */

/* INSERTS new C string 'data' into 'list' in 'ABC...abc...' order */
pListOfStr insert_sorted( char* data, pListOfStr list );

/* erase/free up all memory in list */
pListOfStr erase_all( pListOfStr list );

/* show all the (insert_sorted-sorted) 'text lines' in the 'list' */
void print_all( pListOfStr p );

/* utility function to return line in NEWly allocated memory */
char* c_safe_getline();

int strcmpIgnoreCase( char*, char* );

void myAssert( int condition, char text[] )
{
    if( !condition )
    {
        fprintf( stderr, "%s.  Press 'Enter' to exit ... ", text );
        getchar();
        exit(1);
    }
}



int main() /* * * * * * * * * * * * * * MAIN BEGINS * * * * * * * * * * * * * */
{
    /* in the following ... list is decalred as a pointer to ListOfStr ... */
    pListOfStr list = NULL; /* 'list' ... holds the address of the list's HEAD */

    char* line;
    char* prompt = "Enter a line of text (or just press 'Enter' to end) : ";

    /* just press 'Enter' ... and no text entered to end this loop ... */
    while( printf( prompt ) && (line = c_safe_getline()) && line[0] != 0 )
        list = insert_sorted( line, list );

    free( line ); /* free last line's allocated memory when line[0] == 0 */

    print_all( list );

    list = erase_all( list ); /* ... and re-sets list to NULL ... */

    printf( "\nPress 'Enter' ... to continue ... " );
    getchar();
    return 0;

}/* * * * * * * * * * * * * * * * * * MAIN ENDS * * * * * * * * * * * * * * * */



pListOfStr insert_sorted( char* data, pListOfStr list )
{
    /* create a new node */
    pListOfStr p = (pListOfStr) malloc( sizeof(ListOfStr) );
    myAssert( (p != NULL), "Error: malloc failed to allocate memory" );

    /* save address of new memory into the new node ... */
    p->str = data ;

    /* firstly, handle the frequent case where 'data' is NOT the first element */
    if( list != NULL && strcmpIgnoreCase(data, list->str) >= 0 )
    {
        pListOfStr q = list;
        while( q->next != NULL && strcmpIgnoreCase(q->next->str, data) <= 0 )
            q = q->next;

        p->next = q->next; /* N->B*/
        q->next = p; /* A->N */
        return list;
    }
    /* else ... */
    /* if program reaches here, search the linked list for the right location */
    /* yes ... this IS the first element */
    /* so set to be the first element */
    p->next = list;
    return p;
}

pListOfStr erase_all( pListOfStr list )
{
    pListOfStr p;
    while( list != NULL )
    {
        p = list->next;
        free( list->str );
        free( list );
        list = p;
    }
    return list; /* i.e. return NULL; */
}

void print_all( pListOfStr p )
{
    for( ; p != NULL; p = p->next ) printf( "%s\n", p->str );
}

/* utility function to return line in NEWly allocated memory */
char* c_safe_getline()
{
    int c, buf_len = 256, len = 0;
    char* tmp, * line = (char*) malloc( buf_len );
    myAssert( (line!=NULL), "Error: malloc failed to allocate memory" );

    /* eats up WHOLE line ... including '\n' */
    while( (c = getchar()) != '\n' )
    {
        if( len == buf_len-1 ) /* good upto buf_len-2 */
        {
            buf_len += buf_len;
            tmp = (char*) realloc( line, buf_len );
            if( tmp == NULL )
            {
                free( line );
                myAssert( 0, "Error: realloc failed to allocate memory" );
            }
            /* if reach here ... good realloc ... so update ... */
            line = tmp;
        }
        line[len++] = c;
    }

    line[len] = 0; /* confirm NULL terminated ... */
    tmp = (char*) realloc( line, len+1  );
    if( tmp == NULL )
    {
        free( line );
        myAssert( 0, "Error: realloc failed to allocate memory" );
    }
    return tmp;
}

int strcmpIgnoreCase( char* a, char* b )
{
    while( *a != 0 && *b != 0 && tolower(*a) == tolower(*b) ) ++a, ++b;
    /* now examine end  condition ...*/
    return( tolower(*a) - tolower(*b) );
}
« Last Edit: September 08, 2010, 04:37:33 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #25 on: April 19, 2009, 08:13:02 AM »
And ... a little about linked lists for C++ students who may not yet C ...

A mini C++ linked lists tutorial ... (taken from my recent comment's posted at ...)

1st link ...
http://www.dreamincode.net/forums/showtopic98767.htm

2nd link ...
http://www.dreamincode.net/forums/showtopic99329.htm

Or ... try this first, maybe ...
http://www.dreamincode.net/forums/index.php?s=&showtopic=152343&view=findpost&p=908336

From the first link ... you will see below ...

1. a simple Node (with just one int value) ...
2. with an insert sort demo'd ...
3. and some discussion re. pointers ...
4. also a Node(with an int value and a string value)
5. passing by value and returning a function value
6. passing/returning by ref
7. typedef Node* pNode discussed and demo'd

A Linked-List is quite a different data structure than an array ...

If data item 'a' has Address A, data item 'b' has address B, etc ...

Then the start address is ... (the value in the pointer variable pHead is) ... A
and (the node at) A points to B
and (the node at) B points to C
...
...
...
and Z (i.e. the last node/element) points to a NULL terminal value.

pHead = A; // where A is the start address that was assigned by 'new'


This simple working example may help you get started ...

Code: [Select]
// linked_list_ex1.cpp // rev 2010-07-25

#include <iostream>
using namespace std;

struct Node
{
    int data;
    Node* next;
};

// after this following typedef statement ...
// where-ever you would have had (type) Node*
// you may now more simply use (type)  pNode

typedef Node* pNode;

// Node* take_in_more( Node* pHead)
pNode take_in_more( pNode pHead )
{
    // recall pNode is type pointer to a Node, i.e. Node*
   
    // get pEnd ... the address of the last node in the list
    pNode pEnd;
    int i = 0; // i holds count of nodes ...
    if( pHead != NULL )
    {
        for( pEnd = pHead; pEnd->next != NULL; pEnd = pEnd->next, ++i )
            ;
    }
    // now ... i holds count, pEnd holds address of last Node

    char prompt[] = "('x' to eXit) Enter a value for number ";
    // advance i to next count for this new number to be input ...
    while( cout << prompt << ++i << ": " && cin >> num )
    {
        pNode pNew = new Node; // get new memory to hold a Node
        pNew->data = num; // fill in values for this Node
        pNew->next = NULL;
       
        if( pHead != NULL ) // append (for all passes after the first pass)
        {
            pEnd->next = pNew; // link to new node
            pEnd = pNew; // reset 'pEnd' to this latest new node
        }
        else // pHead is set on the first pass only ...
            pHead = pEnd = pNew;
    }
    cin.clear(); // clear cin error flags ...
    cin.sync(); // 'flush' cin stream ...
    return pHead;
}

// show all the node datas ...
// note: pStart is a local copy of the pointer ( the address )
void show_all( pNode pStart )
{
    int i = 0;
    while( pStart != NULL )
    {
        cout << "node " << ++i << " data : "
             << (pStart->data) << endl;
        pStart = pStart->next;
    }
}

void delete_all( pNode& pStart )
{
    while( pStart != NULL )
    {
        pNode pCopy = pStart; // copy address in pStart into pCopy ...
        pStart = pStart->next; // advance to the next address ... (it may be NULL)
        delete( pCopy ); // free ... the node at this address
    }
    // Note: When done the above loop ... pStart is equal to NULL
    // So ... via 'pass by ref' ... pStart (i.e. pHead) is set to NULL
}


int main()
{
    // Node* pHead = NULL; // Note: pHead must be NULL to start
    pNode pHead = NULL; // Note: pHead must be NULL to start

    cout << "Enter some numbers ... \n\n";
    pHead = take_in_more( pHead );
    cout << "\nSo far ...\n";
    show_all( pHead );

    cout << "\nEnter some more numbers ...\n\n";
    pHead = take_in_more( pHead );
    cout << "\nWith added ...\n";
    show_all( pHead );

    delete_all( pHead );
    cout << "\nAfter delete_all ...\n";
    show_all( pHead );

    cout << "\nNow again, enter some numbers ...\n";
    pHead = take_in_more( pHead );
    cout << "\nList at present ...\n";
    show_all( pHead );
    delete_all( pHead );

    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get(); // wait for 'Enter' key to be pressed ...
}


And ... after you've grasped the pointer style used in linked-lists ... here is an insert-sort example that inserts each new element, as it is entered, in order, in a list ...

Code: [Select]
// linked_list_ex2.cpp // rev 2010-07-25

#include <iostream>
#include <string>

// re. atoi converting an 'alpha' C string 'to' an 'int'
#include <cstdlib>

using namespace std;

struct Node
{
    string name;
    int id;
    Node* next;
};

// Note: variable type pNode if for holding an address of a 'Node'
typedef Node* pNode;


// insert each new node in the list with names in proper order
pNode insert_sorted( pNode pHead, pNode pNew )
{
    // First ... handle case where new node should be first element
    if( pHead == NULL || pNew->name < pHead->name )
    {
        // It now becomes the first element
        pNew->next = pHead; // old pHead becomes 2nd in list
        pHead = pNew; // and this new node becomes the head of the list
    }
    else // If here ... search the linked list for the right location
    {
        pNode q = pHead; // Get a working copy of pHead in q
        // Start comparing with element AFTER 'q' ... i.e. the 'next in'
        while( q->next != NULL && q->next->name <= pNew->name )
        {
            q = q->next; // Traverse the list ...
        }

        // Ok, insert after 'q' by relinking the pointers
        // ( Includes inserting at end position ... where q->next == NULL )
        // for A->B to became A->N->B ... first insert N->B
        pNew->next = q->next; // 'N' is first linked to 'B'
        // and now A->N
        q->next = pNew; // now 'A' is updated to link to 'N'
    }

    return pHead; // since it may have changed, return update
}

pNode take_in_more( pNode pHead )
{
    char prompt[] = "(Blank line to exit) ... Enter name: ";
    char prompt2[] = "Enter ID number: ";
    string tmpStr;
    while( cout << prompt && getline( cin, tmpStr ) )
    {
        if( tmpStr == "" ) break;
       
        pNode pTmp = new Node;
        pTmp->name = tmpStr;
        cout << prompt2;
        getline( cin, tmpStr );
        pTmp->id = atoi( tmpStr.c_str() );

        // Note: the address held in pHead may be updated during the 'insert'
        pHead = insert_sorted( pHead, pTmp ); // Note: HERE we insert each Node
    }

    return pHead;
}

// Show all the node data ...
// Note: pStart is a local copy of the pointer (the address)
void show_all( pNode pStart )
{
    for( int i = 0; pStart != NULL; pStart = pStart->next )
        cout << "Node " << ++i
             << " with id: " << pStart->id
             << " name : " << pStart->name
             << endl;
}

void delete_all( pNode& pStart )
{
    while( pStart != NULL )
    {
        pNode pCopy = pStart; // copy address in pStart into pCopy ...
        pStart = pStart->next; // advance to the next address ... (it may be NULL)
        delete( pCopy ); // free ... the node at this address
    }
    // Note: When done the above loop ... pStart is equal to NULL
    // So ... via 'pass by ref' ... pStart (i.e. pHead) is set to NULL
}


int main()
{
    cout << "Enter some data ... \n\n";

    pNode pHead = NULL; // Note: pHead must be NULL to start
    pHead = take_in_more( pHead );
   
    cout << "\nSo far ...\n";
    show_all( pHead );

    cout << "\nEnter some more data ...\n\n";
    pHead = take_in_more( pHead );
   
    cout << "\nWith added ...\n";
    show_all( pHead );

    delete_all( pHead );
   
    cout << "\nAfter delete_all ...\n";
    show_all( pHead );

    cout << "\nNow again, enter some data ...\n";
    pHead = take_in_more( pHead );
   
    cout << "\nList at present ...\n";
    show_all( pHead );
   
    delete_all( pHead );
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get(); // wait for 'Enter' key to be pressed ...
}


Pointers are just variables to hold an address ... And getting the bits, at different addresses, (of various memory chunks in RAM), and interpreting that bit pattern ...

is it data? (if data ... what decoding to use?) ...
is it an instruction? (ok ... execute that instruction) ...

is really what computing is all about ...

Code: [Select]
// you can refer to a value ... directly ... by its variable name

int number = 5;
cout << number << endl; // prints 5

// or ... indirectly ... by its address ...

// Note: pNumber is declared as a variable to hold the address of an 'int'
int* pNumber = &number; // or ... int* pNumber; pNumber = &number;
cout << *pNumber << endl; // prints 5


This re-edited program below, (with more comments), may help some more ...

Code: [Select]
// linked_list_ex3.cpp // rev 2010-07-25

#include <iostream>

using namespace std;

struct Node
{
    int data;
   
    // Note: 'next' is used to hold the address
    // of the 'next' Node in the linked-list
    Node* next;
};

// Note: pNode is here 'defined' as ...
// a variable type to hold an address of a 'Node'
typedef Node* pNode;

// Note: pHead gets updated (in main) by 'pass by ref'
void take_in_more( pNode& pStart )
{
    // Here ... we want to ...
    // set pEnd to address of the last node in the list,
    // set i to number of nodes
    pNode pEnd;
    int i = 0;
    if( pStart != NULL )
    {
        for( pEnd = pStart; pEnd->next != NULL; pEnd = pEnd->next, ++i )
            ;
    }

    char prompt[] = "('x' to eXit) Enter number ";
    int num;
    // advance i to show number of next new integer to be input ...
    while( cout << prompt << ++i << ": " && cin >> num )
    {
        pNode pNew = new Node; // get new memory to hold a new 'int' and a new 'address'
        pNew->data = num; // Ok ... copy 'num' to this new memory to hold an 'int'
        pNew->next = NULL; // don't forget to 'NULL terminate' each new 'end' Node

        if( pStart != NULL ) // append ... for all passes with a list of one or more elements
        {
            pEnd->next = pNew; // link 'end' Node to new node (after it now)
            pEnd = pNew; // reset 'pEnd' to hold address of this latest new node
        }
        else // pStart (and pHead by ref.) get set here ... *ONLY* if the list passed in was empty
            pStart = pEnd = pNew; // pStart and pEnd now hold this address (i.e. NOT NULL now)
    }
    cin.clear(); // clear cin error flags caused by 'x' instead of an int
    cin.sync(); // 'flush' cin stream ...
}

// show all the node data ...
// Note: pStart is a local copy of the pointer (the address)
void show_all( pNode pStart )
{
    for( int i = 0; pStart != NULL; pStart = pStart->next  )
        cout << "node " << ++i
             << " data : " << (pStart->data)
             << endl;
}

void delete_all( pNode& pStart )
{
    while( pStart!=NULL )
    {
        pNode pCopy = pStart; // copy address in pStart into pCopy ...
        pStart = pStart->next; // advance to the next address (it may be NULL)
        delete( pCopy ); // free the node memory at this address
    }
   
    // Note: When done the above loop, pStart is equal to NULL
    // So, via 'pass by ref' ... pStart (i.e. pHead) is set to NULL
}



int main()
{
    // Note: pHead must be NULL to start
    pNode pHead = NULL;

    cout << "Enter some numbers ... \n\n";
    take_in_more( pHead );
    cout << "\nSo far ...\n";
    show_all( pHead );

    cout << "\nEnter some more numbers ...\n\n";
    take_in_more( pHead );
    cout << "\nWith added ...\n";
    show_all( pHead );

    delete_all( pHead );
    cout << "\nAfter delete_all ...\n";
    show_all( pHead );

    cout << "\nNow again, enter some numbers ...\n";
    take_in_more( pHead );
    cout << "\nList at present ...\n";
    show_all( pHead );
   
    delete_all( pHead );
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get(); // wait for 'Enter' key to be pressed ...
}


C++ linked-list intro ... continued below ...
« Last Edit: July 26, 2010, 02:49:55 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #26 on: April 19, 2009, 08:36:58 AM »
Intro to linked-lists, using C++, continued from above ...

The pass by ref syntax used here may make the code a little simpler to follow ...

Code: [Select]
// linked_list_ex4.cpp // rev 2010-07-25

#include <iostream>
#include <fstream> // ostream ... and overloaded operator <<
#include <string>
#include <cstdlib> // re. atoi ... 'alpha to int'

using namespace std;

struct Node
{
    string name;
    int id;
    Node* next; // to hold the address of the 'next' Node
};

// Note: pNode is 'defined' as ...
// a variable type to hold an address of a 'Node'
typedef Node* pNode;

// insert each new node in the list with names in proper order
// Note: pStart (pFront in calling function) is updated by 'pass by ref'
void insert_sorted( pNode& pStart, pNode pNew )
{
    // Firstly, handle the most common case, where
    // the New node is NOT the first element ...
    if( pStart != NULL && pNew->name >= pStart->name )
    {
        pNode q = pStart; // Get a working copy of pStart in q
        // Start comparing with element AFTER 'q' ... i.e. the 'next in'
        while( q->next != NULL && q->next->name <= pNew->name )
        {
            q = q->next; // Traverse the list ...
        }

        // Ok, insert after 'q' by relinking the pointers
        // ( Includes inserting at end position ...
        // ... where q->next == NULL )
        // for A->B to become A->N->B
        // first link N->B
        pNew->next = q->next; // since q->next is address of 'B'
        // and now A->N
        q->next = pNew; // since pNew is address of 'N'
    }
    else // It now becomes the first element ...
    {   // Note: pStart may have been NULL ... that's 'no problem'
        pNew->next = pStart; // old pStart becomes 2nd in list
        pStart = pNew; // and this new node becomes the start of the list
    }
}

// Note: pFront (pHead in main) is updated by 'pass by ref'
void take_in_data( pNode& pFront )
{
    char prompt[] = "(Enter a blank line to exit) ... Enter name: ";
    char prompt2[] = "Enter ID number: ";
    string tmpStr;
    while( cout << prompt && getline( cin, tmpStr ) )
    {
        if( tmpStr == "" ) break;
       
        pNode pNew = new Node;
        pNew->name = tmpStr;
       
        cout << prompt2;
        getline( cin, tmpStr );
        pNew->id = atoi( tmpStr.c_str() );

        // Note: the address held in pFront may be updated during the 'insert'
        // since we are using 'pass by ref' for 'pFront' ...
        insert_sorted( pFront, pNew ); // Note: HERE we insert each Node
    }
}

// show all the node data ...
// note: pStart is a local copy of the pointer ( i.e. the address) passed to it
void show_all( pNode pStart )
{
    for( int i = 0; pStart != NULL; pStart = pStart->next )
        cout << "node " << ++i << " with id: " << pStart->id
             << " name : " << pStart->name << endl;
}

// Or ... can show all data via:  cout << pStart;
// via an overloaded operator <<
// Here's how ... Note! ostream object is passed in AND returned 'by ref'
// Note 2: This function HAS 2 passed in variables (objects)
ostream& operator << ( ostream& fout, pNode pStart )
{
    for( int i = 0; pStart != NULL; pStart = pStart->next )
        fout << "node " << ++i << " with id: " << pStart->id
             << " name : " << pStart->name << endl;
    return fout;
}

// Note: pStart (pHead in main) is updated by 'pass by ref'
void delete_all( pNode& pStart )
{
    while( pStart != NULL )
    {
        pNode pCopy = pStart; // copy address in pStart into pCopy
        pStart = pStart->next; // advance to the next address (it may be NULL)
        delete( pCopy ); // free the node memory at this address
    }
   
    // Note: When done the above loop ... pStart is equal to NULL
    // So via 'pass by ref' ... pStart (i.e. pHead in main) is set to NULL
}




int main()
{
    // Note: pHead MUST be NULL to start ...
    pNode pHead = NULL;

    cout << "Enter some data ... \n\n";
    take_in_data( pHead );
    cout << "\nSo far ...\n";
    show_all( pHead );

    cout << "\nEnter some more data ...\n\n";
    take_in_data( pHead );
    cout << "\nWith added ...\n";
    show_all( pHead );

    delete_all( pHead );
    cout << "\nAfter delete_all ...\n";
    show_all( pHead );

    cout << "\nNow again, enter some data ...\n";
    take_in_data( pHead );
    cout << "\nList at present ...\n";
    cout << pHead; // using overloaded operator <<

    delete_all( pHead );
    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get(); // wait for 'Enter' key to be pressed ...
}


Quote
... thanks, the only thing I'm unsure of ... is  ... What is a node?

Like ... I know the '*' is to point to what ever is in that variable ...


Not really ... * is used to indicate a variable is a pointer variable

int* p; // indicates that p is a variable to hold the address of an integer


Or ... * is used to de-reference an address, i.e. to take/use the value at an address ...

*p = 7; // means to assign/copy 7 to the memory beginning at the address in the (int pointer) variable p
           // BUT this WILL CRASH if you haven't a valid address in p of memory reserved to hold an int,
           // as we don't yet ... here ... but see the example program snippet below for a proper way to do it.

int seven = *p; // will assign/copy into the memory reserved for the variable seven ... the value 7

int* q = NULL; // declare q as an int pointer variable and assign it the initial value NULL
q = & seven;   // will copy the address of the memory reserved for 'int seven' into q ...
                    // so that q now holds a valid address and NOT NULL any more

cout << *q << endl; // will print out the value at the address in q, which is 7
cout << hex << q << endl; // will print out the hexidecimal value of the address held in the variable q
cout << hex << &q << endl; // will print out the hexidecimal value of the address OF the variable q


Code: [Select]
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int* p; // indicates that p is a variable to hold the address of an integer

    // get some new memory to hold an integer ... (4 bytes in many systems today)
    p = new int; // put the address of (the start byte of) that memory into p

    // Or ... * is used to de-reference an address,
    // i.e. to take/use the value at an address ...
    // here we assign/copy 7 to the address held in the (int pointer) variable p

    *p = 7;
    cout << *p << endl;

    // assign/copy into memory reserved for the variable seven ... the value 7
    int seven = *p;

    // declare q as an int pointer variable and assign it the initial value NULL
    int* q = NULL;

    // copy the address of the memory reserved for 'int seven' into q ...
    //so that q now holds a valid address and NOT NULL any more
    q = & seven;

    // print out the value at the address in q, which is 7
    cout << *q << endl;

    // print out the hexidecimal value of the address held in the variable q
    cout << hex << q << endl;
    cout << hex << &seven << endl; //and the address of the memory used by seven
    
    // print out the hexidecimal value of the address OF the variables q and p
    cout << hex << &q << endl;
    cout << hex << &p << endl;
    

    cin.get();
}
// My output from running the compiled program above was ...
/*
7
7
0x23ff70
0x23ff70
0x23ff6c
0x23ff74
*/

Quote
but I've never used 'typedef Node* pNode' before.
However ... I guess this is good though ... because this one program is making me learn more than I've learned all semester.

Oh, and David ... when I stated the assignment, I guess I worded it poorly ... I don't really need to store the random numbers into an array first.  I could just have sorted the list, as it is made, via insert sort. But for simplicity ... I stored it into an array so I could see the numbers ... and thus know what was going on. (Note: Since I didn't use srand the numbers aren't truly random ... rather ... the same set of random numbers appears every time.)

Programming can be fun when you start to see what is going on and begin to enter into the problem solving process. The ability to, via a PC, quickly try out some well designed code for a well defined task and see it actually do what it was designed to do ... you may now understand something of the joy of a great creator. (The big historical danger here though, has been ... that we become so enamoured with our little creations that we ignore our own so much more Awesome Creator.)

The word Node is somewhat arbitrary ... you could use List, MyList, MyLinkedList ... or what ever might best describe all that is there' ...

But the word Node ... ( common practice is to put cap's on the first letter of structs or classes you define/create ) ... is very commonly used because it seems to well represent that idea that ONE MORE set of data, often called a data record, or in C/C++, a struct, is being discussed. The special data item included in these node or list structs ( beside any other data items ) ... is a pointer to the next node (next data record) ... i.e. each record/struct ALSO has a variable to hold the address of the next link in the chain.

Array's are often implemented as ( equal sized ) chunks of contiguous memory ... and so the address of the next element in an array can be calculated from the address of the first element ... addressFirst + ( n-1 ) * ( sizeof( each_element ) )

Thus the array[ i ] notation ... where i = 0 .. ( n-1 )

BUT ... each node in a linked list will be at the address that it was given when it was created ( in C++, via the new operator ) ... And the next node may NOT be contiguous. So ... it CAN-NOT be calculated ( from the address of the first node ) . Thus the address of each node must be stored in the pointer variable of the previous node ... a variable often named next

The memory address of the first node, (the first node is often called head or front or start ) , must be stored in a pointer variable ... like pStart ... so we can reach there ... to start.

And for the end node in a linked list ... the value in its pointer variable 'next' will be NULL ... to signal we have reached the end of the chain.

Before we have any data records or nodes ... the value in pHead is assigned NULL to signal that the list is empty.

Of course ... all the above is with respect only to the most primitive linked list ... a list that links in the forward direction only. There are many embellishments ... but this is the common simple place to start.

If you look over the examples here ... you may have noticed 2 styles:

pass/return by ref
and
pass by value and return a function value

and that both styles were alternately used.

Take your choice here.

If/when you get to C++ classes ... you may find the void function pass/return by ref style closer to what you need ... when you want to update the private class data members ... in the public member functions (that have access to all the private data as if they were global variables )

You may find that you now have all the concepts and snippets that you need to put together a suitable solution to your problem.

I applaud your approach in first attempting to get some working code for the much simpler problem of just getting some random numbers into an array of numbers and displaying them.


And from link 2  ...
http://www.dreamincode.net/forums/showtopic99329.htm

Quote
My code is supposed to give three situations...

1. If user inputs 1, then code has to list the student name and id already in the code.

2. If user inputs 2, then the code should allow the user to add a student name and id to the linked list
   to be automatically inserted as (previous id+1) ...

3. If user inputs 3, response should be to exit the program ...

(However, my program, even though it compiles, doesn't work properly ...

... to keep it simple, the program below may give you some ideas and a working start:

Note 1: this list keeps track of pTail, (as well as pHead), to facilitate appending a node (i.e. push_back)
Note 2: typedef is great if one can read a program 'top down' ...

Programming is much about defining new things,

like ...
  
  functions,
  classes,
  types,
  structs,
  #include "helper.h",
  etc ...

to aid smooth program logic flow ...

And whatever helps to make a program flow more smoothly ... including good type names ...  is highly recommended ... yes/no?

Code: [Select]
// linked_list_ex5.cpp // rev 2010-07-25

#include <iostream>
#include <string>

using namespace std;

struct Node
{
    string name;
    int id;
    Node *next;
};

typedef Node* pNode;

void push_back( pNode& head, pNode& tail, int new_id, const string& new_name )
{
    pNode pNew = new Node;
    pNew->id = new_id;
    pNew->name = new_name;
    pNew->next = NULL;

    if( head != NULL )
    {
        tail->next = pNew;
        tail = pNew;
    }
    else
        head = tail = pNew;
}

void push_front( pNode& head, pNode& tail, int new_id, const string& new_name )
{
    pNode pNew = new Node;
    pNew->id = new_id;
    pNew->name = new_name;

    pNew->next = head;
    head = pNew;
   
    if( tail == NULL )
        tail = pNew;
}

void display_all( pNode front )
{
    if( front == NULL)
    {
        cout << "The list is empty.\n";
        return;
    }
   
    int i = 0;
    while( front )
    {
        cout << "Node[" << ++i << "] is holding "
             << "ID[" << front->id << "] "
             << front->name << endl;
        front = front->next;
    }
}

void delete_all( pNode& front, pNode& back )
{
    while( front )
    {
        pNode copy  = front;
        front = front->next; // Note: when done ... front = NULL
        delete( copy ); // ok ... delete the memory 'pointed to' ...
    }
    back = NULL; // these new values are returned 'by ref'
}



int main()
{
    // get some name data ...
    const char* names[] = { "Susan", "Sarah", "Karry", "Joe" };
    const int num_names = sizeof names / sizeof names[0] ;
   
    pNode front = NULL, tail = NULL; //
   
    int id ;
    cout << "After push_back loop ... \n";
    for( id = 0; id < num_names; ++id )
        push_back( front, tail, id+1, names[id] );

    display_all( front);
    cout << endl;


    cout << "After push_back of 'visitor' ... \n";
    // note id has value num_names now ... at end of above loop
    push_back( front, tail, id+1, "Guest visitor" );
    display_all( front );
    cout << endl;

    cout << "After delete_all ... then push_front loop ... \n";
   
    delete_all( front, tail );
    for( id = 0; id < num_names; ++id )
        push_front( front, tail, ++id, names[id] );
    display_all( front );
    cout << endl;
   
    cout << "After delete_all ... \n";
   
    delete_all( front, tail );
    display_all( front );
    cout << "\nPress 'Enter' to continue ... " << flush;
    cin.get();
}

// Program output ...
/*
After push_back loop ...
Node[1] is holding ID[1] Susan
Node[2] is holding ID[2] Sarah
Node[3] is holding ID[3] Karry
Node[4] is holding ID[4] Joe

After push_back of 'visitor' ...
Node[1] is holding ID[1] Susan
Node[2] is holding ID[2] Sarah
Node[3] is holding ID[3] Karry
Node[4] is holding ID[4] Joe
Node[5] is holding ID[5] Guest visitor

After delete_all ... then push_front loop ...
Node[1] is holding ID[4] Joe
Node[2] is holding ID[3] Karry
Node[3] is holding ID[2] Sarah
Node[4] is holding ID[1] Susan

After delete_all ...
The list is empty.

Press 'Enter' to continue ...
*/

And you can now jump to the next link to see an added upgrade of the above  ... using a C++ class ...

class MyStudentList

http://developers-heaven.net/forum/index.php/topic,106.msg632.html#msg632

Note the encapsulation and data hiding ... especially to the pointers ...

Using this C++ class version ... you may not notice in your coding (outside the class) - for example, in the  main function - that pointers were even involved in using a list.
« Last Edit: July 26, 2010, 08:19:58 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #27 on: April 24, 2009, 12:09:03 PM »
Carrying on with C++ lists ...this may be a useful example for C++ students

class Student using the STL list container to hold class Student objects ...

Code: [Select]
// this revision 2010-07-25 ...

// A simple example of Student records ...
// using a C++ 'list' container to hold each 'Student' element

// 1. adds info from keyboard into a list of 'Student' records (using push_back)
// 2. shows the 'records' in memory on the screen
// 3. writes to file ...         all the records in memory
// 4. reads from file and stores all the records in memory (in a C++ list)
// 5. allows edit/erase ... to a Student record
// 6. sorts Student records by student name ...
// 7. sorts Student records by student id number ...

// Note:
// * this program allows only unique student id's for each record
// * this program is set to update its file, (if there were any changes),
//   before quitting

#include <fstream>
#include <iostream>
#include <string>
#include <list>
#include <cctype>

// Globals ...
using namespace std;

// file name of file for term's records ...
const char THIS_TERM[] = "Fall2010.txt";

const string MENU =
"\nWhat do you want to do ?\n\n"
"\t1. A dd a new student name and id ? \n"
"\t2. E dit/E rase a student record ? \n"
"\t3. S ort student records ? \n"
"\t4. V iew all in memory at present ? \n"
"\t5. U pdate file with data currently in memory ? \n"
"\t6. L oad in data from file ? \n"
"\t7. e X it program ? ";

class Student
{
public:
    // constructors ...
    Student() {}
    Student( string nName, string nId ) : name(nName), id(nId) {}

    // setters ...
    void setName( string nName ) { name = nName; }
    void setID( string nId ) { id = nId; }

    // getters ...
    string getName() { return name; }
    string getID() { return id; }
private:
    string name, // add any needed info here, just like in a C/C++ 'struct'
           id;
};


// functions used by main to process a list of Student records

// returns a valid iterator if ID is used already ... otherwise returns 0
list< Student >::iterator existID( list< Student >& term, const string& ID )
{
    list< Student >::iterator it;
    for( it = term.begin(); it != term.end(); ++it )
    {
        if( it->getID() == ID )
            return it;
    }

    return term.end();
}

// adds Student records to end of end of list of Student records ... 'term'
// gets input from keyboard ...
int newStud( list< Student >& term )
{
    cout << "\nEnter an empty record to exit this 'Input Loop' ..." << endl;
    int count = 0, reply;
    string nam, num;
    for( ;; ) // loop forever until break ...
    {
        cout << "\nID   : ";
        getline(cin, num);
        if( existID( term, num ) != term.end() )
        {
            cout << "\nThat 'id' " << num << " already exits ... " << endl;
            continue; // from the top of the forever loop right now
        }
        cout << "Name : ";
        getline(cin, nam);
        if( nam=="" || num=="")
            break;

        cout << "Add or Redo (a/r) ? ";
        reply=cin.get();
        cin.sync();
        if ( toupper(reply)!='A' )
        {
            cout << "Aborted ..." << endl;
            continue;
        }

        // ok ... create and add this record to the end of the list ...
        term.push_back( Student(nam, num) );
        ++count;
        cout << "Added ..." << endl;
    }
    return count;
}

// shows (to console screen) all student records in list container ... 'term'
void viewStuds( list< Student >& term )
{
    list< Student >::iterator it;
    int i = 0;
    for( it = term.begin(); it != term.end(); ++it )
    {
        cout << ++i << ".\n"
             << "Name   : " << it->getName() << endl
             << "Number : " << it->getID() << endl;
    }
}

// file all records in memory ... create/overwrite file with name 'THIS_TERM'
int fileStuds( list< Student >& term )
{
    ofstream fout( THIS_TERM );  // recall 'THIS_TERM' is a Global variable
    if ( !fout )
    {
        cout << "\nError attempting to open file ..." << endl;
        return -1;    // report error condition ...
    }

    // else ...
    list< Student >::iterator it;
    int i = 0;
    for( it = term.begin(); it != term.end(); ++it )
    {
        fout << it->getName() << "," << it->getID() << endl;
        ++i;
    }

    fout.close();

    if( i == (int)term.size() )
        cout << "\nAll " << i << " records filed ok." << endl;
    else
        cout << "\nOnly " << i << " of " << term.size()
             << " records were written ..." << endl;

    return i; // report success ... i.e. report count of records filed
}

// reads in all Student records from file 'THIS_TERM' ... if it exists
// returns -1 if no file exists; else returns the number of records read
int readStuds( list< Student >& term )
{
    ifstream fin( THIS_TERM ); // recall THIS_TERM is a Global variable
    if ( !fin )
    {
        cout << "Error attempting to open file ... "
             << "(Perhaps it dosen't exist yet?)" << endl;
        return -1;          // report error condition ...
    }

    // else ... check existing term.size() first before re-set
    if( term.size() ) // i.e. if not == 0 ...
    {
        cout << "\nDo you want over-write the " << term.size()
             << " records in memory (y/n) ? " << flush;
        char reply = toupper( cin.get() );
        cin.sync();
        if( reply != 'Y' )
        {
            cout << "Aborted ... " << flush;
            return 0;
        }
        // if reach here ...
        cout << "Ok ... will over-write the " << term.size()
             << " records in memory ... " << flush;
    }

    // if reach here ...
    term.clear(); // list is empty now ...
    string nam, num;
    int i;
    for( i=0; getline( fin, nam, ',' ); ++i ) //first get 1st string (up to ',')
    {
        getline( fin, num, '\n' ); // then get rest of line (up to '\n')
        term.push_back( Student(nam, num) ); // construct and add new Student
    }
    fin.close();
    return i; // report success? ... i.e. return the record count ...
}

// returns 'true' if a record was edited or erased; otherwise returns false
bool editStud( list< Student > &term )
{
    cout << "\nEnter an empty record to exit this 'Edit/Erase Function' ..."
         << "\nEnter the ID of the student record to edit ? " << flush;
    string idStr, nam;
    getline( cin, idStr );

    list< Student >::iterator i, index;
    i =  existID( term, idStr );
    if( i == term.end() )
    {
        cout << "This '" << idStr << "' does not exist." << endl;
        return false;
    }

    // else ... show ... and ask if ok to edit ...
    cout << "Name   : " << i->getName() << endl
         << "Number : " << i->getID() << endl

         << "Ok to edit/erase (y/n) ? " << flush;

    int reply = toupper( cin.get() );
    cin.sync();
    if( reply != 'Y' )
    {
        cout << "Aborted ... " << endl;
        return false;
    }

    cout << "\nDo you want to erase this record (y/n) ? " << flush;
    reply = toupper( cin.get() );
    cin.sync();
    if( reply == 'Y' )
    {
        term.erase( i );
        cout << "Erased ..." << endl;
        return true;
    }


    // else ...

    cout << "\nOk ... will edit then ...\nNew ID   : ";
    getline(cin, idStr);
    index = existID( term, idStr );
    if( index != term.end() && index!= i )
    {
        cout << "\nThat " << idStr << " already exits ... " << endl;
        return false; // exit to menu now ...
    }

    cout << "New Name : ";
    getline(cin, nam);
    if( nam=="" || idStr=="")
        return false;

    cout << "Ok or Redo (o/r) ? ";
    reply=cin.get();
    cin.sync();
    if( toupper(reply)!='O' ) // cap 'O' ... as in Ok
    {
        cout << "Aborted ..." << endl;
        return false;
    }

    // ok ... do edit
    i->setName( nam );
    i->setID( idStr );
    cout << "Edited ..." << endl;
    return true;
}

// name comparison here is NOT case sensitive ...
bool compare_nocaseName(Student& first, Student& second)
{
  unsigned int i=0;
  while( i<first.getName().length() && i<second.getName().length() )
  {
    if( tolower(first.getName()[i]) < tolower(second.getName()[i]) ) return true;
    else if( tolower(first.getName()[i]) > tolower(second.getName()[i]) ) return false;
    ++i;
  }
  if( first.getName().length() < second.getName().length() ) return true;
  else return first.getID() < second.getID();;
}

bool compare_id(Student& first, Student& second)
{
    return first.getID() < second.getID();
}

void pauseForEnter()
{
    cout << "\nPress 'Enter' to continue ... " << flush;
    cin.sync();
    cin.get();
}



int main()
{
    // create a 'fall list' to hold student names and ids for the 'Fall Term'
    // also holds number of records, via 'fall.size()'
    list <Student > fall;

    // now get all records from file ... if it exists ?
    int count = readStuds( fall );
    if( count >= 0 )
        cout << count << " student record(s) read into memory ..." << endl;
    else
        cout <<"(The file will be created when some student records exist.)"
             <<endl;

    bool changes = false; // set 'update file flag' to initial value ...
    int reply;
    for( ;; ) // loop forever ... until break ...
    {
        cout << MENU;
        reply = toupper(cin.get());
        cin.sync(); // flush cin stream ...

        if( reply == '1' || reply == 'A' )
        {
            int numStuds = newStud( fall );
            cout << endl << numStuds << " student record(s) added ..."
                 << " The total number of student records now is "
                 << fall.size() << endl;
            if( numStuds )
                changes = true; // if >0 update bool variable changes
        }
        else if( reply == '2' || reply == 'E' )
        {
            if( editStud( fall ) )
                changes = true;
        }
        else if( reply == '3' || reply == 'S' )
        {
            cout << "\nSort by id or name  (i/n) ? " << flush;
            reply = toupper( cin.get() );
            cin.sync();
            cout << "Now sorted in memory by ";
            if( reply == 'I' )
            {
                fall.sort(compare_id);
                cout << "id. ";
            }
            else
            {
                fall.sort(compare_nocaseName);
                cout << "name. ";
            }
            cout << "Update file (y/n) ? " << flush;
            reply = toupper( cin.get() );
            cin.sync();
            if( reply == 'Y' )
            {
                changes = true;
                cout << "File to be updated ...\n";
            }
        }
        else if( reply == '4' || reply == 'V' )
            viewStuds( fall );
        else if( reply == '5' || reply == 'U' )
        {
            if( !changes )
                cout << "\nNo changes to file ..." << endl;
            else
            {
                cout << "Are you sure you want to update the file (y/n) ? "
                     << flush;
                reply = toupper( cin.get() );
                cin.sync();
                if( reply == 'Y' )
                {
                    if( fileStuds( fall ) != (int)fall.size() )
                        cout << "\nUNEXPECTED ERROR! NOT all records were filed!"
                             << "\nTry again ... If Error persits call IT."
                             << endl;
                    else
                    {
                        changes = false;// update file flag ...
                        cout << "File write operation confirmed." << endl;
                    }
                }
            }
        }
        else if( reply == '6' || reply == 'L' )
        {
            int condition = readStuds( fall );
            if(  condition >= 0 )
            {
                cout << "\nThere were " << condition
                     << " student records read into memory from file." << endl;
                if( condition > 0 ) changes = false;
            }
        }
        else if( reply == '7' || reply == 'X' )
        {
            if( changes ) // then ...
                fileStuds( fall );
            break; // and exit program ...
        }
        else
        {
            cout << "\nThis choice not implemented yet ... " << endl;
        } // end of if( reply == ? ) switch structure ...

    } // end of forever loop ...


    // debug exit routine ...

    ifstream ftest( THIS_TERM );  // recall 'THIS_TERM' is a Global variable
    if ( !ftest )
    {
        cout << "\nError attempting to open file ..." << endl;
        pauseForEnter();
        return -1;    // report error condition ...
    }

    // if reach here ... first ...
    ftest.close();

    // then ... proceed ... to open the file in a system text editor ...

    // if you have a Win OS ... show structure of file
    string tmpSee = " ";
    tmpSee = "notepad" + tmpSee + THIS_TERM;
    system( tmpSee.c_str() );
}

« Last Edit: September 07, 2010, 06:57:49 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #28 on: April 24, 2009, 12:13:24 PM »
And something similar in C ...

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. strlen, strcmp */

/*
    C/C++ students may like to see ...

    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

/* Globals ... */

#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 "1. (I)nitialize Student record list in RAM\n" \
                "2. (A)dd i.e. insert in order, by name, a NEW Student record\n" \
                "3. view/(D)elete a Student record\n" \
                "4. view/(E)dit a Student record\n" \
                "5. (S)how all Student records (as inserted BY NAME above)\n" \
                "6. (F)ile all Student records presently in RAM\n" \
                "7. (R)ead all Student records on file into RAM\n" \
                "8. set/change (P)assword\n" \
                "9. e(X)it"

#define fName "Studentinfo.txt"
#define fPW "StudentPW.txt"
#define minPWLen 8
#define maxStringLen 20

#define sortRead 1

typedef struct Student
{
    int id;
    char* last;
    char* first;
    float test1;
    float test2;
    float assignment;
    float labtest;
    float finalexam;
    struct Student* next;
} Student ;

typedef Student* pStudent;

/* can use these global var's to keep function calls much simpler ... */
pStudent phead = NULL;
int numStudents = 0; /* to hold 'the number of Student records in memory' ...*/
int pwOK = 0;        /* to hold 'the password was OK' flag; 0=false & 1=true */
int fileFlag = 0;    /* fileFlag indicates 'the need to update the file' ... */

/* forward declarations */

pStudent pID(int n);
char* getLine( FILE* fp );
/* char* newCopy( char* str ); */
void add();
void insert( pStudent pS );
void flushStdin();
void showAll();
void viewEdit();
void viewDel();
void view(pStudent pS);
void edit(pStudent pS);
void del(pStudent pS);
void delAll();
void init();
void scramble( char s[] );
void unscramble( char s[] );
void writeAllToFile();
void exitNowYes();
int writeFile();
int readFile();
int passWord();
int newPW();
int StudentCmp( pStudent pS1, pStudent pS2 );

int menu()
{
    int c, selection;
    puts( header1 );
    if( numStudents == 1 ) puts( "Presently there is 1 record in RAM.\n" );
    else printf( "Presently there are %d records.\n\n", numStudents );
    puts( header2 );
    printf( "\nPlease enter your selection  : " );
    selection = c = getchar();
    while( c!='\n' ) c=getchar(); /* 'flush' stdin */
    return selection;
}

void myAssert( int condition, char text[] )
{
    if( !condition )
    {
        fprintf( stderr, "%s.  Press 'Enter' to exit ... ", text );
        getchar();
        exit(1);
    }
}


int main() /* main start * * * * * * * * * * * * * * * * * * * * * * * * * * */
{
    pwOK = passWord();
    numStudents = readFile();
    for(;;) /* Loop forever ... until 'return' ... */
    {
        int choice = -1; /*  error flag */
        if( !pwOK )
            pwOK = passWord();
        choice = menu();
        /* printf("You picked %d ... \n", choice ); */
       
        switch( choice )
        {
            case '1': case 'i': case 'I': init(); break; /* out of 'switch' */
            case '2': case 'a': case 'A': add();  break;
            case '3': case 'd': case 'D': viewDel(); break;
            case '4': case 'e': case 'E': viewEdit(); break;
            case '5': case 's': case 'S': showAll(); break;
            case '6': case 'f': case 'F': writeAllToFile(); break;
            case '7': case 'r': case 'R':
            {
                /* If any were read ... will update Global variable phead */
                int readNum = readFile();
                if( readNum > 0 )
                    numStudents = readNum; /* update Global numStudents */
            }
            break;
            case '8': case 'p': case 'P': pwOK = newPW(); break;
            case '9': case 'x': case 'X': exitNowYes(); break;
            default: puts("\nNot implemented yet ...");
        } /* end switch */
    } /* end for ... */
    return 0;
} /* main end * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

Function definitions are on the next page ...
« Last Edit: April 09, 2010, 09:17:48 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: New thread especially for students of C and C++
« Reply #29 on: April 24, 2009, 12:15:18 PM »
Functions for the above C program are given below ...


Code: [Select]
/* Function definitions ... */

char* getLine( FILE* fp )
{
    int c, i=0;
    char* buffer = (char*) calloc( maxStringLen+1, 1 );
    myAssert( (buffer!=NULL), "Error: calloc failed to allocate memory" );
    buffer[0] = 0; /* NULL terminate 'as we go' ... */

    /* eats up WHOLE line ... including '\n' */
    while( (c=fgetc(fp)) != EOF && c != '\n' )
    {
        if( i<maxStringLen )
        {
            buffer[i] = c;
            ++i;
            buffer[i] = 0;
        }
    }
    buffer = (char*) realloc( buffer, i+1  );
    myAssert( (buffer!=NULL), "Error: realloc failed to allocate memory" );
    return buffer;
}

/*
char* newCopy( char* str )
{
    int i, len=strlen( str );
    //while( str[len]!=0 ) ++len;
    char * nCopy = (char*) malloc( len+1 );
    myAssert( (nCopy!=-NULL), "Error: malloc failed to allocate memory" );
    for( i=0; i<len; ++i ) nCopy[i] = str[i];
    nCopy[len] = 0;
    return nCopy;
}
*/

/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pID( int n )
{
    pStudent p = phead;
    if( p==NULL )
        return NULL; /* List empty ... so all id numbers are available */

    while( p!=NULL )
    {
        if( p->id == n )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    }

    /* If reach here ... then id number not in list so ... */
    return NULL;
}

void flushStdin()
{
    while( getchar() != '\n' );
}

void exitNowYes()
{
    int c, quit;
    printf("\nPress 'X' to eXit  ... ");
    c = quit = getchar();
    while(c != '\n') c=getchar(); /* flush stdin ... */
    if( quit=='x' || quit=='X' )
    {
        if( fileFlag ) writeAllToFile();
        printf("\nPress 'Enter' to exit right now ... ");
        if( (c=getchar()) == '\n' ) exit(0);
        else while(c != '\n') c=getchar(); /* flush stdin ... */
    }
}

void add() /* ... and insert in the proper place in the list. */
{
    pStudent pS;
    int ID = 0;
    printf("Enter ID         : ");
    scanf("%d", &ID); flushStdin();

    if( pID(ID) || ID<=0  ) /* if pointer returned is NOT NULL, id IS used */
    {
        printf("\nid %d is NOT available.\n", ID );
        return; /* Exit to menu right now ... */
    }
    /* If program reaches here, the ID just entered is available to use. */
    pS = (pStudent) malloc(sizeof(Student));
    myAssert( (pS!=NULL), "Error: malloc failed to allocte memory" );
    pS->id = ID;

    printf("Enter Last Name  : ");
    pS->last = getLine(stdin);
    printf("Enter First Name : ");
    pS->first = getLine(stdin);

    printf("Enter Test1      : ");
    scanf( "%f", &pS->test1 );      flushStdin();
    printf("Enter Test2      : ");
    scanf( "%f", &pS->test2 );      flushStdin();
    printf("Enter Assignment : ");
    scanf( "%f", &pS->assignment ); flushStdin();
    printf("Enter Lab Test   : ");
    scanf( "%f", &pS->labtest );    flushStdin();
    printf("Enter Final Exam : ");
    scanf( "%f", &pS->finalexam );  flushStdin();

    /* Set up link to this node */
    insert( pS );
}

/* insert in list with last & first names in proper order */
void insert( pStudent pS )
{
    /* Firstly, we handle the case where 'this' should be the first element. */
    if(phead == NULL || StudentCmp(pS, phead) < 0)
    {
        /* So ... it now becomes the first element ... */
        pS->next = phead; /* old phead becomes 2nd in list ... */
        phead = pS; /* and ... this pS ... becomes the head of the list */
    }
    else /* If here ... search the linked list for the right location ... */
    {
        pStudent q = phead; /* Get a working copy of phead in q */
        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while(q->next != NULL && StudentCmp(q->next, pS) <= 0)
        {
            q = q->next; /* Traverse the list ... */
        }
        /*
            Ok, insert after 'q' by relinking the pointers (similar to above)
            ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
        q->next = pS;  /* Now 'q' is updated to link to the new 'pS' element */
    }

    /* Update global variables. */
    ++numStudents;
    fileFlag = 1;
}

void showAll()
{
    pStudent p = phead;
    int c;

    if (phead==NULL)
    {
        puts("\nNo records in memory at present.") ;
        return;
    }

    /* If reach here ... */
    
    while( p!=NULL )
    {
        view( p );
        printf("\nPress 'Enter' to continue ... or enter 'A' to abort ... ");
        if( (c=getchar()) == 'a' || c == 'A' )
        {
            flushStdin();
            return;
        }
        while(c != '\n') c=getchar(); /* flush stdin ... */
        p = p->next;
    }
}

void viewEdit()
{
    int yes = 0, ID = 0;
    pStudent p;

    printf("Enter the id number to View/Edit : ");
    scanf("%d",&ID); flushStdin();

    p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p )     /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nEdit (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' )
        {
            while( yes!='\n' ) yes=getchar(); /* flush stdin */
            edit(p);
        }
        else while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void view(pStudent pS)
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %.2f\n"
        "Test 2     : %.2f\n"
        "Assignment : %.2f\n"
        "Lab Test   : %.2f\n"
        "Final Exam : %.2f\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );
}

void edit(pStudent pS)
{
    int ID = 0;
    int idTmp = pS->id; /* Firstly get a backup copy of this id ... */
    pS->id = -1; /* Now ... reset old id number to a dummy value ... */
    
    printf("Edit ID          : ");
    scanf("%d", &ID); flushStdin();
    if( pID(ID) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
    {
        printf("\nid %d is NOT available.\n", ID );
        pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to menu right now ... */
    }

    /* If reach hear ... */

    del(pS);/* Delete old record ... etc */

    pS = (pStudent) malloc(sizeof(Student)); /* get new memory for new record */
    myAssert( (pS!=NULL), "Error: malloc failed to allocte memory");
    pS->id = ID;

    printf("Edit Last Name   : ");
    pS->last = getLine(stdin);
    printf("Edit First Name  : ");
    pS->first = getLine(stdin);

    printf("Edit Test1       : ");
    scanf( "%f", &pS->test1 );      flushStdin();
    printf("Edit Test2       : ");
    scanf( "%f", &pS->test2 );      flushStdin();
    printf("Edit Assignment  : ");
    scanf( "%f", &pS->assignment ); flushStdin();
    printf("Edit Lab Test    : ");
    scanf( "%f", &pS->labtest );    flushStdin();
    printf("Edit Final Exam  : ");
    scanf( "%f", &pS->finalexam );  flushStdin();

    insert( pS );
}

void viewDel()
{
    pStudent p;
    int yes = 0, ID = 0;

    printf("Enter the id number to View/Delete : ");
    scanf("%d",&ID); flushStdin();

    p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nDelete (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' ) { del(p); fileFlag = 1; }
        while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void del(pStudent pS)
{
    pStudent p,
             pp; /* to hold the pointer to the previous record */

    /* Handle special case of 'first in list' */
    if( pS==phead )
    {
        phead = pS->next;
        free( pS->first );
        free( pS->last );
        
        free( pS );
        --numStudents; /* update globals ... */
        fileFlag = 1;
        return;
    }

    /* Else not first in list, so ... */

    p = phead; /* set p to this initial value to start loop */

    /* Now find the pointer to the previous record. */
    while( p != pS )
    {
        pp = p; /* pp holds previous pointer value ... */
        p = p->next; /* set to next pointer in link list chain */
    }

    /*
        Now we have a pointer to the previous Student record, so ...
        we can now point that previous record to one past this pS record
    */
    pp->next = pS->next;

    /* Now free the memory for this record and update the globals ... */
    free( pS->first );
    free( pS->last );
    
    free( pS);
    --numStudents;
    fileFlag = 1;
}

void delAll()
{
    pStudent p = phead; /* Set p to this initial value to start loop */
    pStudent pNext;     /* To hold the pointer to the next record */

    while( p != NULL )
    {
        pNext = p->next; /* Get a pointer to the next record. */
        free( p->first );
        free( p->last );
        
        free( p );
        p = pNext; /* Update p ... */
    }

    /* Update globals ...  */
    phead = NULL;
    numStudents = 0;
    fileFlag = 0;
}

/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
    int yes;
    if( phead != NULL )
    {
        printf("\nDo you wish to overwrite the records in memory y/n ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' )
            delAll(); /* re-sets globals ... */
        else
        {
            if(numStudents==1)
                puts("1 Student record was left intact in memory.");
            else
                printf("%d Student records were left intact in memory.\n",
                       numStudents);
        }
        while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else puts("\nThere were no records in memory to clear.");
}

void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] - code[i]); ++i; }
}

void unscramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] + code[i]); ++i; }
}

void writeAllToFile()
{
    if( !fileFlag ) return;

    if( numStudents == writeFile() )
    {
        if( numStudents > 0 )
        {
            if( numStudents == 1 )
                puts("\nThe 1 Student record was safely filed.");
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    numStudents
                );
        }
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        flushStdin(); /* Holds window open to show above message. */
        exit(0); /* Return error number to system. */
    }
}

int writeFile()
{
    int count; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = phead;

    if( phead==NULL )
    {
        puts("\nNo records available ... so NO records written to file.") ;
        return 0;
    }

    fp = fopen( fName, "w" );
    if( fp==NULL )
    {
        printf("\nError opening file %s.  Press 'Enter' to continue ... ", fName);
        flushStdin();
        return 0;
    }

    count = 0; /* to track the records actually written to the file */
    while( p!=NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n"
            "%.2f\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );

        ++count;
        p = p->next;
    }

    fclose( fp );
    fileFlag = 0;
    return count; /* Number of records written. */
}

int readFile()
{
    int count, ID;
    /* char buffer[maxStringLen+1]; */
    FILE *fp;

    pStudent pS;
#if !sortRead
    pStudent pp=NULL;
#endif

    fp = fopen( fName, "r" );
    if( fp==NULL )
    {
        printf
        (
            "\nError opening file %s.\n"
            "Perhaps it hasn't been created yet?\n"
            "Press 'Enter' to continue ... ",
            fName
        );
        flushStdin();
        return 0;
    }

    /* BUT!!! may need to delete any records in memory first. */
    init();

    /*
        NOTE: we need phead to be equal to NULL in the following ...
        to be permitted to set phead ...
        to point to the first Student record in memory (read in from the file).
    */
    if( phead != NULL ) /* then exit with message ... */
    {
        if(numStudents==1)
            puts("\nThe 1 former Student record was left in memory.");
        else
            printf("\nThe %d former Student records were left in memory.\n", numStudents);
        return 0; /* So ...old count of Student records will NOT be updated. */
    }

    /* If the program reaches here ... then ... */

    count = 0;

    while(  fscanf( fp, "%d", &ID) != EOF  )
    {
        pS = (pStudent) malloc(sizeof(Student));
        pS->id = ID;

        //fscanf( fp, "%s", buffer );
        //pS->last = newCopy( buffer );
        fgetc(fp); /* eats up the '\n' char left over from above 'ID read' */
        pS->last = getLine(fp);

        //fscanf( fp, "%s", buffer );
        //pS->first = newCopy( buffer );
        pS->first = getLine(fp);

        fscanf( fp, "%f", &pS->test1 );
        fscanf( fp, "%f", &pS->test2 );
        fscanf( fp, "%f", &pS->assignment );
        fscanf( fp, "%f", &pS->labtest );
        fscanf( fp, "%f", &pS->finalexam );
#if !sortRead
        if ( pp != NULL )   /* for 2nd and up records ...*/
            pp->next = pS;  /* now previous record points to this new one */
        else phead =pS;     /* first record only has base pointer */

        pS->next = 0; /* NULL terminate list ... */
        pp = pS; /* Keep a copy of address of this pS in pp for next while loop. */
#else
        insert( pS );
#endif
        ++count;
        /* printf( "\nRecord number is %d\n", count ); */
    }
    fclose( fp );
    if(count==1)
        puts("\n1 record was read into memory from the disk file.");
    else
        printf("\n%d records were read into memory from the disk file.\n", count);

    fileFlag = 0;
    return count; /* Total number of Student records found in the file. */
}

int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char *buffer1;
    char buffer2[maxStringLen+1];
    int attempts;
    int pwOK = 0;
    
    FILE *fp = fopen(fPW, "r");
    if(fp==NULL) /* i.e. if file fPW doesn't exit ... */
    {
        pwOK = newPW(); /* get new password ...*/
        if( pwOK == 1 ) return 1; /* report this match of passwords back ...*/
    }
    else /* File fPW does exist ... so ... */
    {
        /* Get file password into a string in buffer2. */
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );

        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts=0; attempts<3; ++attempts )
        {
            printf("Enter password: ");
            //scanf( "%s", buffer1 ); flushStdin();
            buffer1 = getLine(stdin);
            if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    exit(1); /* Quit the program right now ... */
}

int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;

    for(;;)
    {
         /* Get the new password into a string in buffer1. */
        printf("Enter the new password (8 to 20 characters): ");
        buffer1 = getLine(stdin); /* a max of maxStringLen char's */
        if( strlen(buffer1) >= minPWLen )
            break;

        printf("Your password must be at least %d characters ...\n", minPWLen );
        free( buffer1 ); /* ... and try again ...*/
    }

    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    printf("Enter the new password again: ");
    buffer2 = getLine(stdin);
    if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
    {
        fp = fopen(fPW, "w");
        if(fp==NULL)
        {
            printf("Error opening file %s ... Press 'Enter' to exit ... ", fPW);
            flushStdin();
            free(buffer2);
            free(buffer1);
            exit(2);
        }
        else
        {
            puts( "Match!\n" );
            scramble(buffer1);
            fprintf( fp, "%s", buffer1 );
            fclose( fp );
            free(buffer2);
            free(buffer1);
            return 1; /* Report this match of passwords back ...*/
        }
    }

    /* If reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    free(buffer2);
    free(buffer1);
    exit(3); /* Quit the program right now ... */
}

/* A function to compare two Student records to permit sorting ... */
int StudentCmp( pStudent pS1, pStudent pS2 )
{
    int compare = strcmp(pS1->last, pS2->last);
    if ( compare == 0 )
        return strcmp(pS1->first, pS2->first);

    return compare;
}
« Last Edit: May 26, 2010, 09:07:41 PM by David »