Trying to Understand Pointers 
Author Message
 Trying to Understand Pointers

I'm having a real problem understanding pointers.  By repetition and
trying many different things, I get through most of the things I try to
write, but I just don't get why some things work and others don't.  I
know that once I understand WHY things have to be coded a certain way,
everything will clear up.  It always does.  So . . . .

-- Declare a pointer to a float:  float* pFloat;
So, how is the memory used that stores pFloat?  If it just contains a
memory address (as the books I've seen indicate), then why does its
declaration have to know it's going to point to a float ultimately?  A
memory address is just a memory address.  So pFloat actually contains
more than a simple address?

-- Pass the pointer into a function: func(float* pFloat){...}
Now, if pFloat contains information that says it's going to be pointing
to a float, isn't the function's argument actually repetitious?  If
pFloat contains type information, why tell it again?  If it doesn't
contain type information, then go back to the declaration question
above.

-- (I'm sure that's not the sum of my ignorance, but it's a start)

The actual problem I'm trying to solve right now is much beyond the
pointers chapter in the book (need to dynamically allocate an array of
structs within a function, and the structs each contain an array member,
which I must also dynamically allocate -- if that makes any sense).  I
think the problem my brain is really having is that it just hasn't
gotten this whole pointer thing yet.  (Of course, if someone would like
to suggest the format of the present problem's solution, I really like
that, too. <g>)

Thanks for any help you can give me.
Ken



Wed, 26 Feb 2003 01:46:56 GMT  
 Trying to Understand Pointers

Quote:
> I'm having a real problem understanding pointers.  By repetition and
> trying many different things, I get through most of the things I try to
> write, but I just don't get why some things work and others don't.  I
> know that once I understand WHY things have to be coded a certain way,
> everything will clear up.  It always does.  So . . . .

> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

No. It contains a "simple" address, with no type information. We tell the
compiler that it is "pointer to float" to allow the compiler to catch errors
like:

float * pFloat;
int x;
pFloat = & x;            // compile-time error

This is known as strong-typing and is a good thing!

Quote:

> -- Pass the pointer into a function: func(float* pFloat){...}
> Now, if pFloat contains information that says it's going to be pointing
> to a float,

It doesn't.

Quote:
> isn't the function's argument actually repetitious?

Once again, this allows the compiler to catch errors:

int x;

func( & x );            // compile-time error

Quote:
> If pFloat contains type information, why tell it again?

You are not "telling it again" - even you must admit you need to tell the
compiler at least once!

Quote:
> If it doesn't
> contain type information, then go back to the declaration question
> above.

> -- (I'm sure that's not the sum of my ignorance, but it's a start)

> The actual problem I'm trying to solve right now is much beyond the
> pointers chapter in the book (need to dynamically allocate an array of
> structs within a function, and the structs each contain an array member,
> which I must also dynamically allocate -- if that makes any sense).  I
> think the problem my brain is really having is that it just hasn't
> gotten this whole pointer thing yet.  (Of course, if someone would like
> to suggest the format of the present problem's solution, I really like
> that, too. <g>)

You would be much better off using the STL rather than doing your own
dynamic structures, but in outline (and in a kind of C-ish style):

struct Foo {
    char * mArray;

Quote:
};

int main() {

    Foo * f;
    // let's say we want 10 foos
    f = new Foo[ 10 ];

    // now let's build the arrays in the Foos
    for ( unsigned int i = 0; i < 10; i++ ) {
        f[i].mArray = new char[100];
        sprintf( f[i].mArray, "This is Foo number %d",  i );
    }

    // do something with it

    // delete allocated memory

    return 0;

Quote:
}

NeilB


Wed, 26 Feb 2003 02:30:38 GMT  
 Trying to Understand Pointers

Quote:
> I'm having a real problem understanding pointers.  By repetition and
> trying many different things, I get through most of the things I try to
> write, but I just don't get why some things work and others don't.  I
> know that once I understand WHY things have to be coded a certain way,
> everything will clear up.  It always does.  So . . . .

> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

Yes and no.  Image the following structure:

RECT {
    LONG top;
    LONG left;
    LONG bottom;
    LONG right;

Quote:
};

Now imagine the following:

RECT *lpRect;

The pointer lpRect stores two pieces of information.  The first piece of
information is the starting offset, in memory, that the variable occupies.
The second piece of information which you can determine through the sizeof()
function is the size of the variable, or how many bytes it spans.  So when
you declare a pointer to a RECT object it has to know:

A)  Where the rectangle object starts, and...
B)  How many bytes the rectangle object spans in memory.

Thefore, pointers have to be cast to a specific type so the compiler knows
not only where to find the variable, but how to act upon the data it finds.
This is why C++ supports casting and void pointers.  A pointer need not
neccessarily point to a specific data type, structure, or object.  In
example you could just as easily do the following:

float fVal;
void *lpVoid = &fVal;

This is a perfectly legitimate operation in C++.  However, the compiler
won't be able to act upon the data stored via the pointer until you cast it
to a specific data type, structure or object.  For example:

float *lpFloat = (float*)lpVoid;

This is a somewhat advanced topic, but I hope it illustrates that pointers
don't really care what they point to:  They just have to know how much data
they point to for them to be used effectively.

Quote:
> -- Pass the pointer into a function: func(float* pFloat){...}
> Now, if pFloat contains information that says it's going to be pointing
> to a float, isn't the function's argument actually repetitious?  If
> pFloat contains type information, why tell it again?  If it doesn't
> contain type information, then go back to the declaration question
> above.

Ok.  Before this can be explained you need to know a little something about
how C++ passes parameters to functions.  By default C++ passes by value.
This means that if you pass--for example--a float variable into a function,
a new copy of that variable is pushed onto the stack.  This variable has
function level scope.  This means that it only exists inside the function,
for the life of the function, and cannot be used outside the body of the
function.  Once the function returns, the stack is "popped" and the variable
is discarded.  The variable is not returned or seen in any way by the
calling function, unless the variable was passed by value (via the return
command) to the calling function.  So, if for example you changed the value
from 12.5 to 16.5, upon returning the value would be 12.5 because only the
local copy was effected.

Now, instead consider passing by pointer.  Again, as in all functions, a new
value is pushed onto the stack.  In this case the value is the address of
the float variable.  The pointer pFloat is a new value, it's value copied
from the variable supplied as an argument.  It is pushed onto the stack at
the start of the function and is popped off the stack at the end of the
function.  Unless you specifically return the pointer, it will not be seen
by the calling function.  However, that doesn't matter.  What does matter is
that for the life of the function you DO have the address of the a float
variable (hopefully), and that you can discreetly access that variable.
Because the actual variable pointed to exists outside the scope of the
function, you are changing variable itself.  So, when the function exits the
value remains changed.  Continuing the example above, if you passed by
pointer and used indirection the value would be 16.5 when the function
exits, as the actual variable was changed, not just a copy.

Quote:
> -- (I'm sure that's not the sum of my ignorance, but it's a start)

> The actual problem I'm trying to solve right now is much beyond the
> pointers chapter in the book (need to dynamically allocate an array of
> structs within a function, and the structs each contain an array member,
> which I must also dynamically allocate -- if that makes any sense).  I
> think the problem my brain is really having is that it just hasn't
> gotten this whole pointer thing yet.  (Of course, if someone would like
> to suggest the format of the present problem's solution, I really like
> that, too. <g>)

> Thanks for any help you can give me.
> Ken

There are several ways to allocate resources in your program.  Specifically
with C++ there is the malloc function and the new operator.  Personally, I
prefer malloc.  But that's just me.  At any rate, here is the way you would
use them both (with the RECT structure used for example earlier).

RECT *lpRect;

// Dynamically create an array of 24 RECT variables
lpRect = new RECT[24];    // Allocate memory
delete lpRect[];                   // De-allocate memory

OR

lpRect = (RECT*)malloc(sizeof(RECT) * 24);    // Allocate memory
free (lpRect);    // De-allocate memory

Either way will work, though the "new" and "delete" operator require C++.
New is a bit more straightforward, and simpler I will admit.  However,
malloc is very explicit; thus my preference for it.  Malloc should not be
used for objects, however; just simple data types and structures.  New can
be used for any variable, which may make it more convenient.

Use whichever you prefer, just be sure NOT to mix them up.  Calling delete
on memory allocated with malloc and calling free on memory allocated with
new can cause some serious bugs and/or crashes to be introduced into your
programs.  Also note that you can't trust your OS to free these resources
for you, even when the program terminates.  Always be sure to free resources
you allocate, or you could introduce a severe memory leak through your
program.

--
Daemon (a.k.a. Benjamin)

If a fool and his money are so easily parted, why do politicians keep
getting rich?



Wed, 26 Feb 2003 08:22:23 GMT  
 Trying to Understand Pointers

Quote:

> I'm having a real problem understanding pointers.  By repetition and
> trying many different things, I get through most of the things I try to
> write, but I just don't get why some things work and others don't.  I
> know that once I understand WHY things have to be coded a certain way,
> everything will clear up.  It always does.  So . . . .

> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

You got some long answers, I'll try a short one on the fundamental WHY.  Your
observations that a memory address is just a memory address are correct at the
hardware level but not at the compiler level.  The compiler needs to index into
arrays of floats for you and it needs to know how to do arithmetic on the thing
pFloat points at.  When you declare float* pFloat you are allocating 4 bytes to
hold the address AND telling the compiler how many bytes to add per item when
indexing into the array pFloat.  The indexing code it must generate is different
depending on size of the type, and the arithmetic (and even load/store) code is
different depending on whether it is a signed, unsigned, float or double that is
being manipulated via the pointer.

--
Scott McPhillips [VC++ MVP]



Wed, 26 Feb 2003 10:08:46 GMT  
 Trying to Understand Pointers
Ha!  This is great.  Trying to understand pointers.

Hey Pete this reminds me of Chip Elliot's office hours ....

Ed


Quote:
> I'm having a real problem understanding pointers.  By repetition and
> trying many different things, I get through most of the things I try to
> write, but I just don't get why some things work and others don't.  I
> know that once I understand WHY things have to be coded a certain way,
> everything will clear up.  It always does.  So . . . .

> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

> -- Pass the pointer into a function: func(float* pFloat){...}
> Now, if pFloat contains information that says it's going to be pointing
> to a float, isn't the function's argument actually repetitious?  If
> pFloat contains type information, why tell it again?  If it doesn't
> contain type information, then go back to the declaration question
> above.

> -- (I'm sure that's not the sum of my ignorance, but it's a start)

> The actual problem I'm trying to solve right now is much beyond the
> pointers chapter in the book (need to dynamically allocate an array of
> structs within a function, and the structs each contain an array member,
> which I must also dynamically allocate -- if that makes any sense).  I
> think the problem my brain is really having is that it just hasn't
> gotten this whole pointer thing yet.  (Of course, if someone would like
> to suggest the format of the present problem's solution, I really like
> that, too. <g>)

> Thanks for any help you can give me.
> Ken



Wed, 26 Feb 2003 13:08:27 GMT  
 Trying to Understand Pointers

Quote:
> -- (I'm sure that's not the sum of my ignorance, but it's a start)

Listen, to really nail down pointers, take every book you own, and throw it
out the window.  If you're into zen, empty your cup.

Fill it up with some brita-filtered tap water, and continue.



Wed, 26 Feb 2003 13:09:30 GMT  
 Trying to Understand Pointers

Quote:
> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

It does NOT contain any memory YET.  You have to create the actual value
space with the "new" operator.  Let's use MFC classes as well.

For example:

CString *pString;

pString = new CString();

.
.
pString = "Hi Mom.";
.
.

delete(pString);



Wed, 26 Feb 2003 13:11:48 GMT  
 Trying to Understand Pointers

Quote:
> -- Pass the pointer into a function: func(float* pFloat){...}
> Now, if pFloat contains information that says it's going to be pointing
> to a float, isn't the function's argument actually repetitious?  If
> pFloat contains type information, why tell it again?  If it doesn't
> contain type information, then go back to the declaration question
> above.

Did you ever learn Pascal?  The difference is between VALUE and VARIABLES.

Small types such as int's and float's can be passed by VALUE.  Anything
larger, and also, any variable which will be changed during the course of
the function, needs to be passed by pointer.

Main()
{
        CString *pString;
        pString = new CString();

        DoItNow(pString);

        delete pString;

Quote:
}

Function DoItNow(CString *pString);
{
        pString = "World Cup Soccer 2002";

Quote:
}

Etc.


Wed, 26 Feb 2003 13:14:57 GMT  
 Trying to Understand Pointers

Quote:
> structs within a function, and the structs each contain an array member,
> which I must also dynamically allocate -- if that makes any sense).  I

Sure, piece of cake.

Header:
.
.
.

struct Trailblazers
{
        int NumStarters;
        int FreeThrowAverages;
        int NumClutch3PointerPlayersAtTheBuzzer;

Quote:
}

struct NBA
{
        int NumTeams;
        Trailblazers *pBlazers;

Quote:
}

.
.
.

Implementation:

Function CallingFunct(...)
{
        NBA *pNBA = new NBA;
        Trailblazers *pNewNode = new Trailblazers;
        pNBA->pBlazers = pNewNode;

        SeeYouNextYear(pNBA);

        delete pNewNode;
        delete pNBA;

Quote:
}



Wed, 26 Feb 2003 13:21:49 GMT  
 Trying to Understand Pointers
<snip>

Quote:

> It does NOT contain any memory YET.  You have to create the actual value
> space with the "new" operator.  Let's use MFC classes as well.

Or you can assign the value with the address-of operator (&).  For example:

float fVal;
float *pVal = &fVal;

New is only used if you are creating variables upon the heap.

--
Daemon (a.k.a. Benjamin)

If a fool and his money are so easily parted, why do politicians keep
getting rich?



Thu, 27 Feb 2003 00:49:22 GMT  
 Trying to Understand Pointers

Quote:
> float fVal;
> float *pVal = &fVal;

Correct.  Let's not confuse him yet, first the * THEN the &.

Ed



Thu, 27 Feb 2003 02:47:10 GMT  
 Trying to Understand Pointers

Quote:

> I'm having a real problem understanding pointers.  By repetition and
> trying many different things, I get through most of the things I try to
> write, but I just don't get why some things work and others don't.  I
> know that once I understand WHY things have to be coded a certain way,
> everything will clear up.  It always does.  So . . . .

> -- Declare a pointer to a float:  float* pFloat;
> So, how is the memory used that stores pFloat?  If it just contains a
> memory address (as the books I've seen indicate), then why does its
> declaration have to know it's going to point to a float ultimately?  A
> memory address is just a memory address.  So pFloat actually contains
> more than a simple address?

Yes a pointer has a fixed size. The only reason we qualify with float*
is so the C/C++ compiler will know what we are talking about -- and
tell us off if we point to another type.

Quote:

> -- Pass the pointer into a function: func(float* pFloat){...}
> Now, if pFloat contains information that says it's going to be pointing
> to a float, isn't the function's argument actually repetitious?  If
> pFloat contains type information, why tell it again?  If it doesn't
> contain type information, then go back to the declaration question
> above.

No pFloat doesn't contain any type info, it's just a pointer. Again
we're telling the compiler that we know what we're doing. This is
really a prototype of the function, so that if we subsequently run
the function with an incorrect argument e.g. a pointer to an integer,
the compiler will tell us we've made a mistake.

Quote:

> -- (I'm sure that's not the sum of my ignorance, but it's a start)

> The actual problem I'm trying to solve right now is much beyond the
> pointers chapter in the book (need to dynamically allocate an array of
> structs within a function, and the structs each contain an array member,
> which I must also dynamically allocate -- if that makes any sense).  I
> think the problem my brain is really having is that it just hasn't
> gotten this whole pointer thing yet.  (Of course, if someone would like
> to suggest the format of the present problem's solution, I really like
> that, too. <g>)

> Thanks for any help you can give me.
> Ken

You're welcome.


Thu, 27 Feb 2003 06:25:30 GMT  
 Trying to Understand Pointers

Quote:

>I'm having a real problem understanding pointers.  By repetition and
>trying many different things, I get through most of the things I try to
>write, but I just don't get why some things work and others don't.  I
>know that once I understand WHY things have to be coded a certain way,
>everything will clear up.  It always does.  So . . . .

>-- Declare a pointer to a float:  float* pFloat;
>So, how is the memory used that stores pFloat?  If it just contains a
>memory address (as the books I've seen indicate), then why does its
>declaration have to know it's going to point to a float ultimately?  A
>memory address is just a memory address.  So pFloat actually contains
>more than a simple address?

On some machines, addresses of different types of objects have
different representations, possibly due to alignment constraints.

Furthermore, after you initialize the pointer to point to an
appropriate object (in this case a float) and you then dereference the
pointer (such as x = *pFloat * PI * 2;), it is important for the
compiler to know that the first term in the expression is a float and
not an int or double.

Quote:

>-- Pass the pointer into a function: func(float* pFloat){...}
>Now, if pFloat contains information that says it's going to be pointing
>to a float, isn't the function's argument actually repetitious?  If
>pFloat contains type information, why tell it again?  If it doesn't
>contain type information, then go back to the declaration question
>above.

Your comment applies to any type of function argument, pointer or not.

If all the compiler knew was the type of pFloat, how would it be able
to verify that this type is what the function was expecting.

Additionally, there is no requirement that the function be compiled in
the same source file (translation unit) as the statement calling it.
When the function is compiled separately, how does it know what types
of parameters to expect.

Quote:

>-- (I'm sure that's not the sum of my ignorance, but it's a start)

>The actual problem I'm trying to solve right now is much beyond the
>pointers chapter in the book (need to dynamically allocate an array of
>structs within a function, and the structs each contain an array member,
>which I must also dynamically allocate -- if that makes any sense).  I
>think the problem my brain is really having is that it just hasn't
>gotten this whole pointer thing yet.  (Of course, if someone would like
>to suggest the format of the present problem's solution, I really like
>that, too. <g>)

>Thanks for any help you can give me.
>Ken

<<Remove the del for email>>


Thu, 27 Feb 2003 15:44:55 GMT  
 Trying to Understand Pointers


Quote:
> > float fVal;
> > float *pVal = &fVal;

> Correct.  Let's not confuse him yet, first the * THEN the &.

> Ed

Confusing; only marginally.  The address-of operator is one of the more
commonly used operators in C++.  A full study of pointers cannot be done
without it.  In my own code I would have to say I use it ten times for every
new or delete operator.  Take the following function for example:

void DrawRect(RECT *rcRegion)
{
    // Do drawing code here

Quote:
}

Rather than doing the following:

RECT *lpRect = new Rect();
lpRect->top = 0;
lpRect->left = 0;
lpRect->bottom = 12;
lpRect->right = 12;

DrawRect(lpRect)

It would be much simpler to do the following:

RECT rcRegion = {0, 0, 12, 12};
DrawRect(&rcRegion);

But to help clarify this for Ken, we'll have to delve into memory addressing
a little...

Memory is addressed in one of two locations:  The stack or the free store
(also called the heap).  Typically, in most cases, you'll be allocating
memory on the stack.  The stack is used for functions and variables of a
local scope.  It is simply an area of sequentially addressed memory used
specifically for program execution.  The amount of stack space is limited
(I'm not really sure how much; just a lot less than the heap) and you can
run out of it.  This danger is mostly encountered in recursive functions
(functions that call themselves to solve a problem) or in functions that do
not have a terminating condition.  I wouldn't worry about it too much,
unless your your using recursive functions.

The main thing to know is that variables are placed onto the stack one on
top the other.  Lets say you have a function.  The function takes two
variables.  When you call the function two variables are pushed onto the
stack.  These two variables equal the values you supplied to the function.
These values ARE copies.  All functions push new variables onto the stack;
there is no way to avoid this.  Now let's say you create a for block using
"i" as a counter.  The variable "i" is placed on the stack.  When the for
block exits, the variable "i" is popped off the stack.  When the function
returns, the two copy variables are popped off the stack.  If a value is
returned, that value is placed ont top of the stack after the other
variables are cleaned up.  And thus your program continues.

Now enter pointers.  Pointers are used for one of two reasons.  Allocating
memory on the free store (read below) OR manipulating variables indirectly.
Given the operation of the stack, it is impossible to supply a variable
directly and have it affected in the function.  Take for example:

void Swap(char cDest, char cSource)
{
    cDest = cSource;

Quote:
}

char cVal = 'x';
char cSrc = 'y';

Swap(cVal, cSrc);

The following code does the following:  It pushes two char-sized variables
onto the stack.  These are copies.  One contains the value 'x', the other
the value 'y'.  Now within the function the local copy of cDest is given the
value of cSource.  Then the function exits.  cDest and cSource are popped
from the stack.  No value is returned.  Because these are new values pushed
onto the stack and no value was returned the calling code did not see the
changes in any way.  They didn't happen.

Now consider the following code:

void Swap(char *lpDest, char *lpSource)
{
    *lpDest = *lpSource;

Quote:
}

char cVal = 'x';
char cSrc = 'y';

Swap(&cVal, &cSrc);

The following code does the following.  It pushes two char-pointers on the
stack.  These are copies.  One contains the address of variable cVal, the
other the address of variable cSrc.  Now within the function we assign
values from one memory location to another through dereferncing (if you
don't understand dereferencing, you really need to buy a good C++ book.  The
investment is minimal in my experience.)  No value is returned.  Again the
pointers are pushed off the stack.  The pointers themselves cannot be seen
outside the scope of the function.  However; we don't care.  They
manipulated the data indirectly inside the function, as was the intention.
Thus the use of pointers for functions.

Now for the other case.  The free store.  The heap (as it is more
affectionately known) is a vast area of memory that you, as a programmer,
have access to.  The only caveat of the heap is that you are responsible for
all the memory management.  This is different from local copies, where the
stack manages them.  With the free store you have no such luxury.

To declare memory on the free store you have to use pointers.  This is
because you HAVE to know where you declared memory.  If you loose the
pointer or let it fall out of scope you've just made a major boo-boo called
a memory leak.  This is because once memory is allocated only the process
that created can touch it.  If another process tries to touch the memory you
will get access violations (at best).  Sometimes--even worse--you won't get
such a violation and you'll be able to write to the memory.  This can cause
major boo-boo's, because your writing to another process's memory space
which could have dissastrous (at best) consequences.  Once that process
accesses that memory space, there is no telling what could happen; whatever
does, you can be sure it isn't pretty.

So, warnings aside, to create memory on the free store you use one of two
operators:  new or malloc.  The new keyword is a c++ operator that works on
any kind of variable, be it an object, simple data type, or structure.  The
malloc keyword is a throwback to c and should only be used on basic data
types and structures; might work on objects, but it's not a good idea
because said objects won't be constructed.  At any rate, to create a
variable on the free store you follow edwards simple instructions:

float *lpFloat = new float;
float *lpLotsOfFloats = new float[25];

That will allocate memory on the heap.  However, when you are done with the
memory you need to de-allocate it.  This is done as follows:

delete lpFloat;
delete lpLotsOfFloats[];

Be sure to note that when creating new arrays (or de-allocating arrays) that
you include the [] brackets.  When creating memory you have to supply the
number of items, either through a constant or a variable.  When
de-allocating, be sure NOT to include any values.  This can have unforseen
effects; the least of which is not the total de-allocation of allocated
memory.

As an option to new/delete you can use the following syntax:

float *lpFloat = (float*)malloc(sizeof(float));
float *lpLotsOfFloats = (float*)malloc(sizeof(float) * 25);

free (lpFloat);
free (lpLotsOfFloats);

Malloc is also cool because you can do something with it that you can't do
with new (that I know of).  Namely, you can reallocate resources.  If your
familiar with VB, this is a lot like using the Redim keyword.  You can
realloc memory as follows, providing you HAVE used malloc.

if (lpLotsOfFloats != NULL)
    lpLotsOfFloats = (float*)realloc(lpLotsOfFloats, sizeof(float) * 30);
else
    lpLotsOfFloats = (float*)malloc(sizeof(float) * 30);

Realloc basically does three things:  Allocates a new memory space on the
heap (or expands the current space, if possible), copies all the existing
memory to that location, and de-allocates the previous memory space.  You
should always check to make sure that the pointer is NULL though; if it is
NULL you DON'T want to reallocate it; that'd cause bad, bad things to
happen.  Allocate fresh memory instead.

And, as to ken's original question, while we are on the subject, lets take
problem of allocating nested arrays of data structures to example:

struct RECT {
    LONG top;
    LONG left;
    LONG bottom;
    LONG right;

Quote:
}

struct RECT_CONTAINER {
    RECT* lpRects;
    LONG  lCount;

Quote:
}

struct BIGGER_CONTAINER {
    RECT_CONTAINER *lpRectCont;
    LONG    lCount;

Quote:
}

 LONG lMaxBig  = 3;
 LONG lMaxCont = 5;
 LONG lMaxRect = 12;

// Pointer to the address of the base collection
BIGGER_CONTAINER *lpBigCont;

// Cascade allocate memory
lpBigCont = (BIGGER_CONTAINER*)malloc(sizeof(BIGGER_CONTAINER) * lMaxBig);
for (LONG i = 0; i < lMaxBig; i++)
{
        lpBigCont[i].lCount = lMaxCont;
        lpBigCont[i].lpRectCont =
(RECT_CONTAINER*)malloc(sizeof(RECT_CONTAINER) * lMaxCont);

        for (LONG j = 0; j < lMaxCont; j++)
        {
            lpBigCont[i].lpRectCont[j].lCount = lMaxRect;
            lpBigCont[i].lpRectCont[j].lpRects = (RECT*)malloc(sizeof(RECT)
* lMaxRect);
        }
 }

// Cascade de-allocate memory
for (LONG i = 0; i < lMaxBig; i++)
{
    for (LONG j = 0; j < lMaxCont; j++)
    {
        free (lpBigCont[i].lpRectCont[j].lpRects);
        lpBigCont[i].lpRectCont[j].lpRects = NULL;
        lpBigCont[i].lpRectCont[j].lCount = 0;
    }

    free (lpBigCont[i].lpRectCont);
    lpBigCont[i].lpRectCont = NULL;
    lpBigCont[i].lCount = 0;

Quote:
}

free (lpBigCont);
lpBigCont = NULL;

===================================
OR USING THE NEW/DELETE OPERATORS
===================================

 LONG lMaxBig  = 3;
 LONG lMaxCont = 5;
 LONG lMaxRect = 12;

 BIGGER_CONTAINER *lpBigCont;
 lpBigCont = new BIGGER_CONTAINER[lMaxBig];

for (LONG i = 0; i < lMaxBig; i++)
{
    lpBigCont[i].lCount = lMaxCont;
    lpBigCont[i].lpRectCont = new RECT_CONTAINER[lMaxCont];

    for (LONG j = 0; j < lMaxCont; j++)
    {
        lpBigCont[i].lpRectCont[j].lCount = lMaxRect;
        lpBigCont[i].lpRectCont[j].lpRects = new RECT[lMaxRect];
    }

Quote:
}

for (LONG i = 0; i < lMaxBig; i++)
{
    for (LONG j = 0; j < lMaxCont; j++)
    {
        delete lpBigCont[i].lpRectCont[j].lpRects[];
        lpBigCont[i].lpRectCont[j].lpRects = NULL;
        lpBigCont[i].lpRectCont[j].lCount = 0;
    }

    delete lpBigCont[i].lpRectCont[];
    lpBigCont[i].lpRectCont = NULL;
    lpBigCont[i].lCount = 0;

Quote:
}

delete lpBigCont[];
lpBigCont = NULL;

--
Daemon (a.k.a. Benjamin)



Thu, 27 Feb 2003 16:43:57 GMT  
 Trying to Understand Pointers
Errr... detected a few errors in my posted code.  Should read as follows
(had the [] in the wrong place on delete; told ya I didn't use it much ;):

 long lMaxBig  = 3;
 long lMaxCont = 5;
 long lMaxRect = 12;
 long i, j;

 BIGGER_CONTAINER *lpBigCont;
 lpBigCont = new BIGGER_CONTAINER[lMaxBig];

 for (i = 0; i < lMaxBig; i++)
 {
  lpBigCont[i].lCount = lMaxCont;
  lpBigCont[i].lpRectCont = new RECT_CONTAINER[lMaxCont];

  for (j = 0; j < lMaxCont; j++)
  {
   lpBigCont[i].lpRectCont[j].lCount = lMaxRect;
   lpBigCont[i].lpRectCont[j].lpRects = new RECT[lMaxRect];
  }
 }

 for (i = 0; i < lMaxBig; i++)
 {
  for (j = 0; j < lMaxCont; j++)
  {
   delete[] lpBigCont[i].lpRectCont[j].lpRects;
   lpBigCont[i].lpRectCont[j].lpRects = NULL;
   lpBigCont[i].lpRectCont[j].lCount = 0;
  }

  delete[] lpBigCont[i].lpRectCont;
  lpBigCont[i].lpRectCont = NULL;
  lpBigCont[i].lCount = 0;
 }
 delete[] lpBigCont;
 lpBigCont = NULL;



Thu, 27 Feb 2003 16:54:57 GMT  
 
 [ 20 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Trying to understand pointer and malloc

2. Trying to Understand Pointers

3. Still trying to understand .NET

4. Trying to understand disassembly, need help.

5. novice trying to understand something

6. Total C newbie trying to understand a date conversion function

7. Trying to understand CreateWindow - HELP!!!

8. trying to understand a macro...help!?

9. Trying to understand operator+

10. Trying to understand some code

11. Trying to understand MFC...

12. Trying to Understand CTreeView

 

 
Powered by phpBB® Forum Software