manipulation and memory allocation

I

iouswuoibev

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function? For example, I have the following function:

char * to_bits(int n, char *s, int b) {
int i;

if(b == 0)
b = 32;

if(s != NULL) {

free(s);
}

s = (char *)malloc(sizeof(char) * (b + 1));

for(i = b - 1; i > -1; i--) {

if((0x01 << i) & n) {

s[b - i - 1] = '1';
}
else {

s[b - i - 1] = '0';
}
}

s = '\0';

return s;
}


This function converts an integer into a string representation of its
bits. As you can see, it allocates and deallocates its own memory in
order to return a new string. The alternative would be allocating the
required memory outside of the function, e.g. calling the function as
follows:

s = to_bits(n, s = malloc(TB_SSIZE), int b);

Where TB_SSIZE is the required length of the string.

Is either method good or bad, and why or why not?
 
P

pete

s = (char *)malloc(sizeof(char) * (b + 1));

s = malloc(b + 1);

The cast is bad.
sizeof(char) is one always.

It would have been simpler for you to have posted a rudimentary plan B,
concerning the return value of malloc,
than to have to explain why it's missing from the code.

if (s == NULL) {
exit(EXIT_FAILURE);
}
This function converts an integer into a string representation of its
bits. As you can see, it allocates and deallocates its own memory in
order to return a new string.
The alternative would be allocating the
required memory outside of the function, e.g. calling the function as
follows:

s = to_bits(n, s = malloc(TB_SSIZE), int b);

Where TB_SSIZE is the required length of the string.

Is either method good or bad, and why or why not?

I like the second method.
It's possible that a whole bunch of strings might be output
and that you could use the same buffer for all of them,
that is to say that s could be an automatic array instead.

char s[TB_SSIZE + 1];

http://groups-beta.google.com/group/comp.lang.c/msg/5ac9de7e87e58d46?hl=en
 
R

Rob

pete said:
s = malloc(b + 1);

The cast is bad.
sizeof(char) is one always.

OK, I thought it was platform dependant.
I like the second method.
It's possible that a whole bunch of strings might be output
and that you could use the same buffer for all of them,
that is to say that s could be an automatic array instead.

char s[TB_SSIZE + 1];

That's a good reason, thanks.
 
A

August Karlstrom

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function? For example, I have the following function:

char * to_bits(int n, char *s, int b) {
int i;

if(b == 0)
b = 32;

if(s != NULL) {

free(s);
}

s = (char *)malloc(sizeof(char) * (b + 1));

for(i = b - 1; i > -1; i--) {

if((0x01 << i) & n) {

s[b - i - 1] = '1';
}
else {

s[b - i - 1] = '0';
}
}

s = '\0';

return s;
}


This function converts an integer into a string representation of its
bits. As you can see, it allocates and deallocates its own memory in
order to return a new string. The alternative would be allocating the
required memory outside of the function, e.g. calling the function as
follows:

s = to_bits(n, s = malloc(TB_SSIZE), int b);

Where TB_SSIZE is the required length of the string.

Is either method good or bad, and why or why not?


The second approach is more flexible, for instance if the client wants
to use a non-heap allocated array, so my suggestion is:

/* to_bits(n, s, b) returns... where s holds at least b + 1 elements. */

char * to_bits(int n, /*out*/ char *s, int b)
{
int i;

assert((n >= 0) && (b >= 0));
if(b == 0) { b = 32; }
for(i = b - 1; i > -1; i--) {
if((0x01 << i) & n) { s[b - i - 1] = '1'; }
else { s[b - i - 1] = '0'; }
}
s = '\0';
return s;
}


-- august
 
C

CBFalconer

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function? For example, I have the following function:

char * to_bits(int n, char *s, int b) {
int i;

if(b == 0)
b = 32;
if(s != NULL) {
free(s);
}
s = (char *)malloc(sizeof(char) * (b + 1));
... snip ...

In this case it is bad. Besides the fundamental coding errors, you
are introducing anomalous complications and restrictions into the
functions usage, which are not evident from the prototype. It must
be passed an s that has been created by malloc. That action will
leave behind an orphan pointer that is no longer usable in any
way. If the enclosing file fails to #include <stdlib.h> there will
be no complaint (because of the extraneous cast), and the code will
quietly go off into the boondocks. sizeof(char) is 1 by
definition, and the usage only obfuscates. What purpose, if any,
does the magic number 32 serve, and it seems to be 33 anyhow. If
it has something to do with the size of an int get it from the
appropriate place in <limits.h>.

The whole thing is balancing on a pinhead and is prone to
precipitate errors.

Your objective is suspect. The input integer already consists of
bits, so the only possible purpose of all this is for output of a
char. representation to some file. So write a function interface
that says just that:

int writebits(int n, FILE *f);

which can return some form of error indicator to allow for full
disks, i/o errors, etc. Then work out how to do it. It is not
hard.

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
R

Rob

If the enclosing file fails to #include said:
be no complaint (because of the extraneous cast), and the code will
quietly go off into the boondocks.

OK, I didn't know a cast would do that.
What purpose, if any,
does the magic number 32 serve, and it seems to be 33 anyhow. If
it has something to do with the size of an int get it from the
appropriate place in <limits.h>.

That's quite right. What seems to be 33? The size of the array is b + 1
so I can terminate the string with \0.
Your objective is suspect. The input integer already consists of
bits, so the only possible purpose of all this is for output of a
char. representation to some file.

I don't know why you think this is the sole possible purpose for having
such a function. I was using it while experimenting with bitwise
operations, so I could see what was happening to each bit.
 
F

Flash Gordon

Rob said:
OK, I thought it was platform dependant.

The number of bits in a char is platform dependant, but however many
bits it is, that is the size C defines a byte to be. I've used DSP
processors where a byte is 16 bits, as specified by CHAR_BIT in limits.h

<snip>
 
F

Fred L. Kleinschmidt

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function? For example, I have the following function:

char * to_bits(int n, char *s, int b) {
int i;

if(b == 0)
b = 32;

if(s != NULL) {

free(s);
}

s = (char *)malloc(sizeof(char) * (b + 1));

for(i = b - 1; i > -1; i--) {

if((0x01 << i) & n) {

s[b - i - 1] = '1';
}
else {

s[b - i - 1] = '0';
}
}

s = '\0';

return s;
}

This function converts an integer into a string representation of its
bits. As you can see, it allocates and deallocates its own memory in
order to return a new string. The alternative would be allocating the
required memory outside of the function, e.g. calling the function as
follows:

s = to_bits(n, s = malloc(TB_SSIZE), int b);

Where TB_SSIZE is the required length of the string.

Is either method good or bad, and why or why not?


Neither is good.

There is no good reason for 's' to be passed as an input parameter - or
'b' for that matter. Your function should be:
char * to_bits(int n);
and documented that it allocates memory for the return value and it is
the application's responsibility to free that memory when it is no
longer needed.
Also, don't assume that sizeof(int) is 4. You should allocate space for
(8*sizeof(int) + 1) characters, and don't worry about whether you fill
all of them with 0's or 1's.

--
Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Common User Interface Services
M/S 2R-94 (206)544-5225
#! rnews 1800
Xref: xyzzy rec.arts.sf.written:1081779
Newsgroups: rec.arts.sf.written
Path: xyzzy!nntp
From: Eric D. Berge <eric_berge @ hotmail.com.invalid>
Subject: Re: editorial choices: updating Re: Schmitz's "Grandpa" a Hub story?
X-Nntp-Posting-Host: anc659yt31.sw.nos.boeing.com
Content-Type: text/plain; charset=us-ascii
Message-ID: <[email protected]>
Sender: (e-mail address removed) (Boeing NNTP News Access)
Content-Transfer-Encoding: 7bit
Organization: The Boeing Company
X-Newsreader: Forte Agent 1.8/32.548
References: <[email protected]> <[email protected]> <[email protected]> <[email protected]> <[email protected]> <2005051022394724084%kurtbusiek@comcastnetherworld> <[email protected]> <2005051117505527590%kurtbusiek@comcastnetherworld>
Mime-Version: 1.0
Date: Thu, 12 May 2005 15:28:25 GMT

On everything? Or just on a book for which that's the expressed intent?

Whenever the eternal "How do you measure quality in a book?" debate
rolls 'round.
 
C

CBFalconer

Rob said:
.... snip ...


That's quite right. What seems to be 33? The size of the array is
b + 1 so I can terminate the string with \0.

But nothing says an int has 32 bits. It may have any number, with
a minimum of 16.
I don't know why you think this is the sole possible purpose for
having such a function. I was using it while experimenting with
bitwise operations, so I could see what was happening to each bit.

You have simply confirmed my attitude. The only purpose is for
display, which you do by outputting to a file. If you are bit
picking you should be using unsigned ints anyhow. Try this
(without the testing code), which I have lying about:

/* Routines to display values in various bases */
/* with some useful helper routines. */
/* by C.B. Falconer, 19 Sept. 2001 */
/* Released to public domain. Attribution appreciated */

#include <stdio.h>
#include <string.h>
#include <limits.h> /* ULONG_MAX etc. */

/* ======================= */
/* reverse string in place */
size_t revstring(char *stg)
{
char *last, temp;
size_t lgh;

lgh = strlen(stg);
if (lgh > 1) {
last = stg + lgh; /* points to '\0' */
while (last-- > stg) {
temp = *stg; *stg++ = *last; *last = temp;
}
}
return lgh;
} /* revstring */

/* ============================================ */
/* Mask and convert digit to hex representation */
/* Output range is 0..9 and a..f only */
int hexify(unsigned int value)
{
static char hexchars[] = "0123456789abcdef";

return (hexchars[value & 0xf]);
} /* hexify */

/* ================================================== */
/* convert unsigned number to string in various bases */
/* 2 <= base <= 16, controlled by hexify() */
/* Returns actual output string length */
size_t basedisplay(unsigned long number, unsigned int base,
char *stg, size_t maxlgh)
{
char *s;

/* assert (stg[maxlgh]) is valid storage */
s = stg;
if (maxlgh && base)
do {
*s = hexify(number % base);
s++;
} while (--maxlgh && (number = number / base) );
*s = '\0';
revstring(stg);
return (s - stg);
} /* basedisplay */

/* ================================================ */
/* convert signed number to string in various bases */
/* 2 <= base <= 16, controlled by hexify() */
/* Returns actual output string length */
size_t signbasedisplay(long number, unsigned int base,
char * stg, size_t maxlgh)
{
char *s;
size_t lgh;
unsigned long n;

s = stg; lgh = 0;
n = (unsigned long)number;
if (maxlgh && (number < 0L)) {
*s++ = '-';
maxlgh--;
n = -(unsigned long)number;
lgh = 1;
}
lgh = lgh + basedisplay(n, base, s, maxlgh);
return lgh;
} /* signbaseddisplay */


/* ==================== */
/* flush to end-of-line */
int flushln(FILE *f)
{
int ch;

while ('\n' != (ch = fgetc(f)) && (EOF != ch)) /* more */;
return ch;
} /* flushln */

/* ========== END of generically useful routines ============ */

/* ========================= */
/* Prompt and await <return> */
static void nexttest(char *prompt)
{
static char empty[] = "";

if (NULL == prompt) prompt = empty;
printf("\nHit return for next test: %s", prompt);
fflush(stdout);
flushln(stdin);
} /* nexttest */

/* ============================== */
/* Display a value and its length */
static void show(char *caption, int sz, char *stg)
{

if ((unsigned)sz != strlen(stg))
printf("Something is wrong with the sz value\n");
printf("%s: sz = %2d \"%s\"\n", caption, sz, stg);
} /* show */

/* =========== */
/* exercise it */
int main(void)
{
#define LGH 40
#define VALUE 1234567890

char stg[LGH];
unsigned int base;
int sz;

printf("\nExercising basedisplay routine\n");
printf("\nbase sz value\n");
for (base = 2; base <= 16; base++) {
sz = (int)basedisplay(VALUE, base, stg, LGH - 1);
printf("%2d %2d %s\n", base, sz, stg);
}

nexttest("ULONG_MAX");
for (base = 8; base <= 16; base++) {
sz = (int)basedisplay(ULONG_MAX, base, stg, LGH - 1);
printf("%2d %2d %s\n", base, sz, stg);
}

basedisplay(0, 10, stg, 3);
printf("\nzero %s\n", stg);

basedisplay(VALUE, 10, stg, 3);
printf("3 lsdigits only, base 10 %s\n", stg);

printf("\nBad calls:\n");

sz = (int)basedisplay(VALUE, 10, stg, 0);
show("0 length field", sz, stg);

sz = (int)basedisplay(VALUE, 1, stg, 20);
show("base 1, lgh 20", sz, stg);

sz = (int)basedisplay(VALUE, 0, stg, 20);
show("base 0, lgh 20", sz, stg);

sz = (int)signbasedisplay(-1234, 10, stg, 0);
show("0 lgh fld, -ve", sz, stg);

sz = (int)signbasedisplay(-1234, 10, stg, 2);
show("truncate -1234", sz, stg);

nexttest("System limits");

sz = (int)signbasedisplay(SCHAR_MIN, 10, stg, 20);
show("SCHAR_MIN ", sz, stg);

sz = (int)signbasedisplay(SCHAR_MAX, 10, stg, 20);
show("SCHAR_MAX ", sz, stg);

sz = (int)signbasedisplay(UCHAR_MAX, 10, stg, 20);
show("UCHAR_MAX ", sz, stg);

sz = (int)signbasedisplay(CHAR_MIN, 10, stg, 20);
show("CHAR_MIN ", sz, stg);

sz = (int)signbasedisplay(CHAR_MAX, 10, stg, 20);
show("CHAR_MAX ", sz, stg);

sz = (int)signbasedisplay(MB_LEN_MAX, 10, stg, 20);
show("MB_LEN_MAX ", sz, stg);

sz = (int)signbasedisplay(SHRT_MIN, 10, stg, 20);
show("SHRT_MIN ", sz, stg);

sz = (int)signbasedisplay(SHRT_MAX, 10, stg, 20);
show("SHRT_MAX ", sz, stg);

sz = (int)signbasedisplay(USHRT_MAX, 10, stg, 20);
show("USHRT_MAX ", sz, stg);

sz = (int)signbasedisplay(INT_MIN, 10, stg, 20);
show("INT_MIN ", sz, stg);

sz = (int)signbasedisplay(INT_MAX, 10, stg, 20);
show("INT_MAX ", sz, stg);

sz = (int)signbasedisplay(INT_MAX, 10, stg, 20);
show("INT_MAX ", sz, stg);

sz = (int) basedisplay(UINT_MAX, 10, stg, 20);
show("UINT_MAX ", sz, stg);

sz = (int)signbasedisplay(LONG_MIN, 10, stg, 20);
show("LONG_MIN ", sz, stg);

sz = (int)signbasedisplay(LONG_MAX, 10, stg, 20);
show("LONG_MAX ", sz, stg);

sz = (int) basedisplay(ULONG_MAX, 10, stg, 20);
show("ULONG_MAX ", sz, stg);

nexttest("DONE");
return 0;
} /* main */

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
A

Alan Balmer

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function?

In general, I believe that memory should be allocated and freed in the
same scope.

If your function allocates the memory, uses it, then deallocates it,
fine. If it allocates memory and passes it back to the calling
function, that's usually a bad idea, since it makes the caller
responsible for memory it didn't allocate.
 
K

Keith Thompson

Alan Balmer said:
In general, I believe that memory should be allocated and freed in the
same scope.

If your function allocates the memory, uses it, then deallocates it,
fine. If it allocates memory and passes it back to the calling
function, that's usually a bad idea, since it makes the caller
responsible for memory it didn't allocate.

I presume that by "In general" you mean "usually", not "always".

There are many circumstances where it makes sense to allocate memory
in one place and free it somewhere else (though of course you have to
be careful to get it right). The malloc() function itself is an
example of this; it allocates memory and leaves it to the caller to
make sure it's freed later. Or if I'm building a data structure, I
might have a function that allocates a single node and returns a
pointer to it; eventually something else will have to free the
allocated node(s).
 
F

Fred L. Kleinschmidt

Alan said:
In general, I believe that memory should be allocated and freed in the
same scope.

If your function allocates the memory, uses it, then deallocates it,
fine. If it allocates memory and passes it back to the calling
function, that's usually a bad idea, since it makes the caller
responsible for memory it didn't allocate.

So you think that strdup() is a bad idea, since it allocates memory and
passes it back to the caller? How about Motif XmStringCreate() functions
- are they also a bad idea?
 
A

Alan Balmer

I presume that by "In general" you mean "usually", not "always".

Of course.
There are many circumstances where it makes sense to allocate memory
in one place and free it somewhere else (though of course you have to
be careful to get it right). The malloc() function itself is an
example of this; it allocates memory and leaves it to the caller to
make sure it's freed later.

Yes. It also results in many examples of the pitfalls of doing this
;-)
Or if I'm building a data structure, I
might have a function that allocates a single node and returns a
pointer to it; eventually something else will have to free the
allocated node(s).

In the case of a function whose primary purpose is allocation of a
data structure, the same logic applies. The user should call the
allocator function and the corresponding deallocator (you did provide
one, of course) at the same scope when possible.

Of course, it's often possible to encapsulate functions like this as
an abstract data type so that the user never sees it, or sees it only
at an abstraction level that matches his problem domain, making
mistakes less likely.
 
C

CBFalconer

Alan said:
In general, I believe that memory should be allocated and freed
in the same scope.

If your function allocates the memory, uses it, then deallocates
it, fine. If it allocates memory and passes it back to the
calling function, that's usually a bad idea, since it makes the
caller responsible for memory it didn't allocate.

s/that's usually/that can be/

A function that allocates memory only should be treated much like
any other call to malloc, and thus should also be simple,
understandable, and documented. This often arises when creating
nodes for linked lists, or entries for symbol tables, etc. The
principle should be that the function that causes the allocation
also causes the deallocation.

tbl = opensymboltable(...)
/* code such as "enterintable(tbl, ...)" */
closesymboltable(tbl); /* deleting all the entries */

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
M

Malcolm

When writing a function that manipulates data (for example, a string),
is it in principle a good or bad idea to allocate/deallocate memory
within that function? For example, I have the following function:

Is either method good or bad, and why or why not?
There aren't definite rules about how to manage memory.

For instance often input, like a name, is technically unbounded but actually
always fits in a relatively small buffer. So you can argue about whether it
is worth handling corrupt input or not. In a video game you probably don't
need to worry, but in a banking system you might create a security flaw.

The first priority is for the code to do what it is designed to do. The
second priority is usually for it to be readable by a human programmer, and
the third priority is for it to be efficient.
These aims are often in conflict, particuarly with memory management.
Increasingly it is becoming obvious that priority two is the one that tends
to distinguish the successful projects from the disasters.

So when designing the interface to a function, think, "what does this
function do?" and "can I explain to someone else how to use it?". However
you cannot totally forget "is it calling malloc() unnecessarily often?" or
"what happens if I am passed a giant string?".
 
A

Alan Balmer

s/that's usually/that can be/

I'll stick with usually :)
A function that allocates memory only should be treated much like
any other call to malloc, and thus should also be simple,
understandable, and documented.

And the documentation should be built into the name, if possible. (See
below).
This often arises when creating
nodes for linked lists, or entries for symbol tables, etc. The
principle should be that the function that causes the allocation
also causes the deallocation.

tbl = opensymboltable(...)
/* code such as "enterintable(tbl, ...)" */
closesymboltable(tbl); /* deleting all the entries */

A good example, though I would probably make the names
createsymboltable and deletesymboltable, to emphasize the fact that we
are allocating new objects, not just opening old ones. Also, your
example has the creation and deletion in the same scope, which still
follows the principle.
 
M

Martien Verbruggen

On Thu, 12 May 2005 15:21:29 GMT,

[snip discussion of function that needs to fill/create a string with a
binary representation of an integer]

[snip]
Also, don't assume that sizeof(int) is 4. You should allocate space for
(8*sizeof(int) + 1) characters, and don't worry about whether you fill
all of them with 0's or 1's.

If you are careful enough to not assume that sizeof(int) == 4, why
would you, at the same time, be bold enough to assume that the number
of bits in a byte is 8 instead of using CHAR_BIT?

Martien
 
W

websnarf

When writing a function that manipulates data (for example, a
string), is it in principle a good or bad idea to allocate/
deallocate memory within that function? For example, I have the
following function:

char * to_bits(int n, char *s, int b) {
int i;

if(b == 0)
b = 32;

32? Do you mean sizeof(n)*CHAR_BIT ?
if(s != NULL) {
free(s);
}
s = (char *)malloc(sizeof(char) * (b + 1));

This sequence looks functionally equivalent to:

s = (char *) realloc (s, (b + 1) * sizeof (char));

However, you don't seem to have done anything about the case of
receiving a NULL from malloc (if/when you run out of memory).
for(i = b - 1; i > -1; i--) {
if((0x01 << i) & n) {
s[b - i - 1] = '1';
} else {
s[b - i - 1] = '0';
}
}
s = '\0';
return s;
}


This looks like its technically correct but a lot more complicated than
it needs to be. How about:

for (i = b - 1; i >= 0; i--)
s = ((1 << (b-i-1)) & n) ? '1' : '0';

Or even:

for (i = b - 1; i >= 0; i--)
s = '0' + ((1 << (b-i-1)) & n);
This function converts an integer into a string representation of its
bits. As you can see, it allocates and deallocates its own memory in
order to return a new string. The alternative would be allocating
the required memory outside of the function, e.g. calling the
function as follows:

s = to_bits(n, s = malloc(TB_SSIZE), int b);

Well, drop the "int" before the b and you are set. BTW, your function
actually is strangely compatible with this already -- but you can see
the advantage of the "realloc" simplification.
Where TB_SSIZE is the required length of the string.

Is either method good or bad, and why or why not?

Well, not checking the return of malloc is bad. Otherwise this all
depends on your intended semantics. The function will allocate memory
(if you pass it NULL) for a NUL terminated string containing a textual
representation of the binary bits of a 2s complement number and will
recycle allocated space if you call it repeatedly (which makes the
advantage of using realloc clear.) Is this how you are intending to
use it? You might rename it as "to_bits_realloc()" to be explicit
about its semantics, and there are clearly ways of speeding this up
using tables.

But other than that, the code at least looks correct.
 
O

Old Wolf

This sequence looks functionally equivalent to:

s = (char *) realloc (s, (b + 1) * sizeof (char));

Yes -- they both invoke undefined behaviour, and both
instruct the compiler to not give a warning about the
undefined behaviour.

Also, the realloc() is functionally different anyway. If
the memory allocation fails, then the original example
frees the original string, but the realloc() example leaks
the original string.

To the OP: the best way to call malloc is:

s = malloc(b+1);

the sizeof and the cast are worse than redundant.
However, you don't seem to have done anything about the case of
receiving a NULL from malloc (if/when you run out of memory).
[b is an int from 1 to 32, and n is a 32-bit int]
How about:
for (i = b - 1; i >= 0; i--)
s = ((1 << (b-i-1)) & n) ? '1' : '0';


Undefined behaviour when (b-i-1) is 31 (ie. b = 32, i = 0),
because the left shift causes integer overflow.
Change the 1 to 1U.
Or even:

for (i = b - 1; i >= 0; i--)
s = '0' + ((1 << (b-i-1)) & n);


Absolutely dreadful. For example, b=32, i=29, n=0x7FFFFFF .
Then (1 << (b-i-1)) is 4, as is ((1 << (b-i-1)) & n),
so you are assigning '0' + 4 (ie. '4') to s.

In some cases, the behaviour is implementation-defined
(assigning an out-of-range value to a char).
But other than that, the code at least looks correct.
Just a few hiccups on the way.
 
A

Achintya

Hi,

In my opinion also the second method is a better one. since always a
parent context knows the memory allocation/deallocation requirements
better than a child context specially in case of C language where the
data is not hidden.

-vs_p...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top