NickDMax's Profile User Rating: *****

Reputation: 2209 Grandmaster
Group:
Alumni
Active Posts:
9,165 (4.01 per day)
Joined:
18-February 07
Profile Views:
64,861
Last Active:
User is offline Jan 13 2013 12:37 PM
Currently:
Offline

Previous Fields

Country:
US
OS Preference:
Windows
Favorite Browser:
FireFox
Favorite Processor:
Intel
Favorite Gaming Platform:
PC
Your Car:
Nissan
Dream Kudos:
1250
Expert In:
Java/C++

Latest Visitors

Icon   NickDMax "somewhere beneath my feet is a weapon of days honeycombed with neurons come neuroses."

Posts I've Made

  1. In Topic: Pointer to Pointer The double asterisks need or not needed?

    Posted 11 Jan 2013

    A pointer to a pointer is called "double indirection" and as the name seems to imply it can be difficult to really wrap your head around.

    Generally think of it just as a pointer... that just happens to point to another pointer.

    Lets go back to old C programming for a bit. Lets say that I was working on the infamous 99 bottles of beer problem and wanted a function that returned either "bottles" or "bottle" depending upon an argument.

    #include <stdio.h>
    
    const char* const singleBottle = "bottle";
    const char* const multipleBottles = "bottles";
    const char* const line1 = "%d %s of beer on the wall; %d %s of beer;\n"
                        "   Take one down, pass it arround...\n";
    const char* const line2 = "   %d %s of beer on the wall!!!\n";
                
    
    void chooseCorrectText(int count, const char** text) {
        if (count == 1) {
            *text = singleBottle;
        } else {
            *text = multipleBottles;
        }
    }
    
    void takeOneDown(int* pCount) {
        (*pCount)--;
    }
    
    int main() {
        int i = 5;
        const char* bottleptr;
        while(i > 0) {
            chooseCorrectText(i, &bottleptr);
            printf(line1, i, bottleptr, i, bottleptr);
            takeOneDown(&i);
            chooseCorrectText(i, &bottleptr);
            printf(line2, i, bottleptr);
        }
        return 0;
    }
    

    Now the above would have been confusing to me for the first few years I was programming C so lets see if we can walk though it.

    #1 lets clear this up: const char* bottleptr; pointer declarations are read backwards so we have "bottleptr is a POINTER to a CHAR CONSTANT" - That is bottleptr is mutable (non-constant), but what it points to is not.

    (as opposed to const char* const singleBottle = "bottle"; which says: "singleBottle is a CONSTANT pointer to a char constant" - so singleBottle can not be changed.

    So lets take this from a bottom up approach. In the line:
    printf(line1, i, bottleptr, i, bottleptr); we want the pointer variable bottleptr to contain the address of either "bottles" or "bottle".

    So we pass bottleptr BY REFERENCE to chooseCorrectText(int count, const char** text): So text is a pointer to the bottleptr (which happens to be a pointer). so *text gets us to bottleptr which is what we want to change:
    *text = singleBottle;
    so now we have assigned bottleptr to the value of singleBottle. so bottleptr now points to the string "bottle" in memory.

    I made the function takeOneDown to demonstrate that concepts of pass by reference when the value is not a pointer. The pointer pCount points to some integer that holds our count, so *pCount gives us access to that value and (*pCount)-- will decrease that value by 1.


    All of this is maybe a little easier to see when we look at a generic function in C++ like swap written out in C.
    template<typename T>
    void swap(T* v1, T* v2) {
        T temp = *v1;
        *v1 = *v2;
        *v2 = temp;
    }
    
    when you simulate this for ints in C you get:
    void c_swap_int(int* v1, int* v2) {
        int temp = *v1;
        *v1 = *v2;
        *v2 = temp;    
    }
    


    When you simulate this for int* (say you want to swap two arrays) in C you get:
    void c_swap_int(int** v1, int** v2) {
        int *temp = *v1;
        *v1 = *v2;
        *v2 = temp;    
    }
    


    This will swap two pointers. Say you wanted to swap two 2D arrays:
    void c_swap_int(int*** v1, int*** v2) {
        int **temp = *v1;
        *v1 = *v2;
        *v2 = temp;    
    }
    


    So you see a pattern forming? the algorithm is the same - the only thing that needs to change is the datatype of what we are swapping.
  2. In Topic: Why would you ever... Return a Pointer or reference..

    Posted 11 Jan 2013

    So I find this to be a little contradictory:

    Quote

    Ok, so I understand pointers and references, ive used them before plenty of times. Thing is that I just doin't understand the concept of returning a pointer or a reference.


    if you understand pointers/references they surely you understand the need to return them from functions! They are forms of variables and you will need to manipulate them and that generally means passing them into and out-of functions.

    I personally love to return references from function, ESPECIALLY member functions that return a reference to *this!

    Take for example this dumb little class:
    #include <iostream>
    
    using namespace std;
    
    class AverageFinder {
        int accumulator;
        int count;
        
        public:
        AverageFinder() : accumulator(0), count(0) { }
        
        AverageFinder& addDataPoint(const int& data) {
            accumulator += data;
            count++;
            return *this; //return a reference to the current instance
        }
        
        double getAverage() {
            return (double)accumulator/count;
        }
    };
    
    int main() {
        AverageFinder avg;
        avg.addDataPoint(1);
        avg.addDataPoint(2).addDataPoint(3).addDataPoint(4);
        cout << avg.getAverage() << endl;
        return 0;
    }
    


    By returning a reference to *this from addDataPoint() I can chain them together. I know what you are thinking, "so... that is neat I guess but... so?"

    Well what if instead of a function we did that with an operator? (which is really just a function).

    #include <iostream>
    
    using namespace std;
    
    class AverageFinder {
        int accumulator;
        int count;
        
        public:
        AverageFinder() : accumulator(0), count(0) { }
        
        AverageFinder& addDataPoint(const int& data) {
            accumulator += data;
            count++;
            return *this; //return a reference to the current instance
        }
        
        double getAverage() {
            return (double)accumulator/count;
        }
    };
    
    AverageFinder& operator<<(AverageFinder& avg, const int& data) {
        return avg.addDataPoint(data);
    }
    
    int main() {
        AverageFinder avg;
        avg.addDataPoint(1);
        avg.addDataPoint(2).addDataPoint(3).addDataPoint(4);
        
        avg << 5 << 6 << 7 << 8;
        
        cout << avg.getAverage() << endl;
        return 0;
    }
    


    but wait there's more! This is how we overload operator<< for output streams too!
    #include <iostream>
    
    using namespace std;
    
    class AverageFinder {
        int accumulator;
        int count;
        
        public:
        AverageFinder() : accumulator(0), count(0) { }
        
        AverageFinder& addDataPoint(const int& data) {
            accumulator += data;
            count++;
            return *this; //return a reference to the current instance
        }
        
        double getAverage() {
            if (count == 0) { count = 1; }
            return (double)accumulator/count;
        }
    };
    
    AverageFinder& operator<<(AverageFinder& avg, const int& data) {
        return avg.addDataPoint(data);
    }
    
    ostream& operator<<(ostream& out, AverageFinder& avg) {
        return (out << avg.getAverage());
    }
    
    int main() {
        AverageFinder avg;
        avg << 1 << 2 << 3;
        cout << avg << endl;
        return 0;
    }
    


    --but you see the point here is not tricks you can play with syntax, the point is that pointers and references are variables and manipulating the data in variables is what programming is really kind of all about. So IF you understand pointers and references then returning them from functions is just something you find yourself doing.
  3. In Topic: Memory not being freed as expected when using pointers

    Posted 11 Jan 2013

    being able to create your own vector class is a really good excersize and I don't want to steer you away from that from an educational point of view, BUT in real-world application programming you would probably want to stick with std::vector unless there were compelling reasons not to.

    So your problem seems to be adding an array of values to the vector all at once. This is easy enough to do with vectors:
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    static const int ARRAY_SIZE = 1024;
    
    int main() {
        vector<double> derp;
        double *hurr = new double[ARRAY_SIZE]; //Why not just use a vector here rather than an array?
        for (int i=0;i<1024;i++) { hurr[i]=i; }
        for (int i=0;i<1000;i++) { 
            derp.insert(derp.end(), hurr, hurr+ARRAY_SIZE); //add all elements of the array
        } 
        cout << "Size of derp: " << derp.size() << endl;
        
        
        delete[] hurr;
    }
    


    so you could make that into a little utility function if you wanted:
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    static const int ARRAY_SIZE = 1024;
    
    template<typename CONTAINER_TYPE>
    CONTAINER_TYPE& addData(CONTAINER_TYPE& container, typename CONTAINER_TYPE::value_type* array, size_t arraySize) {
        container.insert(container.end(), array, array+arraySize);
        return container;
    }
    
    int main() {
        vector<double> derp;
        double *hurr = new double[ARRAY_SIZE]; //Why not just use a vector here rather than an array?
        for (int i=0;i<1024;i++) { hurr[i]=i; }
        for (int i=0;i<1000;i++) { 
            //derp.insert(derp.end(), hurr, hurr+ARRAY_SIZE); //add all elements of the array
            addData(derp, hurr, ARRAY_SIZE);
        } 
        cout << "Size of derp: " << derp.size() << endl;
        
        
        delete[] hurr;
    }
    


    And there are several other ways to go about this

    Next lets talk about your Cvector class:

    First in your constructor:
    	    oldstream= new T;
    	    stream= new T;
    
    -- Your vector will be managing things of an array type and will need to use delete[] so you CAN NOT assign stream or oldstream and new T, it must be of type T[]. So if there is no data it is best to set these to null (or an initial size) and deal with them later.

    Since we know that oldstream and stream will have data we should probably work on our deconstructor, copy constructor, and assignment operator (remember if you need one of these three then you need all three).

    so the deconstructor would look like this
    	~Cvector() {
            if (oldstream != NULL) {
                delete[] oldstream;
                oldstream = NULL;
            }
            if (stream != null) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
    	}{/code]
    
    and for now it is fine to just create a private copy constructor and assignment operator with nothing in them (this disables clients from using those functions and will result in wonderful cryptic error messages when someone tries):[code]    Cvector(const Cvector& other) { } // do not allow copy
        Cvector& operator= (const Cvector &other) { }
    


    Ok -- now we are ready to add data! I don't really understand your addData function so I am just going to do it my own way that makes sense to me and you can tell me what you think.


    So the first error in your code I see is this:

    stream=new T[sizeOfStream+size]; -- you didn't save or delete the old array from stream -- memory leak right there!

    that should probably look something like:
    T* temp = stream;
    stream = new T[sizeOfStream+size];
    


    So I rewrote your function as:
    	void addData(T *dataIn, unsigned int size){//main function of class
            //first create a temp to hold the new data;
            T* temp = stream;
    
            
    	    stream=new T[sizeOfStream+size];
            
            //note that if temp = null then this is std::copy(null, null, stream) -- and should result in no copy so
    	    T* insertPosition = std::copy(temp, temp+sizeOfStream, stream);
            std::copy(dataIn, dataIn+size, insertPosition);
            //the above two lines could be written as:
            //std::copy(dataIn, dataIn+size,
            //    std::copy(temp, temp+sizeOfStream, stream));
            // which avoids the use of the var insertPosition but is less clear. 
            
    	    //update our size
            sizeOfStream += size;
            
            //Release the old temp
            if (temp != NULL) {
                delete[] temp;
            }
    	}
    


    we now want clear to work like our deconstructor:
    	void clear(){
            if (oldstream != NULL) {
                delete[] oldstream;
                oldstream = NULL;
            }
            if (stream != null) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
    	}
    


    the data() function works the same I guess so we have:
    #include <iostream>
    #include <algorithm> //std::copy
    
    template <class T> class Cvector {
        typedef T value_type;
    
        Cvector(const Cvector& other) { } // do not allow copy
        Cvector& operator= (const Cvector &other) { }
        
        
        public:
    	Cvector() { //pass initial parameters
    	    sizeOfStream=0;
    	    oldstream= NULL;
    	    stream= NULL;
    	}
        
        
    	~Cvector() {
            if (oldstream != NULL) {
                delete[] oldstream;
                oldstream = NULL;
            }
            if (stream != NULL) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
    	}
        
        
    
    	void addData(T *dataIn, unsigned int size){//main function of class
            //first create a temp to hold the new data;
            T* temp = stream;
    
            
    	    stream=new T[sizeOfStream+size];
            
            //note that if temp = null then this is std::copy(null, null, stream) -- and should result in no copy so
    	    T* insertPosition = std::copy(temp, temp+sizeOfStream, stream);
            std::copy(dataIn, dataIn+size, insertPosition);
            //the above two lines could be written as:
            //std::copy(dataIn, dataIn+size,
            //    std::copy(temp, temp+sizeOfStream, stream));
            // which avoids the use of the var insertPosition but is less clear. However this is how you are likely to see this.
            
    	    //update our size
            sizeOfStream += size;
            
            //Release the old temp
            if (temp != NULL) {
                delete[] temp;
            }
    	}
    
    	unsigned int size(){//return the size of the array
    	    return sizeOfStream;
    	}
    
    	void clear(){
            if (oldstream != NULL) {
                delete[] oldstream;
                oldstream = NULL;
            }
            if (stream != NULL) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
    	}
    
    	T *data(){//retrieve the array
    	    return stream;
    	}
    
        private:
    	T *stream;
    	T *oldstream;
    	unsigned int sizeOfStream;
    };
    
    using namespace std;
    
    static const int ARRAY_SIZE = 1024;
    
    int main() {
        Cvector<double> derp;
        double *hurr = new double[ARRAY_SIZE]; //Why not just use a vector here rather than an array?
        for (int i=0;i<1024;i++) { hurr[i]=i; }
        for (int i=0;i<1000;i++) { 
            derp.addData(hurr, ARRAY_SIZE);
        } 
        cout << "Size of derp: " << derp.size() << endl;
        
        
        delete[] hurr;
        return 0;
    }
    


    I didn't end up using oldstream at all, I suspect that I used temp where your thinking was to use oldstream.

    Now this is MUCH MUCH MUCH slower than vector! So the question is why?

    Well vectors don't allocate "just the memory needed" -- they buffer ahead and allocate more memory than is needed, they also grow by a factor of roughly 2 every time they reallocate memory. So this might be something that we could implement to look for a boost in performance.
    #include <iostream>
    #include <algorithm> //std::copy
    
    template <class T> class Cvector {
        typedef T value_type;
    
        Cvector(const Cvector& other) { } // do not allow copy
        Cvector& operator= (const Cvector &other) { }
        
        
        public:
    	Cvector() { //pass initial parameters
    	    sizeOfStream = 0;
            sizeOfData = 0;
    	    stream = NULL;
    	}
        
        
    	~Cvector() {
            if (stream != NULL) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
            sizeOfData = 0;
    	}
        
        
    
    	void addData(T *dataIn, unsigned int size){//main function of class
            // first determine if we need to grow in size:
            if (sizeOfData+size <= sizeOfStream) { // no need to grow we can fit with what we have!
                std::copy(dataIn, dataIn+size, stream + sizeOfData);
                sizeOfData += size;
                return; //done
            }
            //ok so we need to determine the size we need, if we can double our size we will do that:
            size_t newSize = sizeOfStream * 2;
            if (sizeOfData + size > newSize) {
                newSize = sizeOfData + size;
            }       
            T* temp = stream;
    	    stream=new T[newSize];
            
            //note that if temp = null then this is std::copy(null, null, stream) -- and should result in no copy so
    	    T* insertPosition = std::copy(temp, temp+sizeOfStream, stream);
            std::copy(dataIn, dataIn+size, insertPosition);
            //the above two lines could be written as:
            //std::copy(dataIn, dataIn+size,
            //    std::copy(temp, temp+sizeOfStream, stream));
            // which avoids the use of the var insertPosition but is less clear. However this is how you are likely to see this.
            
    	    //update our size
            sizeOfData += size;
            sizeOfStream = newSize;
            
            //Release the old temp
            if (temp != NULL) {
                delete[] temp;
            }
    	}
    
    	unsigned int size(){//return the size of the array
    	    return sizeOfData;
    	}
    
    	void clear(){
            if (oldstream != NULL) {
                delete[] oldstream;
                oldstream = NULL;
            }
            if (stream != NULL) {
                delete[] stream;
                stream = NULL;
            }
    	    sizeOfStream = 0;
    	}
    
    	T *data(){//retrieve the array
    	    return stream;
    	}
    
        private:
    	T* stream;
    	size_t sizeOfStream;
        size_t sizeOfData;
    };
    
    using namespace std;
    
    static const int ARRAY_SIZE = 1024;
    
    int main() {
        Cvector<double> derp;
        double *hurr = new double[ARRAY_SIZE]; //Why not just use a vector here rather than an array?
        for (int i=0;i<1024;i++) { hurr[i]=i; }
        for (int i=0;i<1000;i++) { 
            derp.addData(hurr, ARRAY_SIZE);
        } 
        cout << "Size of derp: " << derp.size() << endl;
        
        
        delete[] hurr;
        return 0;
    }
    


    This preforms much the same as the vector class in terms of time. It is still not a perfect vector and there are some very good articles on how the std::vector class works so you might want to do a little deeper research.
  4. In Topic: Pointer to a local variable

    Posted 4 Jan 2013

    This is a good place to use a debugger. Watch the point pinstance and put a break point where you noticed the error.

    Somethings to check: #1 Scope. Make sure that instance is still in scope everywhere you are using the object. Remember you CAN NOT do this:
    A* myfunc() {
        A instance;
        A* pinstance = &instance;
        return pinstance; //error! memory pointed to will no longer be available!
    }
    


    #2 Make sure that pinstance still points to instance. Maybe somewhere you did pinstance = newValue instead of *pinstance = *newValue etc.

    #3 Casts. Pointers are magical things that can be cast to any other type compatible or not. If you do any casting remember that structures in memory don't always look exactly like they do on paper. For example padding my be added in places, order might be re-arranged etc.


    The code you gave us didn't really give us enough to spot an error.
  5. In Topic: Something unsual happened while running 'C'.

    Posted 20 Aug 2012

    I am glad you got the answer. I hope your solution was a little more elegant than the ones proffered above.

    The key to the way I would do it was give to you by Hezekiah and #define.

    Use a printf like #define but use the mod operator as described by Hezekiah.
    0 % 7 = 0
    1 % 7 = 1
    ..
    6 % 7 = 6
    7 % 7 = 0
    8 % 7 = 8 - n7 where int(8/7) = 1 so 8%7 = 1
    14% 7 = 0
    N % 7 = N - int(N/7)*7 = the remainder of N/7

    so dayOfMonth % 7 is a number 0-6. If we use a little math and logic to map these values to array indexes we can do the whole thing in 1 little loop!

My Information

Member Title:
Can grep dead trees!
Age:
Age Unknown
Birthday:
Birthday Unknown
Gender:
Location:
PA
Interests:
Mathematics, Programming, Calligraphy
Years Programming:
17
Programming Languages:
VB6, C, C++, IA86 Assembly, Mathematica, Java/JavaEE, Perl, Python

Contact Information

E-mail:
Private
Twitter:
NickDMax

Comments

  • (2 Pages)
  • +
  • 1
  • 2
  1. Photo

    ishkabible Icon

    20 Nov 2011 - 20:18
    just getting your attention, lolz
  2. Photo

    NickDMax Icon

    12 Sep 2011 - 22:21
    I don't really check my profile very often. So this is a really poor way to get my attention.
  3. Photo

    NickDMax Icon

    12 Sep 2011 - 22:20
    grep is a function (generally in linux/unix) that searches though files using regular expressions. - The expression "You can't grep dead trees." is a disdain for printed manuals (you of course can grep man pages but not a printed manual).
  4. Photo

    hulla Icon

    08 Sep 2011 - 02:35
    Can you reply so I don't look like a loner, please? :)
  5. Photo

    hulla Icon

    02 Sep 2011 - 01:33
    What does grep mean?
  6. Photo

    hulla Icon

    27 Aug 2011 - 07:33
    Your rep is the year I was born on (1997) :)
  7. Photo

    hulla Icon

    16 Aug 2011 - 01:44
    You should be like, a teacher or a tutor or something because you can Seriously communicate with students . . . Unless you already are one. I wouldn't be surprised if you were a college lecturer or something. :)
  8. Photo

    assert(C) Icon

    21 Jul 2011 - 07:27
    Thanks boss you are great
  9. Photo

    assert(C) Icon

    20 Jul 2011 - 08:18
    hey thanks for the reply in the post
  10. Photo

    hulla Icon

    02 Jul 2011 - 07:43
    Uhh, it's malicious? How?
  11. Photo

    NickDMax Icon

    22 Jun 2011 - 03:05
    @PlasticineGuy -- I don't mean to pick on anyone (usually).
    @ishkabible -- I have only really been posting in one forum so I don't expect it to last.
  12. Photo

    ishkabible Icon

    19 Jun 2011 - 13:33
    hey you topped macosxnerd in rep this month!! no small feat!!
  13. Photo

    PlasticineGuy Icon

    18 Jun 2011 - 06:49
    Every time I see you in a topic I've posted in I feel like I'm about to get a slap on the wrist!
  14. Photo

    shib.paul Icon

    20 Dec 2010 - 05:19
    [spoiler] [code] -- #include<iostream
    using namespace std;
    #define SIZE 10
    int a[SIZE]={2, 10, 87, 1000, 23, 31, 45, 85, 988, 344};
    int cnt=1;
    static int iMax=a[0];
    int getMax()
    {
    iMax = iMax*(iMax>a[cnt]) + a[cnt]*(a[cnt]>iMax);
    return cnt++<SIZE && getMax();
    }
    int main()
    {
    getMa...
  15. Photo

    jharr214 Icon

    25 Nov 2010 - 19:10
    Can you help me with my code really quick? Please
  • (2 Pages)
  • +
  • 1
  • 2