WL said:
Hey, all. I'm creating an array of strings (char **argv style) on
the fly, and using realloc to create string pointers, and malloc
for the strings itself (if that makes any sense).
I'm using the construct
ptr = realloc(ptr, size);
*ptr = malloc(string_length);
strncpy(ptr, src, string_length);
to call realloc() multiple times. This should be ok, right?
No, not at all right. In the first line there's a problem
if realloc() fails and returns NULL. Guess what? You've stored
the NULL value into `ptr', and you can no longer find the memory
`ptr' used to point to. This is called a "potential memory leak."
Then in the second line, you always store the new pointer
in the very first slot of the reallocated array, clobbering
whatever lived there before. That is, the second time you do
this you lose track of the string you stored the first time,
and the third time you lose the string stored the second time,
and so on. This is called a "big-time memory leak."
The second and/or third lines may also be in error in the
use of `string_length', whose initialization you haven't shown.
If `string_length' is the strlen() of some string, then the
copied string winds up lacking a terminating '\0' character --
that is, it's no longer a "string" as defined by C, and you
dare not attempt to use it as such.
Finally, there's no error-checking. "Omitted for brevity,"
I'm sure, but considering the rate at which errors are being
committed in this code, brevity here seems to be the soul of
something other than wit.
Anyways, the problem I'm seeing is in (no error checking)
char **template, **temp_ptr;
/* initial template malloc */
template = realloc(template, 2 * sizeof **template);
First, `template' has never been initialized to point to
anything in particular. If it's at file scope it's implicitly
initialized to NULL, and that's all right. But if it's local
to a function, it "points to garbage" and you are in for big
trouble.
Second, see above for a reason to avoid `p = realloc(p,...)'.
Third, that size calculation is wrong. R-O-N-G, wrong.
Hint: the value is two. Not "two pointers' worth," but two.
You want something like `2 * sizeof *template' instead.
Fourth, "anyways" is not an English word.
temp_ptr = template + 1;
*temp_ptr = malloc(5);
Since you only allocated two bytes' worth of memory above
(if you even got that far, given that `template' was uninitialized
when you called realloc() on it), it's quite likely that `temp_ptr'
now points outside the allocated area. When you try to store the
result of malloc() there, who knows what you might be stepping
upon?
strncpy(*temp_ptr, "abcd", 5);
Not an error, exactly, but this habit you've fallen into of
using strncpy() instead of strcpy() is not a good one. The habit
of using magic numbers like `5' and `2' is perhaps even worse.
printf("%s\n%s\n%d %d\n", *template, *(template+1), template, temp_ptr);
You seem unconcerned about the lake of brimstone that awaits
persistent sinners, because here comes another one. Another
three, actually.
First, what's stored in `*template'? Well, you never stored
anything there, did you? So what reason have you to believe it
points to the start of a valid string that you can use with the
"%s" specifier? None at all, that's right ...
Second and third, what makes you think you can print a pointer
value with the "%d" specifier? "%d" is for integers, not for
pointers. If it happens to do something halfway sensible on your
particular system, that's pure dumb luck.
template = realloc(template, 3 * sizeof **template);
Same errors in the previous realloc(). You're up to a whole
three bytes now -- and note that if realloc() decided to copy the
old stuff to a new location, it has not obligingly copied the
things you stored outside the bounds of the old area ...
temp_ptr = template + 2;
*temp_ptr = malloc(5);
strncpy(*temp_ptr, "wxyz", 5);
printf("%s\n%s\n%s\n%d %d\n", *template, *(template+1), *(template+2), template, temp_ptr);
All the same errors, all over again.
and the associated output is
Considering all the problems, it's a bit surprising that
you got any output at all.
1234
abcd
536952928 536952936
@
abcd
wxyz
536952928 536952944
After some futzing, it seems the data in *template gets blown away
after the last malloc(). I've looked this over all morning, but I
don't see where I'm going wrong.
If you can't see what's wrong with what you've written, you
are in serious need of a C course. Pointers are obviously a
mystery to you, and memory management seems to be a dark art.
Read Sections 4 through 7 -- ALL of it! -- in the comp.lang.c
Frequently Asked Questions (FAQ) list
http://www.eskimo.com/~scs/C-faq/faq.html
.... and it would do you no lasting harm to read Section 8 as
well. Until you improve your understanding, you are just
wasting your time writing stuff that looks like code but lacks
sensible content.