Board index » cppbuilder » Record on the heap

Record on the heap


2007-12-04 01:52:55 AM
cppbuilder37
How does one put a dynamic array of records on the heap when using plain C?
Would it go something like this?
struct MyRec
{ char testchar;
int testint;
} *MyRecArray;
calloc(MyRecArray, 20 * Sizeof(MyRec));
Since it's an array, no pointer reference needed with reading or writing?
//Use it
MyRecArray[0].testint = 1;
printf("Element 1 is %d \r\n", MyRecArray[0]);
Free(MyRecArray);
 
 

Re:Record on the heap

Your concept is correct but your C language example has a couple of
wrinkles.
This will not work
calloc(MyRecArray, 20 * Sizeof(MyRec));
calloc takes two arguments, the number of items and the size of one item.
It returns a pointer to the allocated memory. To avoid subtle bugs that can
creep in later when code is modified, I like to use the target pointer
variable to specify the size.
MyRecArray = calloc(20, sizeof(*MyRecArray));
It is customary after an allocation call to test the returned value for NULL
to detect a failed allocation.
if (!MyRecArray) /* same as if (MyRecArray == NULL) */
{
printf("Memory allocation error\n");
return 0;
}
This part has a problem:
Quote
Since it's an array, no pointer reference needed with reading or writing?
//Use it
MyRecArray[0].testint = 1;
printf("Element 1 is %d \r\n", MyRecArray[0]);
As to using the pointer variable name, MyRecArray here, as the name of an
array that you can subscript, that part is correct.
The printf function takes arguments whose type is specified by the format
specifiers (%d in this case which says it is an int). The code shown tries
to write out an entire structure. Instead of MyRecArray[0] use
MyRecArray[0].testint as an argument to printf.
. Ed
Quote
Richard wrote in message
news:4754427a$ XXXX@XXXXX.COM ...

How does one put a dynamic array of records on the heap when using plain
C?
Would it go something like this?

struct MyRec
{ char testchar;
int testint;
} *MyRecArray;

calloc(MyRecArray, 20 * Sizeof(MyRec));

Since it's an array, no pointer reference needed with reading or writing?
//Use it
MyRecArray[0].testint = 1;
printf("Element 1 is %d \r\n", MyRecArray[0]);
Free(MyRecArray);
 

Re:Record on the heap

Yes, Sorry, I was in a hurry in did not pay close attention. I was
calling calloc correctly in the actual code.
Thanks for the quick response.
Richard
"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
Your concept is correct but your C language example has a couple of
wrinkles.

This will not work
calloc(MyRecArray, 20 * Sizeof(MyRec));

calloc takes two arguments, the number of items and the size of one item.
It returns a pointer to the allocated memory. To avoid subtle bugs that
can creep in later when code is modified, I like to use the target pointer
variable to specify the size.

MyRecArray = calloc(20, sizeof(*MyRecArray));

It is customary after an allocation call to test the returned value for
NULL to detect a failed allocation.

if (!MyRecArray) /* same as if (MyRecArray == NULL) */
{
printf("Memory allocation error\n");
return 0;
}

This part has a problem:

>Since it's an array, no pointer reference needed with reading or writing?
>//Use it
>MyRecArray[0].testint = 1;
>printf("Element 1 is %d \r\n", MyRecArray[0]);

As to using the pointer variable name, MyRecArray here, as the name of an
array that you can subscript, that part is correct.

The printf function takes arguments whose type is specified by the format
specifiers (%d in this case which says it is an int). The code shown
tries to write out an entire structure. Instead of MyRecArray[0] use
MyRecArray[0].testint as an argument to printf.

. Ed

>Richard wrote in message
>news:4754427a$ XXXX@XXXXX.COM ...
>
>How does one put a dynamic array of records on the heap when using plain
>C?
>Would it go something like this?
>
>struct MyRec
>{ char testchar;
>int testint;
>} *MyRecArray;
>
>calloc(MyRecArray, 20 * Sizeof(MyRec));
>
>Since it's an array, no pointer reference needed with reading or writing?
>//Use it
>MyRecArray[0].testint = 1;
>printf("Element 1 is %d \r\n", MyRecArray[0]);
>Free(MyRecArray);



 

{smallsort}

Re:Record on the heap

This is the way I actually did it. I think it's right.
BTW, I never actually free the memory. I know that sounds bad, but the
device is Power Up and Run Application or Power Down to end application. It
only has one application. It's a fresh boot everytime.
//Scaling Factors for Analogs
struct FactorRec
{ BYTE SensorType;
float Factor;
float Offset;
float FineAdj;
} *SensorInfo;
struct RBEAckRec
{ BYTE MsgNum;
BYTE MsgLen;
BYTE Status;
BYTE TimesSent;
DWORD LastSent;
char Msg[30];
} *RBEAckArray;
const BYTE MaxSensors = 7;
const BYTE MaxRBERecs = 20;
//If not enough memory then Exit Program
if ((RBEAckArray = calloc(MaxRBERecs,sizeof(*RBEAckArray)))==NULL)
{ exit(1);}
if ((SensorInfo = calloc(MaxSensors,sizeof(*SensorInfo)))==NULL)
{ exit(1);}
 

Re:Record on the heap

Never de-allocating is what I also do in an embedded program like that.
I want to strongly recommend that if the program ends with an allocation
failure you put some form of diagnostic message or beep or something.
Otherwise you will have no feel for why it ended, crash, other problem or
memory allocation failure.
Storing values as floats is ok but every C function working with floating
point takes and/or returns a double, not a float. This causes a conversion
on each call. Along with the extra processing time and code size used for
the conversion it also means that you have elected to live with but 6
decimal digits of precision, what a float provides. Consider using doubles.
Why are you using const BYTE for the max number of sensors instead of a
#define? In C++ that works well, but in C that creates another memory
location and data access for the value.
. Ed
Quote
Richard wrote in message
news:47546da0$ XXXX@XXXXX.COM ...

This is the way I actually did it. I think it's right.
BTW, I never actually free the memory. I know that sounds bad, but the
device is Power Up and Run Application or Power Down to end application.
It only has one application. It's a fresh boot everytime.

//Scaling Factors for Analogs
struct FactorRec
{ BYTE SensorType;
float Factor;
float Offset;
float FineAdj;
} *SensorInfo;

struct RBEAckRec
{ BYTE MsgNum;
BYTE MsgLen;
BYTE Status;
BYTE TimesSent;
DWORD LastSent;
char Msg[30];
} *RBEAckArray;

const BYTE MaxSensors = 7;
const BYTE MaxRBERecs = 20;

//If not enough memory then Exit Program
if ((RBEAckArray = calloc(MaxRBERecs,sizeof(*RBEAckArray)))==NULL)
{ exit(1);}

if ((SensorInfo = calloc(MaxSensors,sizeof(*SensorInfo)))==NULL)
{ exit(1);}
 

Re:Record on the heap

Inline...
"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
Storing values as floats is ok but every C function working with floating
point takes and/or returns a double, not a float. This causes a
conversion on each call. Along with the extra processing time and code
size used for the conversion it also means that you have elected to live
with but 6 decimal digits of precision, what a float provides. Consider
using doubles.
I actually started out using words in mem and storing on flash. I simply
divided them by 10 or 100 or whatever I needed to save space. I have some
sensors that are inches of wc, and g's and require 5 or 6 places.
Quote

Why are you using const BYTE for the max number of sensors instead of a
#define? In C++ that works well, but in C that creates another memory
location and data access for the value.
Mainly because I don't know any better. Let me figure it out.
I honestly figured if I did a constant the compiler knew not to use memory
space and it was taken care during compile time.
Quote

. Ed

 

Re:Record on the heap

Ed, thanks for the tips. Any and all are welcome.
I've done lots of embedded stuff using Turbo Pascal and Delphi on DOS and
XPe systems. I've done lots of pics and Atmels using Basic Compilers and a
couple of small C projects.
This is my first experience with C and I still try to mix the languages and
theres lot of Gotchas. So again, all advice is welcome. The library I have
to use for this device is in Turbo C so I pretty much had to use it. Kind
of glad since I'm learning a lot.
For being my first C program, I'm up to 7,000 lines of code and it's been
running pretty good, with the help of this forum to answer my basic
questions.
I just did a J1939 gateway in C on a pic. It's wasn't a natural CAN enabled
pic. I had to write all the low level routines manually. Bit level stuff
is pretty easy on Pic's. A lot different in C for the PC. Remember all the
bit field questions awhile back??? :)
Anyway, Thanks again, to everyone helping along the way.
Richard
 

Re:Record on the heap

"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
Why are you using const BYTE for the max number of sensors instead of a
#define? In C++ that works well, but in C that creates another memory
location and data access for the value.
I must be using defines incorrectly then....
#define maxregs = 32;
Then when I do
if ((rtvals = (WORD*)calloc(maxregs,sizeof(WORD)))==NULL)
{ exit(1);}
I get Expression syntax error for maxregs.
 

Re:Record on the heap

All, no equal sign and no ";"
#define maxsensors 7
"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote

Why are you using const BYTE for the max number of sensors instead of a
#define? In C++ that works well, but in C that creates another memory
location and data access for the value.
 

Re:Record on the heap

Richard wrote:
Quote
All, no equal sign and no ";"
#define maxsensors 7
Correct.
#define is a macro.
Everything that appears to the right of the name is substituted for the name.
Your example:
#define maxregs = 32;
if ((rtvals = (WORD*)calloc(maxregs,sizeof(WORD)))==NULL)
was converted by the pre-processor to
if ((rtvals = (WORD*)calloc(= 32;,sizeof(WORD)))==NULL)
So, I will add just one more bit of caution:
#define maxregs 32+2
int array[maxregs*2];
allocates only 36 bytes.
#define maxregs (32+2)
int array[maxregs*2];
allocates the expected 68 bytes.
 

Re:Record on the heap

"Richard" < XXXX@XXXXX.COM >writes:
Quote
All, no equal sign and no ";"
#define maxsensors 7
Why not the better behaved
enum
{
maxsensors = 7
};
?
 

Re:Record on the heap

FYI:
Unnamed enums came to the language long after the compiler he is using came
out.
FWIW:
I view them as abominations.
. Ed
Quote
Thomas Maeder wrote in message news: XXXX@XXXXX.COM ...

Why not the better behaved

enum
{
maxsensors = 7
};

?
 

Re:Record on the heap

"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >writes:
Quote
>Thomas Maeder wrote in message news: XXXX@XXXXX.COM ...
>
>Why not the better behaved
>
>enum
>{
>maxsensors = 7
>};
>
>?

FYI: Unnamed enums came to the language long after the compiler he
is using came out.
I see. But even a named enum type would be much preferable than a
macro, when the purpose is to define a symbol for a numerical
constant.
Quote
FWIW:
I view them as abominations.
Well, using #define to define a symbol for a numerical constant has
the drawback of that symbol not respecting scope. A (named or unnamed)
enum may look odd at first, but in many cases provides the same
definition without the drawback. The tradeoff seems clear to me.
 

Re:Record on the heap

I am quite comfortable with macros. I am not comfortable with unnamed
enums.
I do not understand why you rail about macros not having limited scope.
Programming requires discipline. The argument against macros says that when
being undisciplined one can get into trouble. Did you expect undisciplined
behavior to not cause trouble?
An enum is a set of symbols with optional numeric specification. Its uses
are obvious, for providing a limited set of selections and providing named
selections for auto-documentation and ease of understanding. An unnamed
enum is the subversion of that for the purposes of providing names for
numbers. Put the unnamed enum in a header file and, just as with a macro,
it can dabble in the contents of any file which includes that header.
The unnamed enum was a banned-in-the-spec but then later allowed because
after all Microsoft used them in MFC and later Bjorne started using them.
Somehow the banned-in-the-spec became allowed-in-the-spec. So you end up
grepping header files for the unnamed enum instead of for the macro but of
course, unlike the macro, the fact that it is an enum doesn't show since
grepping puts out the one line with the name on it and not the line with the
word 'enum'.
I would not be unhappy if unnamed enums were banned.
. Ed
Quote
Thomas Maeder wrote in message
news: XXXX@XXXXX.COM ...

>FYI: Unnamed enums came to the language long after the
>compiler he is using came out.

I see. But even a named enum type would be much preferable than a
macro, when the purpose is to define a symbol for a numerical
constant.


>FWIW:
>I view them as abominations.

Well, using #define to define a symbol for a numerical constant has
the drawback of that symbol not respecting scope. A (named or unnamed)
enum may look odd at first, but in many cases provides the same
definition without the drawback. The tradeoff seems clear to me.