Incremental memory allocation

D

David Liang

I'm trying to write a string concatenator that (re)allocates memory,
but I'm getting a glibc error on free().

---

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *stracat(char *t, const char *s)
{
if (t == NULL)
if ((t = (char *) malloc(strlen(s)+1)) != NULL)
*t = '\0';
else
t = (char *) realloc(t, strlen(t)+strlen(s)+1);
if (t != NULL)
strcat(t, s);
return t;
}

int main(void)
{
char *p;

p = NULL;
p = stracat(p, "123456789");
p = stracat(p, "ABCDEF");

printf("%s\n", p);
free(p);

exit(0);
}

---
The output with the error:


123456789ABCDEF
*** glibc detected *** a.out: free(): invalid next size (fast):
0x0804a008 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7e01a85]
/lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7e054f0]
a.out[0x8048583]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7dac450]
a.out[0x8048441]
======= Memory map: ========
....

The error disappears if the second call to stracat has fewer
characters, or if stracat was implemented in the following way, so I'm
assuming the problem is with the way I'm using realloc().

char *p = (char *) malloc((t == NULL ? 0 : strlen(t)) + strlen(s)
+ 1);
if (p != NULL)
{
strcpy(p, (t == NULL ? "" : t));
strcat(p, s);
}
free(t);
return p;

I'm using Ubuntu 8.04 with glibc 2.7. Any ideas on how to correct it
would be great, thanks.
 
R

Richard Tobin

David Liang said:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *stracat(char *t, const char *s)
{
if (t == NULL)
if ((t = (char *) malloc(strlen(s)+1)) != NULL)
*t = '\0';
else
t = (char *) realloc(t, strlen(t)+strlen(s)+1);

richard$ cc -ansi -pedantic -Wall -O -o s s.c
s.c: In function 'stracat':
s.c:7: warning: suggest explicit braces to avoid ambiguous 'else'

-- Richard
 
E

Eric Sosman

David said:
I'm trying to write a string concatenator that (re)allocates memory,
but I'm getting a glibc error on free().

---

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *stracat(char *t, const char *s)
{
if (t == NULL)
if ((t = (char *) malloc(strlen(s)+1)) != NULL)
*t = '\0';
else
t = (char *) realloc(t, strlen(t)+strlen(s)+1);
if (t != NULL)
strcat(t, s);
return t;
}

Indentation can make code easier for a human to read, but
when the indentation does not reflect the logical structure of
the code it can actually make things harder. Let's re-format
your code a bit, and see if you can spot what's wrong:

char *stracat(char *t, const char *s)
{
if (t == NULL)
if ((t = (char *) malloc(strlen(s)+1)) != NULL)
*t = '\0';
else
t = (char *) realloc(t, strlen(t)+strlen(s)+1);
if (t != NULL)
strcat(t, s);
return t;
}

Some people make a fetish out of always using { brackets }
with if, while, for, and do-while, in part because it makes this
particular mistake harder.

See also "dangling else."
 
B

Barry Schwarz

I'm trying to write a string concatenator that (re)allocates memory,
but I'm getting a glibc error on free().

---

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

Others have identified the problem with the else attaching to the
wrong if. After you correct this, you still have a problem:
char *stracat(char *t, const char *s)

Nit: This function name is reserved for the implementation.
{
if (t == NULL)

{
if ((t = (char *) malloc(strlen(s)+1)) != NULL)

Nit: You should lose the cast. The only thing it does is prevent the
compiler from warning you of undefined behavior if you don't have a
prototype in scope.
*t = '\0';

}
else
t = (char *) realloc(t, strlen(t)+strlen(s)+1);
if (t != NULL)
strcat(t, s);
return t;
}

int main(void)
{
char *p;

p = NULL;
p = stracat(p, "123456789");

If malloc succeeds on the first call, p points to a 10 byte
allocation.
p = stracat(p, "ABCDEF");

If realloc fails on the second call, p becomes NULL and the 10 byte
area is now a memory leak.
printf("%s\n", p);

And this will invoke undefined behavior if realloc fails.
 
Q

qarnos

        t = (char *) realloc(t, strlen(t)+strlen(s)+1);


If realloc fails, it returns NULL but the original memory block is not
free'd.

You can take care of the leak like this:

char * t2;

if ((t2 = realloc(t, strlen(t) + strlen(s) + 1)) == NULL)
{
free(t);
return NULL;
}

/* now use and return t2 */


Additionally, if a call to realloc passes NULL as the pointer, realloc
behaves like malloc, FWIW.
 
P

Phil Carmody

Malcolm McLean said:
Anti. The rule of three states that humans can cope with three levels
of nested parentheses at once. Curly brackets are no exception. So you
need to keep the bracket count down.

Do they cope with the invisible better than they cope with
the visible?

Phil
 
C

CBFalconer

Malcolm said:
.... snip ...

The problem isn't just the complex flow control, it is also the
syntax used to represent it. If every construct looks similar
then the reader gets lost. That's why in written text we have
punctuation for one level of partitioning, capitals plus punction
for the next, and indentation for the the third. The conventions
have slowly developed over two thousand years. Programming by
constrast is in its infancy.

Um - English, in its more or less present form, has only existed
since roughly the time of Shakespeare. I.e. about 500 years.
 
J

James Kuyper

CBFalconer said:
Malcolm McLean wrote:
... snip ...

Um - English, in its more or less present form, has only existed
since roughly the time of Shakespeare. I.e. about 500 years.

Did he limit the scope of his statement to English? I didn't notice
anything suggesting such a limitation.
 
T

Tomás Ó hÉilidhe

Geoffrey Chaucer was writing recognisable English well over 600
years ago. (Okay, I know, I know - it's not *immediately*
recognisable, but working out what it means is so simple that even
schoolchildren can do it.)



When I was learning Shakespeare at school, (only about 5 years
ago), there was plenty of it that was completely unintelligible. The
teacher had to give many clues before one person copped what was being
said, and even then the students were like "yeah... maybe... I
suppose". Even something like "The die is cast" is unintelligible to
most people in 2009 because everybody uses "dice" as the singular.
When the teacher vocally explained to me what "The die is cast" means,
I figured "die" was actually "dye", in the sense that if you dye
something then it's stained for good and there's no going back. It was
only a year or two later I found out that it was actually a dice.

And as regards saying "even schoolchildren can do it", most people are
at their linguistic peak when they're kids (not all people of course,
but a fairly decent proportion, maybe 65%). When I was living in
Ireland, I had an Arabic lecturer in college who had been living in
Ireland for 30 years. Even after 30 years immersed in speaking
English, in a city where he /had/ to speak English to get anything
done, he still had dodgy inflections (e.g. "The boys is happy", "You
put five resistor in series"), and also sometimes he just plain didn't
cop what you were saying; I'll never forget the day I asked:

"We have a 10-volt battery, right? How could it be that we would
measure anything other than 10 volts across the battery when we apply
a load to it?"

His answer:

"Yes" (with a smile)

I remember everybody in the room turning to the side and looking at
each other with a "Did that just happen?" look on their face. It was
remarkable that this man had been speaking English longer than we had
been alive.

I'm always intrigued when I hear little kids speaking foreign
languages fluently here in Laos. I've been learning the Lao language
for 4 months now, and it's been a very conscious process, I pick up
new words, phrases and constructs every day, and when I find someone
that speaks both Lao and English I take the opportunity to ask
questions... meanwhile I just have to walk down the street to see a
little 6 year old child rambling on to their parents in Lao without
hesitating for a moment to think about how to say something.
 
R

Richard Tobin

When I was learning Shakespeare at school, (only about 5 years
ago), there was plenty of it that was completely unintelligible.
[/QUOTE]
That is anecdotal evidence for a fall in educational standards

Not really. It's more due to the change in vocabulary and style. I
imagine much English spoken by schoolchildren today would be equally
incomprehensible to Shakespeare, or indeed to those educated 40 years
ago.

-- Richard
 
T

Tomás Ó hÉilidhe

That is anecdotal evidence for a fall in educational standards

Not really.  It's more due to the change in vocabulary and style.  I
imagine much English spoken by schoolchildren today would be equally
incomprehensible to Shakespeare, or indeed to those educated 40 years
ago.[/QUOTE]


And of course there's the "general consensus" on ambiguous terms,
sort of "half idioms". They're not quite cryptic enough to be called
idioms, but at the same time they're ambiguous and so their meaning
must be agreed upon by "general consensus". An example would be the
phrase "The state of you", which is a negative remark today in 2009...
however it could just as easily have been a positive remark if that's
what people had agreed upon. Who knows, in 2050 people might be saying
"The state of you" as a compliment.

If you take Shakespeare's "The quality of mercy is not strained",
well that could have loads of meanings, but the one true meaning was
defined by "general consensus" of the people who spoke the language at
that time. Sure you only have to look at the many different ways in
which people have interpreted old religious books.
 
G

Guest

Anti. The rule of three states that humans can cope with three levels of
nested parentheses at once.

so Lisp programmers aren't human. I'd had my suspicions...
 
T

Thad Smith

pete said:
What's your preference regarding the use of optional {braces}
around a single simple statement in a loop,
or after an if() or an (else)?

An early lesson in C was that I was bitten several times by changing

if (foo)
bar();

into

if (foo)
do_this_first();
bar();

or

if (foo)
bar();
and_this();

when I should have added brackets.

I then adopted a personal rule that braces follow an if or else UNLESS
the single statement followed in the same line:
if (foo) {
bar();
}

or

if (foo) bar();

This simple rule serves me well and prevents my previous blunder.

YMMV.
 

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