Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   C++ help: Understanding pointers? (http://www.chiefdelphi.com/forums/showthread.php?t=104890)

Ginto8 22-03-2012 21:17

Re: C++ help: Understanding pointers?
 
Quote:

Originally Posted by ctccromer (Post 1147879)
Okay so after reading all of this and getting (what I think is) a better understanding of pointers, I attempted my book's chapter's next practice problem:

I'm just filling it with an incrementing value rather than multiplication tables

Here's the code I wrote. It has 2 main errors that repeat many times that the compiler picked up and I wouldn't be surprised if there were several more. It looks like a lot, but you'll quickly realize that it's very small, quick, and (hopefully) simple so please don't be put off by its size.
So what's wrong with this and how can I fix it?
Please ignore the fact that I made it a 3x? 2dimensional array instead of a 3dimensional array. I noticed that towards the end of writing this but that's not the main focus of the exercise so I'll fix that later.
[code]

So I looked at your code and fixed it. As I did, I added comments and showed what I changed it from. To distinguish them, my comments are not indented:
Code:

//get 3 user-input values and make a 3dimensional array with those dimensions.  Allocate that much memory.

#include <iostream>
using namespace std;

// See at implementation
void setValues(int *a, int *b, int *c, int arrayOne[], int arrayTwo[], int arrayThree[]); // void setValues(int *a, int *b, int *c, int *arrayOne[], int *arrayTwo[], int *arrayThree[]);
void showValues(int *a, int *b, int *c, int arrayOne[], int arrayTwo[], int arrayThree[]); // void showValues(int *a, int *b, int *c, int *arrayOne[], int *arrayTwo[], int *arrayThree[]);

int main()
{
    int firstNumber;
    int *p_firstNumber = & firstNumber;
    int secondNumber;
    int *p_secondNumber = & secondNumber;
    int thirdNumber;
    int *p_thirdNumber = & thirdNumber;

    //get the 3 sizes
    cout << "Give me a length, width, and height!\n";
    cout << "Length: "; cin >> firstNumber;
    cout << "Width: "; cin >> secondNumber;
    cout << "Height: "; cin >> thirdNumber;

    //create the pointer version of the 3dimensional array
    int **p_p_fullArray = new int*[3]; // int **p_p_fullArray = new int[3];
    int *p_firstArray = new int[firstNumber];
    int *p_secondArray = new int[secondNumber];
    int *p_thirdArray = new int[thirdNumber];

    //set the 3 1dimensional arrays to the full array
    p_p_fullArray[0] = p_firstArray; // p_p_fullArray[0] = & p_firstArray;
    p_p_fullArray[1] = p_secondArray; // p_p_fullArray[1] = & p_secondArray;
    p_p_fullArray[2] = p_thirdArray; // p_p_fullArray[2] = & p_thirdArray;

// this part is trying to statically allocate an array with a length derived from
// a runtime value (illegal), and then leaks memory because you're removing the arrays
// you allocated using new
/*
    //create normal variables for the 3dimensional array
    int firstArray[firstNumber];
    int secondArray[secondNumber];
    int thirdArray[thirdNumber];

    //set the 3 1dimensional pointers to the 3 1dimensional variables
    p_firstArray = & firstArray;
    p_secondArray = & secondArray;
    p_thirdArray = & thirdArray;
*/

// functions are called by passing values, not by declaring what types those values are
    //assign something to every cell in the array
    setValues(p_firstNumber, p_secondNumber, p_thirdNumber, p_firstArray, p_secondArray, p_thirdArray); // setValues(int *p_firstNumber, int *p_secondNumber, int *p_thirdNumber, int *p_firstArray[], int *p_secondArray[], int *p_thirdArray[]);

    //show the array (easy way to make sure the program worked)
    cout << "\nCool thanks.  Here's your array:" << endl;
// same as before
    showValues(p_firstNumber, p_secondNumber, p_thirdNumber, p_firstArray, p_secondArray, p_thirdArray); // showValues(int *p_firstNumber, int *p_secondNumber, int *p_thirdNumber, int *p_firstArray[], int *p_secondArray[], int *p_thirdArray[]);

// delete is not enough for arrays. delete normally just calls a destructor and deallocates memory for a single instance.
// If you want to deallocate an array, you should use delete [].
//
// Although setting pointers to NULL when you're done with them is a good idea, if you aren't
// going to use them again (in a situation like, for example, your program ending), there's no point
    //free the allocated memory and make sure the pointers don't grab on to anything random and cause issues
    delete [] p_p_fullArray; // delete p_p_fullArray;
    p_p_fullArray = NULL;
    delete [] p_firstArray; // delete p_firstArray;
    p_firstArray = NULL;
    delete [] p_secondArray; // delete p_secondArray;
    p_secondArray = NULL;
    delete [] p_thirdArray; // delete p_thirdArray;
    p_thirdArray = NULL;
// you tried to delete statically allocated memory. This messes stuff up.
/*
    delete p_firstNumber;
    p_firstNumber = NULL;
    delete p_secondNumber;
    p_secondNumber = NULL;
    delete p_thirdNumber;
    p_thirdNumber = NULL;
*/
}

// a note on parameters: arrays, when used as function parameters, degenerate and become identical
// to pointers. Therefore, you're asking for 3 int**s, which is definitely not what you passed. Pick
// either * or [], whichever better represents how you use it.
void setValues(int *a, int *b, int *c, int arrayOne[], int arrayTwo[], int arrayThree[]) // void setValues(int *a, int *b, int *c, int *arrayOne[], int *arrayTwo[], int *arrayThree[])
{
    int value = 0;

// you have to dereference a pointer to be able to use it as a normal value
//
// also, i j and k each go out of scope after each loop, so you don't have to
// choose a different name for each. Name them all i and they'll technically
// be different variables, but will still be called i. Consistency is good, and
// coming up with a new name for the iterator in each loop is pointless.
    for (int i = 0; i < *a; i++) // for (int i = 0; i < a; i++)
    {
// since you don't pass in an int**, don't use it as one       
        arrayOne[i] = value; // *arrayOne[i] = value;
        ++value;
    }

    for (int j = 0; j < *b; j++) // for (int j = 0; j < b; j++)
    {
        arrayTwo[j] = value; // *arrayTwo[j] = value;
        ++value;
    }

    for (int k = 0; k < *c; k++) // for (int k = 0; k < c; k++)
    {
        arrayThree[k] = value; // *arrayThree[k] = value;
        ++value;
    }
}

// same as above
void showValues(int *a, int *b, int *c, int arrayOne[], int arrayTwo[], int arrayThree[]) // void showValues(int *a, int *b, int *c, int *arrayOne[], int *arrayTwo[], int *arrayThree[])
{
    cout << "first row: ";
// same situation. Dereference, dereference, dereference!
    for (int i = 0; i < *a; i++) // for (int i = 0; i < a; i++)
    {
        cout << arrayOne[i] << " ";
    }

    cout << "\nsecond row: ";
    for (int j = 0; j < *b; j++) // for (int j = 0; j < b; j++)
    {
        cout << arrayTwo[j] << " ";
    }

    cout << "\nthird row: ";
    for (int k = 0; k < *c; k++) // for (int k = 0; k < c; k++)
    {
        cout << arrayThree[k] << " ";
    }
}

However, as you said, this does not actually do what it was supposed to do, and there were some things about it that could have been done better, so I wrote my own as an example:
Code:

#include <iostream>
#include <sstream>
using namespace std;

// once created, arr[i][j][k] will be the product i*j*k
int*** makeMultTable(int l,int w,int h) {
    if(l <= 0 || w <= 0 || h <= 0)
        return NULL;
    // allocate top-layer containing array
    int*** ret = new int**[l];
    for(int i=0;i<l;++i) {
        // allocate array to store rows
        ret[i] = new int*[w];
        for(int j=0;j<w;++j) {
            // allocate individual row
            ret[i][j] = new int[h];
            // set each row element to its value in the multiplication table
            for(int k=0;k<h;++k)
                ret[i][j][k] = i*j*k;
        }
    }
    return ret;
}

void printTable(int*** table,int l,int w,int h) {
    if(!table || l <= 0 || w <= 0 || h <= 0)
        return;
    // find longest possible int
    // used for prettifying the grid
    stringstream digitTest;
    // if i, j, and k are less than l, w, and h respectively,
    // then the largest value of i*j*k is (l-1)*(w-1)*(h-1)
    digitTest << (l-1)*(w-1)*(h-1);
    // find greatest amount of digits for prettification
    int digitLength = digitTest.str().length();
    // go by layers because text is only 2 dimensional at best
    for(int i=0;i<l;++i) {
        cout << "i = " << i << ":" << endl;
        for(int j=0;j<w;++j) {
            // go through each element in the row
            for(int k=0;k<h;++k) {
                // reset prettifying stream
                digitTest.str("");
                // single grid element
                digitTest << table[i][j][k];
                // prettify the element
                while(digitTest.str().length() < digitLength)
                    digitTest << " ";
                // no extra space needed at the end of a row
                if(k != h-1)
                    digitTest << " ";
                // output prettified element
                cout << digitTest.str();
            }
            // row done
            cout << endl;
        }
        // layer done
        cout << endl;
    }
}

void freeMultTable(int*** table,int l,int w,int h) {
    if(!table || l <= 0 || w <= 0 || h <= 0)
        return;
    // delete contents from the inside out
    for(int i=0;i<l;++i) {
        for(int j=0;j<w;++j)
            // delete individual row
            delete [] table[i][j];
        // delete one layer
        delete [] table[i];
    }
    // delete whole table
    delete [] table;
}

int main() {
    int l,w,h;
   
    cout << "Length? ";
    cin >> l;
    cout << "Width? ";
    cin >> w;
    cout << "Height? ";
    cin >> h;
   
    int*** table = makeMultTable(l,w,h);
   
    printTable(table,l,w,h);
   
    freeMultTable(table,l,w,h);
   
    return 0;
}

Then, since I noticed that the table could be well-represented as a class, I converted it to OOP:
Code:

#include <iostream>
#include <sstream>
#include <stdexcept>
using namespace std;

class MultTable {
    int*** table;
    int l,w,h;
public:
    MultTable(int l_,int w_,int h_) : l(l_),w(w_),h(h_) {
        if(l <= 0 || w <= 0 || h <= 0)
            throw runtime_error("Invalid dimensions");
        // allocate top-layer containing array
        table = new int**[l];
        for(int i=0;i<l;++i) {
            // allocate array to store rows
            table[i] = new int*[w];
            for(int j=0;j<w;++j) {
                // allocate individual row
                table[i][j] = new int[h];
                // set each row element to its value in the multiplication table
                for(int k=0;k<h;++k)
                    table[i][j][k] = i*j*k;
            }
        }
    }
    ~MultTable() {
        if(!table || l <= 0 || w <= 0 || h <= 0)
            return;
        // delete contents from the inside out
        for(int i=0;i<l;++i) {
            for(int j=0;j<w;++j)
                // delete individual row
                delete [] table[i][j];
            // delete one layer
            delete [] table[i];
        }
        // delete whole table
        delete [] table;
    }
   
    int get(int i,int j,int k) const {
        if(i <= 0 || j <= 0 || k <= 0 ||
          i >= l || j >= w || k >= h)
            throw runtime_error("Index out of range");
    }
   
    string toString() const {
        stringstream out;
        // find longest possible int
        // used for prettifying the grid
        stringstream digitTest;
        // if i, j, and k are less than l, w, and h respectively,
        // then the largest value of i*j*k is (l-1)*(w-1)*(h-1)
        digitTest << (l-1)*(w-1)*(h-1);
        // find greatest amount of digits for prettification
        int digitLength = digitTest.str().length();
        // go by layers because text is only 2 dimensional at best
        for(int i=0;i<l;++i) {
            out << "i = " << i << ":" << endl;
            for(int j=0;j<w;++j) {
                // go through each element in the row
                for(int k=0;k<h;++k) {
                    // reset prettifying stream
                    digitTest.str("");
                    // single grid element
                    digitTest << table[i][j][k];
                    // prettify the element
                    while(digitTest.str().length() < digitLength)
                        digitTest << " ";
                    // no extra space needed at the end of a row
                    if(k != h-1)
                        digitTest << " ";
                    // output prettified element
                    out << digitTest.str();
                }
                // row done
                out << endl;
            }
            // layer done
            out << endl;
        }
        return out.str();
    }
};

ostream& operator<<(ostream& o,const MultTable& multTable) {
    return o << multTable.toString();
}

int main() {
    int l,w,h;
   
    cout << "Length? ";
    cin >> l;
    cout << "Width? ";
    cin >> w;
    cout << "Height? ";
    cin >> h;
   
    MultTable table(l,w,h);
   
    cout << table;
   
    return 0;
}

I tried to comment on some of the things that might confuse you. I hope these help!


All times are GMT -5. The time now is 20:15.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi