Pointer confusion with passing string array -- Segmentation fault

  • Thread starter Goh, Yong Kwang
  • Start date
G

Goh, Yong Kwang

I'm trying to create a function that given a string, tokenize it and
put into a dynamically-sized array of char* which is in turn also
dynamically allocated based on the string token length.

I call the function using this code fragement in my main function:
---
char** arg_array;
arg_count = create_arg_array(command, argument, arg_array);

for(count = 0; count < arg_count; count++)
printf("arg_array[%d]: %s\n", count, arg_array[count]);
---
And it always crashes with a segmentation fault when going into the
for loop to print out the array of strings. Why does it crash when
I've already called malloc and realloc (inside create_arg_array()
function) to reserve some memory for the string array?

The create_arg_array is given below.
What's wrong with this function?
---
size_t create_arg_array(char* file, char* arg, char** array){
size_t count;
char* argument;

count = 1;
/* 1 for the filename and 1 for the terminating NULL ptr. */
array = (char**) malloc(count * sizeof(char*));

array[0] = (char*) malloc(strlen(file) + 1);
strcpy((*array)[0], file);

if(arg != NULL){
argument = strtok(arg, " \n");
if(argument != NULL){
array = (char**) realloc(array, (count + 1) * sizeof(char*));
array[count] = (char*) malloc(strlen(argument) + 1);
strcpy(array[count], argument);
count++;
}
while((argument = strtok(NULL, " \n")) != NULL){
array = (char**) realloc(array, (count + 1) * sizeof(char*));
array[count] = (char*) malloc(strlen(argument) + 1);
strcpy(array[count], argument);
count++;
}
}
++count;
array = (char**) realloc(array, (count * sizeof(char*)));
array[count-1] = NULL;

return count-1; /* Minus 1 for the ending NULL */
}
---
I thought the address returned by realloc and malloc is lost when I
return to main function and I've also tried changing the function to
accept a pointer to the array of string (char***) but it doesn't help.

Any advice appreciated.
Thank you.

Goh, Yong Kwang
Singapore
(e-mail address removed)
 
J

Jack Klein

I'm trying to create a function that given a string, tokenize it and
put into a dynamically-sized array of char* which is in turn also
dynamically allocated based on the string token length.

I call the function using this code fragement in my main function:
---
char** arg_array;
arg_count = create_arg_array(command, argument, arg_array);

for(count = 0; count < arg_count; count++)
printf("arg_array[%d]: %s\n", count, arg_array[count]);
---
And it always crashes with a segmentation fault when going into the
for loop to print out the array of strings. Why does it crash when
I've already called malloc and realloc (inside create_arg_array()
function) to reserve some memory for the string array?

The create_arg_array is given below.
What's wrong with this function?

The main answer to your primary question is covered in this
newsgroup's FAQ, specifically:

http://www.eskimo.com/~scs/C-faq/q4.8.html
---
size_t create_arg_array(char* file, char* arg, char** array){
size_t count;
char* argument;

count = 1;
/* 1 for the filename and 1 for the terminating NULL ptr. */
array = (char**) malloc(count * sizeof(char*));

array[0] = (char*) malloc(strlen(file) + 1);

Casting the pointer returned by malloc() is unnecessary in C and
considered bad form by most experienced C programmers. At best it is
useless, a redundant cast. At worst it silences an important compiler
diagnostic if you neglected to include <stdlib.h> to have a proper
prototype in scope.
 
A

Al Bowers

I'm trying to create a function that given a string, tokenize it and
put into a dynamically-sized array of char* which is in turn also
dynamically allocated based on the string token length.

..........snip...........

A char *** parameter would be correct. But you need to correct
the logic errors. Another approach would be to define a
data type that will contain all the data that you need.

like:
typedef struct DATA
{
char *fdata /* contents of the entire file */
char **pdata /* An array of pointers to the file data */
size_t count /* A count of the array of pointers */
} DATA;

Then you can write functions to manipulate this datatype.

Ex.

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

#define FNAME "test.txt" /* File name goes here */

/*test.txt contents:

Bill:JOHN:HARRY:AL:WILLIAM:
FRANK:LARRY:RON

*/

typedef struct DATA
{
char *fstring;
char **pstring;
size_t count;
} DATA;

DATA getDATA(const char *fname, const char *delim);
void freeDATA(DATA *p);
void printDATA(DATA *p);

int main(void)
{
DATA data = getDATA(FNAME, ":\n");

printDATA(&data);
freeDATA(&data);
return 0;
}

DATA getDATA(const char *fname, const char *delim)
{
FILE *fp;
DATA p = {NULL};
char *tmp, buf[64], **tmpp;
size_t sz;

if((fp = fopen(fname,"r")) == NULL) return p;
for(sz = 0 ; (fgets(buf,sizeof buf, fp)); )
{
tmp = realloc(p.fstring, (sz += strlen(buf))+1);
if(tmp == NULL)
{
freeDATA(&p);
break;
}
if(!p.fstring) *tmp = '\0';
p.fstring = tmp;
strcat(p.fstring,buf);
}
fclose(fp);
if(p.fstring)
{
for(tmp = strtok(p.fstring,delim) ; tmp;
tmp = strtok(NULL,delim))
{
tmpp = realloc(p.pstring, (p.count+1)*sizeof(*tmpp));
if(tmpp == NULL)
{
freeDATA(&p);
break;
}
tmpp[p.count++] = tmp;
p.pstring = tmpp;
}
}
return p;
}

void freeDATA(DATA *p)
{
free(p->fstring);
free(p->pstring);
p->fstring = NULL;
p->pstring = NULL;
p->count = 0;
return;
}

void printDATA(DATA *p)
{
size_t i;

for(i = 0; i < p->count; i++)
printf("%u. %s\n",i,p->pstring);
return;
}
 
B

Barry Schwarz

I'm trying to create a function that given a string, tokenize it and
put into a dynamically-sized array of char* which is in turn also
dynamically allocated based on the string token length.

I call the function using this code fragement in my main function:

After you return from create_arg_array, arg_array has not been updated
with the address that was malloc'ed in the function. C always passes
by value.
for(count = 0; count < arg_count; count++)
printf("arg_array[%d]: %s\n", count, arg_array[count]);
---
And it always crashes with a segmentation fault when going into the
for loop to print out the array of strings. Why does it crash when
I've already called malloc and realloc (inside create_arg_array()
function) to reserve some memory for the string array?

The create_arg_array is given below.
What's wrong with this function?
---
size_t create_arg_array(char* file, char* arg, char** array){
size_t count;
char* argument;

count = 1;
/* 1 for the filename and 1 for the terminating NULL ptr. */
array = (char**) malloc(count * sizeof(char*));

Don't cast the return from malloc. It cannot help and can hurt.
array[0] = (char*) malloc(strlen(file) + 1);
strcpy((*array)[0], file);

if(arg != NULL){
argument = strtok(arg, " \n");
if(argument != NULL){
array = (char**) realloc(array, (count + 1) * sizeof(char*));
array[count] = (char*) malloc(strlen(argument) + 1);
strcpy(array[count], argument);
count++;
}
while((argument = strtok(NULL, " \n")) != NULL){
array = (char**) realloc(array, (count + 1) * sizeof(char*));
array[count] = (char*) malloc(strlen(argument) + 1);
strcpy(array[count], argument);
count++;
}
}
++count;
array = (char**) realloc(array, (count * sizeof(char*)));
array[count-1] = NULL;

return count-1; /* Minus 1 for the ending NULL */
}

Yes it does if you use it properly. Your calling statement needs to
specify &arg_array. Inside the function, every place you currently
use array you need to use (*array). This will cause the function to
automatically update arg_array in the calling function.
Any advice appreciated.
Thank you.

Goh, Yong Kwang
Singapore
(e-mail address removed)



<<Remove the del for email>>
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top