NickDMax's Profile
Reputation: 2209
Grandmaster
- Group:
- Alumni
- Active Posts:
- 9,165 (4.01 per day)
- Joined:
- 18-February 07
- Profile Views:
- 64,861
- Last Active:
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
-
Precise 
18 May 2013 - 13:30 -
frijj 
17 Apr 2013 - 06:10 -
Sandals456 
16 Apr 2013 - 13:01 -
Paci 
11 Apr 2013 - 01:11 -
raghav.nagana... 
11 Feb 2013 - 04:42 -
snoopy11 
08 Feb 2013 - 07:16 -
Fredericazck 
01 Feb 2013 - 11:34 -
quim 
13 Jan 2013 - 21:21 -
Vodkacannon 
25 Dec 2012 - 16:33 -
CY5 
22 Dec 2012 - 10:28
Posts I've Made
-
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. -
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. -
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. -
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. -
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
Friends
-

Jayman
-

PsychoCoder
-

Anarion
-

Core
-

BetaWar
-

skyhawk133
-

OliveOyl3471
-

mostyfriedman
-

th3kingdom1
-

Gorian
-

Raynes
-

Martyr2
-

gabehabe
-

zero_cool1
-

KYA
-

SixOfEleven
-

Martyn.Rae
-

coden4fun
-

carltech
-

s2xcracker
-

iankita.29
-

foxbrain
-

khalid10
-

metallab90
-

mobius19
-

williamgeo...
-

espirator
-

Tapas Bose
-

calebjonasson
-

Elcric
-

macosxnerd101
-

sm5312
-

sreman
-

smohd
-

pgfdbug
-

Soumava Ch...
-

sri Harsha
-

rexsam99
-

Nouf ~
-

Adewesko
-

aqshaf
-

BrainTuner
-

Chevon
-

csharpbacha
-

redrider11
-

chris_24
-

ahbrahim2
-

D.Mulroy
-

satzkmr
-

babyshay
Showing 50 random friends of 53 (View all)
|
|


Find Topics
Find Posts
View Reputation Given
|
Comments
ishkabible
20 Nov 2011 - 20:18NickDMax
12 Sep 2011 - 22:21NickDMax
12 Sep 2011 - 22:20hulla
08 Sep 2011 - 02:35hulla
02 Sep 2011 - 01:33hulla
27 Aug 2011 - 07:33hulla
16 Aug 2011 - 01:44assert(C)
21 Jul 2011 - 07:27assert(C)
20 Jul 2011 - 08:18hulla
02 Jul 2011 - 07:43NickDMax
22 Jun 2011 - 03:05@ishkabible -- I have only really been posting in one forum so I don't expect it to last.
ishkabible
19 Jun 2011 - 13:33PlasticineGuy
18 Jun 2011 - 06:49shib.paul
20 Dec 2010 - 05:19using 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...
jharr214
25 Nov 2010 - 19:10