memory deallocation

  • Follow


Hi there,

I've written a function that 'converts' a structure of type timeval to
a c-string:

char *tv2Str(struct timeval tvX)
{
        char caStr[20];
        char *cpResult;

        sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);

        cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
        strcpy(cpResult, caStr);

        return cpResult;
}

I use it like this:

printf("%s", tv2Str((struct timeval){123, 456}) );

Question:
How (if at all) does the compiler (gcc) ensure that the memory
allocated in the above function is deallocated after the printf call ?

Thanks,
Cornel



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Cornel 7/25/2003 11:07:41 AM

"Cornel Arnet" <c.arnet@bluewin.ch> wrote in message
news:3f1fd671@epflnews.epfl.ch...
 > Hi there,
 >
 > I've written a function that 'converts' a structure of type timeval to
 > a c-string:
 >
 > char *tv2Str(struct timeval tvX)
 > {
 >         char caStr[20];
 >         char *cpResult;
 >
 >         sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);
 >
 >         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
 >         strcpy(cpResult, caStr);
 >
 >         return cpResult;
 > }
 >
 > I use it like this:
 >
 > printf("%s", tv2Str((struct timeval){123, 456}) );
 >
 > Question:
 > How (if at all) does the compiler (gcc) ensure that the memory
 > allocated in the above function is deallocated after the printf call ?

No, it doesn't. You have just created a memory leak. Any memory
allocated with malloc() must be explicitly deallocated with free(). To
fix the problem you would have to use tv2Str() like this:

    timeval t = {123, 456};
    char* s = tv2Str(t);
    printf("%s", s);
    free(s);

As you can see it is a bit cumbersome to do the C way. But since you
asked this question in C++ group, you might as well go for a more C++
like solution:
....
#include <cstdio>
#include <string>
#include <sstream>

std::string tv2Str(const timeval& tv)
{
    std::stringstream text;
    text << tv.tv_sec << "." << tv.tv_usec;
    return text.str();
}

int main()
{
    timeval tv = {123, 456};
    printf("%s", tv2Str(tv).c_str());
    return 0;
}

And to get rid of the C remnants altogether you might do it like this:

....
#include <iostream>

std::ostream& operator<<(std::ostream& out, const timeval& tv)
{
    out << tv.tv_sec << "." << tv.tv_usec;
    return out;
}

int main()
{
    timeval tv = {123, 456};
    std::cout << "Time: " << tv;
    return 0;
}

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Peter 7/26/2003 12:45:54 PM


On Fri, 25 Jul 2003 07:07:41 -0400, Cornel Arnet wrote:

 > Hi there,

Hi _there_ :-)

 > I've written a function that 'converts' a structure of type timeval to a
 > c-string:
 >
[...]
 >         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
 >         strcpy(cpResult, caStr);

strcpy copies strlen(caStr)+1 chars to the buffer. You allocated one less.
(There are a few other deficiencies in this function, which I won't
address now.)

BTW: sizeof(char) is 1 by definition.

 >         return cpResult;
 > }
 >
 > I use it like this:
 >
 > printf("%s", tv2Str((struct timeval){123, 456}) );

GCC-specific syntax. BTW, what's wrong with puts? I see no need for printf
here.

 > Question:
 > How (if at all) does the compiler (gcc) ensure that the memory allocated
 > in the above function is deallocated after the printf call ?

Not at all. You didn't tell it to deallocate anything, so it won't. The
canonical solution is called std::string, which encapsulates memory
management. This means a) automatic deallocation when the buffer is no
longer needed and b) No possibility of one-off errors like the one you
committed above. Please look up strings in your favorite C++ textbook. :-)

-- 
Best Regards,   |   Hi! I'm a .signature virus. Copy me into
  Sebastian      |   your ~/.signature to help me spread!


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Sebastian 7/26/2003 1:06:09 PM

<snip>
 >         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
<snip>

 > How (if at all) does the compiler (gcc) ensure that the memory
 > allocated in the above function is deallocated after the printf call ?

Hi :
Simple answer ... it doesn't .  The caller of this
function will be responsible for deleting the memory.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply steve 7/26/2003 1:12:11 PM

Hi,


> char *tv2Str(struct timeval tvX)
> {
>         char caStr[20];
>         char *cpResult;

>         sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);

>         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
>         strcpy(cpResult, caStr);

>         return cpResult;
> }

> I use it like this:

> printf("%s", tv2Str((struct timeval){123, 456}) );

> Question:
> How (if at all) does the compiler (gcc) ensure that the memory 
> allocated in the above function is deallocated after the printf call ?

As simple as it is: It doesn't. It is released as soon as the tv2Str
function is left because it is an automatic variable, thus rendering the
pointer invalid and making your use of the function dangerous. It
"might" appear to work sometimes, but don't count on it.

To prevent this trouble, you'd either
i) declare the string buffer as static and hence giving it a global
lifetime, understanding that there will be only one buffer in the
program and later calls will invalidate the buffers passed out earlier,
ii) manage the memory itself by allocating a buffer in tv2Str and
requiring for the caller to release it after it's done,
iii) use the string class

Greetings,
	Thomas


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Thomas 7/26/2003 4:05:23 PM

In message <3f1fd671@epflnews.epfl.ch>, Cornel Arnet
<c.arnet@bluewin.ch> writes
>I've written a function that 'converts' a structure of type timeval to 
>a c-string:
>
>char *tv2Str(struct timeval tvX)
>{
>        char caStr[20];
>        char *cpResult;
>
>        sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);
>
>        cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
>        strcpy(cpResult, caStr);
>
>        return cpResult;
>}
>
>I use it like this:
>
>printf("%s", tv2Str((struct timeval){123, 456}) );
>
>Question:
>How (if at all) does the compiler (gcc) ensure that the memory 
>allocated in the above function is deallocated after the printf call ?

It doesn't and it isn't. And you have a real problem in C (which your
code looks like) because there is nothing you can do about it. C++
provides you many solutions, most of which centre round avoiding that
explicit allocation of dynamic resources. Here is a minimalist amendment
to your code (far from being a stylistically elegant solution):

string tv2Str(struct timeval tvX)
{
        char caStr[20];
        sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);

        return caStr;
}

cout << tv2Str(timeval(123, 456));

assuming that you provide timeval with a ctor.

If you cannot use a C++ solution, then please post to
comp.lang.c.moderated instead.

-- 
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow      ACCU



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Francis 7/26/2003 4:06:37 PM

In article <pan.2003.07.25.15.30.20.50854@gammaray.dyndns.org>,
  on 26 Jul 2003 09:06:09 -0400,
  Sebastian Kapfer <sebastian_kapfer@web.de> wrote:

 > On Fri, 25 Jul 2003 07:07:41 -0400, Cornel Arnet wrote:
 >
 >  > printf("%s", tv2Str((struct timeval){123, 456}) );
 >
 > BTW, what's wrong with puts? I see no need for printf
 > here.

puts always adds a '\n' to the end of the output, which printf
doesn't. The right thing here (assuming the GCC extention) is:

   fputs( tv2Str((struct timeval){123, 456}), stdout );

I strongly suspect that the addtional '\n' provided by puts (but not by
fputs) is why so many C programmers use printf as their "default" output
function, even when puts (or similar) would serve them better. I've
always considered this mismatch between puts/fputs to be a major flaw in
the C library.

Regards,
  Andy S
-- 
"Light thinks it travels faster than anything but it is wrong. No matter
  how fast light travels it finds the darkness has always got there first,
  and is waiting for it."                  -- Terry Pratchett, Reaper Man

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Andy 7/27/2003 10:38:57 AM

Cornel Arnet wrote:
> char *tv2Str(struct timeval tvX)
> {
>         char caStr[20];
>         char *cpResult;
> 
>         sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);
> 
>         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
>         strcpy(cpResult, caStr);
> 
>         return cpResult;
> }
> 
> I use it like this:
> 
> printf("%s", tv2Str((struct timeval){123, 456}) );
> 
> Question:
> How (if at all) does the compiler (gcc) ensure that the memory 
> allocated in the above function is deallocated after the printf call ?

It doesn't, you have a memory leak.

Uli

-- 
Questions ?
see  C++-FAQ Lite: http://parashift.com/c++-faq-lite/  first !


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Ulrich 7/27/2003 11:32:26 AM

Ben Hutchings wrote:

> In article <3f1fd671@epflnews.epfl.ch>, Cornel Arnet wrote:
>  > Hi there,
>  >
>  > I've written a function that 'converts' a structure of type timeval

> to  > a c-string:  >
>  > char *tv2Str(struct timeval tvX)
>  > {
>  >         char caStr[20];
>  >         char *cpResult;
>  >
>  >         sprintf(caStr, "%ld.%ld", tvX.tv_sec, tvX.tv_usec);
>  >
>  >         cpResult = (char *)malloc(sizeof(char)*strlen(caStr));
>  >         strcpy(cpResult, caStr);
>  >         return cpResult;
>  > }
> 
> This looks very much like a C program, though it is valid in C++ too. 
> Are you sure you posted to the right group?
> 
>  > I use it like this:
>  >
>  > printf("%s", tv2Str((struct timeval){123, 456}) );
> 
> Struct literals are a GNU extension.

Also present in C99, I bleive, and under consideration
for C++0x, with a proposal before the committee.

-- James.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply James 7/27/2003 5:01:51 PM

"Peter van Merkerk" <merkerk@deadspam.com> wrote in message
news:bfr8ru$hu004$1@ID-

> #include <cstdio>
> #include <string>
> #include <sstream>

>     timeval tv = {123, 456};
>     printf("%s", tv2Str(tv).c_str());

Because you include <cstdio> that should be std::printf.


--
+++++++++++
Siemel Naran


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Siemel 7/27/2003 5:09:18 PM

On Sun, 27 Jul 2003 06:38:57 -0400, Andy Sawyer wrote:

>  >  > printf("%s", tv2Str((struct timeval){123, 456}) );
>  >
>  > BTW, what's wrong with puts? I see no need for printf here.
> 
> puts always adds a '\n' to the end of the output, which printf doesn't.

Yes, I should have used fputs. Sorry.

> I strongly suspect that the addtional '\n' provided by puts (but not by
> fputs) is why so many C programmers use printf as their "default" output
> function, even when puts (or similar) would serve them better. I've
> always considered this mismatch between puts/fputs to be a major flaw in
> the C library.

puts and friends are ill-designed, that's right.

int putchar(int c);
int puts(const char *s);
int putc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int fputc(int c, FILE *stream);

AFAIK these all are ISO C. IMO putc "may be implemented as a macro",
that's all what makes it different from fputc. putc does take a FILE
pointer, but its function name doesn't begin with "f".  puts appends "\n",
fputs does not.

Sometimes, I think evolution should be forbidden :-)

-- 
Best Regards,   |   Hi! I'm a .signature virus. Copy me into
 Sebastian      |   your ~/.signature to help me spread!


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Sebastian 7/27/2003 5:18:09 PM

10 Replies
98 Views

(page loaded in 0.439 seconds)

Similiar Articles:










7/25/2012 4:32:12 PM


Reply: