How to Return an array of strings in C (char**)

V

vignesh4u

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

char** split(char str[],int*c) {
int start=0;
int end =0 ;
char** temp=NULL;
char** ptr;
int count=0;
int length = strlen(str);
//first counting the number of spaces
// to know the number of elements in the array
while (str) {
if (*str==' ') count++;
}
printf("count value is %d \n",count);
// I am doubt ful about the malloc too
ptr = (char**) malloc(sizeof(char)*(count+1));
*c = count+1;

while(end<length) {
ptr = str + start;
if (str[end]!=' ' || length) {
end++;
}
if (str[end]!='\0') {// replacing spaces with \0
str[end]='\0';
}
if (!temp) temp= ptr;
ptr++;
}
return temp;
}

Thanks
 
C

CBFalconer

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return
an array of strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a
segmentation fault. I would really appreciate if some one
could give me an answer on this issue:

Search the google archives for my posting of "toksplic.c".
 
O

osmium

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

char** split(char str[],int*c) {
int start=0;
int end =0 ;
char** temp=NULL;
char** ptr;
int count=0;
int length = strlen(str);
//first counting the number of spaces
// to know the number of elements in the array
while (str) {
if (*str==' ') count++;
}
printf("count value is %d \n",count);
// I am doubt ful about the malloc too
ptr = (char**) malloc(sizeof(char)*(count+1));
*c = count+1;

while(end<length) {
ptr = str + start;
if (str[end]!=' ' || length) {
end++;
}
if (str[end]!='\0') {// replacing spaces with \0
str[end]='\0';
}
if (!temp) temp= ptr;
ptr++;
}
return temp;
}

I am not a fan of coding where the malloc and free are in different
functions unless there is a good reason to do so. So I would not return
anything (return void) from split: have the caller allocate the space, tell
split where the space is, modify it in place and have the caller be
responsible for doing the free. If this is a learning exercise, you will
have to make the array you are trying to return static. I hope the
information you need to continue is in the link to the FAQ, if not post
another question.

http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=aryptr
 
M

Malcolm McLean

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

char** split(char str[],int*c) {
int start=0;
int end =0 ;
char** temp=NULL;
char** ptr;
int count=0;
int length = strlen(str);
This must be where you crashed, if you cut and pasted this code. The input
must be null or not set up correctly.
//first counting the number of spaces
// to know the number of elements in the array
while (str) {
if (*str==' ') count++;
}

The reason is that you fail to increment str. Unless input is an empty
string, this will run forever. Since the program didn't hang, probably the
crash was above.
printf("count value is %d \n",count);
// I am doubt ful about the malloc too
ptr = (char**) malloc(sizeof(char)*(count+1));
you want (count + 1) * sizeof(char *).
It is an array of pointers, not of chars.
*c = count+1;

while(end<length) { *ptr = str + start.
ptr = str + start;
What is length doing in this condition ?
if (str[end]!=' ' || length) {
end++;
}
this should surely be an else if.
if (str[end]!='\0') {// replacing spaces with \0
str[end]='\0';

Now you need to set *ptr to str + start. You also need to update start, and
increment end.
This confused me. Much better to set temp before entering the loop.
if (!temp) temp= ptr;
ptr++;
}
return temp;
}

Thanks

Its nearly there. Generally the way to debug rotuintes like this is to slip
in diagnostic printfs. For instance you could have printfed your input
printf("***%s***\n", str) to see it was valid. The asterisks are there to
pick up any funny spaces. The you could have printed "here" before entering
the main loop to see if you actually got there, then str + start to see
where you go to in the string on each pass.
 
A

Army1987

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

[snip]

while (str) {
if (*str==' ') count++;
}
You meant *str++, didn't you?
ptr = (char**) malloc(sizeof(char)*(count+1));
Unless you have 256 bytes of memory (or some system with CHAR_BIT > 8) a
pointer to char will be definitely larger than a char.
if (!temp) temp= ptr;
When did you exactly use temp after initializing it to NULL?
 
F

Flash Gordon

Army1987 wrote, On 25/03/07 22:18:
<[email protected]> ha scritto nel messaggio

Unless you have 256 bytes of memory (or some system with CHAR_BIT > 8) a
pointer to char will be definitely larger than a char.

Which is why we generally recommend using the form
ptr = malloc(N * sizeof *ptr);
Note the lack of a cast, since casts can hide the serious error of not
including stdlib.h, and using sizeof *ptr so you don't have to worry
about getting the type right.
 
A

Army1987

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

char** split(char str[],int*c) { [snip]
}

That's way too long for my standards, I'd use several functions.

/* BEGIN foo.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count_char(char c, char *str);
int search_char(char c, char *str);

char **split(char *str, int *c)
{
int i, wlen;
int num = count_char(' ', str) + 1;
char **res = malloc(num * sizeof(char *));
*c = num;
if (res == NULL) {
perror("Unable to allocate memory");
return NULL;
}
for (i=0; i<num; i++) {
wlen = (i<num-1) ? search_char(' ', str) : strlen(str);
res = malloc(wlen + 1);
if (res == NULL) {
perror("Unable to allocate memory");
return NULL;
}
strncpy(res, str, wlen);
res[wlen] = '\0';
str += wlen + 1;
}
return res;
}

int count_char(char c, char *str)
{
int i, res = 0;
for (i=0; str != '\0'; i++)
if (str == c) res++;
return res;
}

int search_char(char c, char *str)
{
int i;
for (i=0; str != '\0'; i++)
if (str == c) return i;
return -1; /* c not found in str */
}

int main(void)
{
int i, n;
char **a = split("This is a test", &n);
printf("%d\n{", n);
for (i=0; i<n; i++)
printf("\"%s\",", a);
puts("\b}");
return 0;
}

/* END foo.c */

army1987@army1987-laptop:~$ gcc foo.c -ansi -Wall -pedantic
army1987@army1987-laptop:~$ ./a.out
4
{"This","is","a","test"}
army1987@army1987-laptop:~$

(Anyway, in the if (res == NULL) within the for loop in function split
I'd better free res[0], res[1], ... res[i-1] and res, and assign NULL to
res.)
 
A

Army1987

Army1987 said:
(Anyway, in the if (res == NULL) within the for loop in function split
I'd better free res[0], res[1], ... res[i-1] and res, and assign NULL to
res.)

The last point of which is useless anyway, as res is local to split().
 
A

Army1987

CBFalconer said:
(e-mail address removed) wrote:
Search the google archives for my posting of "toksplic.c".

The only one it finds is this one I'm replying to.
 
B

Barry Schwarz

I am trying to implement the Split function in C ie.
if i have a string: char* S="This is a test";
and if i try to split based on space ' ' it should return an array of
strings like:

If your code in the calling function really uses a char* that points
to a literal string, change it to use an array. Your function tries
to modify the string that is passed in and you are not allowed to
modify a string literal.
{"This","is","a","test"} .

I tried to implement it as given below but am getting a segmentation
fault. I would really appreciate if some one could give me an answer
on this issue:

You really should sit down with a piece of paper and desk check your
code by pretending to be the computer and manually performing each
step.
char** split(char str[],int*c) {

Unless you want to commit the exceptions to memory, you should avoid
any user defined function or object name beginning with str.
int start=0;
int end =0 ;
char** temp=NULL;
char** ptr;
int count=0;
int length = strlen(str);
//first counting the number of spaces
// to know the number of elements in the array
while (str) {
if (*str==' ') count++;

This will count consecutive spaces as if each bounded a word.
}
printf("count value is %d \n",count);
// I am doubt ful about the malloc too
ptr = (char**) malloc(sizeof(char)*(count+1));

Wrong on multiple counts:

Don't cast the return from malloc. It never helps and can cause
the compiler to suppress a diagnostic you would really want to see.
Did you #include stdlib.h. If not this invokes undefined behavior.

ptr is a char**. Therefore, whatever it points to is a char*. On
most systems, sizeof (char*) is a multiple of 4. However, you are
using sizeof (char) which is guaranteed to be 1. You are not
allocating enough space by at least 75%. Rather than go through the
mental gymnastics of keeping the types straight in your head, let the
compiler do it for you with
ptr = malloc((count+1) * sizeof (*ptr));
This will work for any type of ptr except void*.

You should always check malloc for success.
*c = count+1;

All of your count+1 terms seem wrong.
while(end<length) {
ptr = str + start;

Didn't your compiler give you a diagnostic here? ptr is a char**. str
is char*. The expression str+start also has type char*. There is no
implicit conversion between the two.

What happened to the memory you just allocated? Who points to it? Do
str or start ever change values?

What you really want is
start = end;
here.
if (str[end]!=' ' || length) {

If length is positive, this always evaluates to true. Make sure you
understand why. You probably meant
if (str[end] != ' ' && end < length) {
Make sure you understand why && and not ||.
end++;
}
if (str[end]!='\0') {// replacing spaces with \0
str[end]='\0';

You need to increment end so the next iteration through the loop does
not start on the '\0' you just inserted.
}
if (!temp) temp= ptr;

This should be done unconditionally right after the malloc.

What you really want here is
*ptr++ = &str[start];
Now figure out why.
}
return temp;
}


Remove 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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top