realloc'ing an array of strings

J

John

I'm trying (struggling) to use realloc to grow a list of strings. The
number of strings is not known (this is a subset of an assignment to write a
recursive ls program... my BS was in EE, so I'm trying to catch up!).

I'm working on the following program to try to figure this out. Now, I'm at
the point where I'm filling up plines with (I belive) a list of pointers,
each of which is pointing to a string ("foo 1", "foo 2", and so forth). The
hard-coded 10 in the for loop, btw, is only for this exploration of ideas...
It will not be in the final code (indeed, none of the hard-code numbers will
be).

My two sticking points are:
1) I'm supposed to "free" stuff that I've malloc'd. If I do free(p),
then the pointers that I've stuffed into plines no longer point to anything,
and the printout loop at the end of main confirms that when free(p) is in
place.

2) I'm malloc'ing the correct size of each string, but how can I
dynamically grow plines as needed? The realloc man page tells me that I can
only realloc a thing that got it's address from a prior malloc... but where
can I malloc plines? It reeks of a chicken/egg situation at 12:30am.

Any insight or pointers [groan] are certainly appreciated.


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

char *plines[30];

int main(void){
char buf[1024];

int i;

for( i=0; i<10; i++ ){
char temp[1024];
sprintf(temp,"foo %d",i);

char *p = malloc( strlen(temp) + 1 );
strcpy(p,temp);
plines=p;
}

for( i=0; i<10; i++ )
printf(">>> %s \n",plines);

}
 
E

Emmanuel Delahaye

John said:
I'm trying (struggling) to use realloc to grow a list of strings. The
number of strings is not known (this is a subset of an assignment to
write a recursive ls program... my BS was in EE, so I'm trying to catch
up!).

I'm working on the following program to try to figure this out. Now,
I'm at the point where I'm filling up plines with (I belive) a list of
pointers, each of which is pointing to a string ("foo 1", "foo 2", and
so forth). The hard-coded 10 in the for loop, btw, is only for this
exploration of ideas... It will not be in the final code (indeed, none
of the hard-code numbers will be).

Ok. Starting with fixed size is a good approach. Better to process the points
one by one.
My two sticking points are:
1) I'm supposed to "free" stuff that I've malloc'd. If I do
free(p),
then the pointers that I've stuffed into plines no longer point to
anything, and the printout loop at the end of main confirms that when
free(p) is in place.

If you free before use, you cause an undefined behaviour. See my code below.
2) I'm malloc'ing the correct size of each string, but how can I
dynamically grow plines as needed?

Should be a flexible array of pointers to char. The type is char * * (aka
char **)

/* empty array */
{
char **pp = NULL;
}
The realloc man page tells me that I
can only realloc a thing that got it's address from a prior malloc...
but where can I malloc plines? It reeks of a chicken/egg situation at
12:30am.

It also said that realloc() with NULL acts like malloc().

/* grow to 3 pointers : (FAQ) */
{
char **pp = NULL;
...
{
void *p_tmp = realloc (pp, 3 * sizeof *pp);
if (p_tmp != NULL)
{
pp = p_tmp;
}
}
}

Note : the 3 pointers are not initialized.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *plines[30];

int main(void){
char buf[1024];

int i;

for( i=0; i<10; i++ ){
char temp[1024];
sprintf(temp,"foo %d",i);

char *p = malloc( strlen(temp) + 1 );
strcpy(p,temp);
plines=p;
}

for( i=0; i<10; i++ )
printf(">>> %s \n",plines);

}


Not bad. Here is your code revisited. HTH. Feel free to ask for details.

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

int main (void)
{
int i;

char *plines[30];

for (i = 0; i < 10; i++)
{
char temp[8]; /* try 4 */

int n = sprintf (temp, "foo %d", i);

/* design checker (works in most cases) */
assert (n < sizeof temp - 1);

{
char *p = malloc (strlen (temp) + 1);

if (p != NULL)
{
strcpy (p, temp);
}
plines = p;
}
}

for (i = 0; i < 10; i++)
{
printf ("[%p] -> '%s'\n", (void *) plines, plines);
}

/* free the allocated arrays of char */
for (i = 0; i < 10; i++)
{
free (plines), plines = NULL;
}

/* just a checker... */
for (i = 0; i < 10; i++)
{
printf ("[%p]\n", (void *) plines);
}

/* -ed- C90 compatibility */
return 0;
}
 
P

Prawit Chaivong

John said:
I'm trying (struggling) to use realloc to grow a list of strings. The
number of strings is not known (this is a subset of an assignment to write a
recursive ls program... my BS was in EE, so I'm trying to catch up!).

I'm working on the following program to try to figure this out. Now, I'm at
the point where I'm filling up plines with (I belive) a list of pointers,
each of which is pointing to a string ("foo 1", "foo 2", and so forth). The
hard-coded 10 in the for loop, btw, is only for this exploration of ideas...
It will not be in the final code (indeed, none of the hard-code numbers will
be).

My two sticking points are:
1) I'm supposed to "free" stuff that I've malloc'd. If I do free(p),
then the pointers that I've stuffed into plines no longer point to anything,
and the printout loop at the end of main confirms that when free(p) is in
place.

I wouldn't free(p), But I would free(plines[whatever]) instead.
2) I'm malloc'ing the correct size of each string, but how can I
dynamically grow plines as needed? The realloc man page tells me that I can
only realloc a thing that got it's address from a prior malloc... but where
can I malloc plines? It reeks of a chicken/egg situation at 12:30am.

char **plines = NULL;
int num_plines = 0;

int main(void){
char buf[1024];
int len;

while ( your_condition )
{
if(!plines)
plines = malloc (sizeof(char*) * ++num_plines );
else
plines = realloc( plines, sizeof(char*) * ++num_plines );

assert(plines);

sprintf(buf,"foo%d",num_plines); // It will start from foo1,if you want
// to start from zero, change it.
len = strlen(buf) + 1;
char *p = malloc(len);
memcpy(p,buf,len);
plines[num_plines-1] = p;
}

....
....
....
} // main


Any insight or pointers [groan] are certainly appreciated.


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

char *plines[30];

int main(void){
char buf[1024];

int i;

for( i=0; i<10; i++ ){
char temp[1024];
sprintf(temp,"foo %d",i);

char *p = malloc( strlen(temp) + 1 );
strcpy(p,temp);
plines=p;
}

for( i=0; i<10; i++ )
printf(">>> %s \n",plines);

}
 
A

Al Bowers

John said:
I'm trying (struggling) to use realloc to grow a list of strings. The
number of strings is not known (this is a subset of an assignment to write a
recursive ls program... my BS was in EE, so I'm trying to catch up!).

I'm working on the following program to try to figure this out. Now, I'm at
the point where I'm filling up plines with (I belive) a list of pointers,
each of which is pointing to a string ("foo 1", "foo 2", and so forth). The
hard-coded 10 in the for loop, btw, is only for this exploration of ideas...
It will not be in the final code (indeed, none of the hard-code numbers will
be).

My two sticking points are:
1) I'm supposed to "free" stuff that I've malloc'd. If I do free(p),
then the pointers that I've stuffed into plines no longer point to anything,
and the printout loop at the end of main confirms that when free(p) is in
place.

The simple solution would free the allocations when you are finished
with them. So, change the printf loop to:

for( i=0; i<10; i++ )
{
printf(">>> %s \n",plines);
free(plines);
}
2) I'm malloc'ing the correct size of each string, but how can I
dynamically grow plines as needed? The realloc man page tells me that I can
only realloc a thing that got it's address from a prior malloc... but where
can I malloc plines? It reeks of a chicken/egg situation at 12:30am.

Instead of using char *plines[30], which fixes the max number of
strings you can allocate to 30, use char **. You can make a struct
that has a char ** member that points to the array and have another
member that keeps the count of the number of elements(strings)
allocated. You can write functions that manipulate this struct;
functions such as AddString, PrintStr, FreeStr. See the example.
char *plines[30];

int main(void){
char buf[1024];

int i;

for( i=0; i<10; i++ ){
char temp[1024];
sprintf(temp,"foo %d",i);

char *p = malloc( strlen(temp) + 1 );
strcpy(p,temp);
plines=p;
}

for( i=0; i<10; i++ )
printf(">>> %s \n",plines);


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

struct sarray
{
char **line;
unsigned count;
};

int AddString(struct sarray *p, const char *s);
void FreeString(struct sarray *p);
void PrintString(struct sarray *p);

int main(void)
{
char buf[1024];
struct sarray mytest = {NULL}; /* Empty array */
int i;

for( i=0; i<10; i++ )
{
sprintf(buf,"foo %d",i);
AddString(&mytest, buf);
}
PrintString(&mytest);
FreeString(&mytest);
return 0;
}

int AddString(struct sarray *p, const char *s)
{
char **tmp;

if((tmp = realloc(p->line,
(p->count+1)*(sizeof *tmp))) == NULL)
return 0;
if(tmp)
{
p->line = tmp;
if((p->line[p->count] = malloc(strlen(s)+1)) == NULL)
return 0;
strcpy(p->line[p->count++],s);
}
return 1;
}

void FreeString(struct sarray *p)
{
unsigned i;

for(i = 0; i < p->count;i++)
free(p->line);
free(p->line);
p->line = NULL;
p->count = 0;
return;
}

void PrintString(struct sarray *p)
{
unsigned i;

for(i = 0;i < p->count;i++)
printf("%6u: %s\n",i+1,p->line);
return;
}
 
J

John

Ahh... All the responses to my op were extremely helpful, and I've got
something going now. I think that one of the main sticking points for me
was the idea data being stored in an unnamed chunk of memory (i.e., no
variable name). But i suppose that the name isn't really necessary, as long
as the memory is set aside for it and the data can be access.
 

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,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top