Home > Software design >  Function to split a string and return every word in the string as an array of strings
Function to split a string and return every word in the string as an array of strings

Time:09-16

I am trying to create a function that will accept a string, and return an array of words in the string. Here is my attempt:

#include "main.h"

/**
 * str_split - Splits a string
 * @str: The string that will be splited
 * 
 * Return: On success, it returns the new array
 * of strings. On failure, it returns NULL
 */
char **str_split(char *str)
{   
    char *piece, **str_arr = NULL, *str_cpy;
    int number_of_words = 0, i;

    if (str == NULL)
    {
        return (NULL);
    }
    str_cpy = str;
    piece = strtok(str_cpy, " ");
    while (piece != NULL)
    {
        if ((*piece) == '\n')
        {
            piece = strtok(NULL, " ");
            continue;
        }
        number_of_words  ;
        piece = strtok(NULL, " ");
    }
    
    str_arr = (char **)malloc(sizeof(char *) * number_of_words);
    piece = strtok(str, " ");
    for (i = 0; piece != NULL; i  )
    {
        if ((*piece) == '\n')
        {
            piece = strtok(NULL, " ");
            continue;
        }
        str_arr[i] = (char *)malloc(sizeof(char) * (strlen(piece)   1));
        strcpy(str_arr[i], piece);
        piece = strtok(NULL, " ");
    }
    return (str_arr);
}

Once I compile my file, I should be getting:

Hello
World

But I am getting:

Hello

Why is this happening? I have tried to dynamically allocate memory for the new string array, by going through the copy of the original string and keeping track of the number of words. Is this happening because the space allocated for the array of strings is not enough?

CodePudding user response:

The code seems fine overall, with just some issues:

You tried to copy str, as strtok modifies it while parsing. This is the right approach. However, the following line is wrong:

str_cpy = str;

This is not a copy of strings, it is only copying the address of the string. You can use strdup function here.

Also, you need to return the number of words counted otherwise the caller will not know how many were parsed.

Finally, be careful when you define the string to be passed to this function. If you call it with:

char **arr = str_split ("Hello World", &nwords);

Or even with:

char *str = "Hello World";
char **arr = str_split (str, &nwords);

The program will crash as str here is read-only (see this).

Taking care of these, the program should work with:

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

/**
 * str_split - Splits a string
 * @str: The string that will be splited
 * 
 * Return: On success, it returns the new array
 * of strings. On failure, it returns NULL
 */
char **str_split(char *str, int *number_of_words)
{
    char *piece, **str_arr = NULL, *str_cpy = NULL;
    int i = 0;

    if (str == NULL)
    {
        return (NULL);
    }
    str_cpy = strdup (str);
    piece = strtok(str_cpy, " ");
    while (piece != NULL)
    {
        if ((*piece) == '\n')
        {
            piece = strtok(NULL, " ");
            continue;
        }
        (*number_of_words)  ;
        piece = strtok(NULL, " ");
    }

    str_arr = (char **)malloc(sizeof(char *) * (*number_of_words));
    piece = strtok(str, " ");
    for (i = 0; piece != NULL; i  )
    {
        if ((*piece) == '\n')
        {
            piece = strtok(NULL, " ");
            continue;
        }
        str_arr[i] = (char *)malloc(sizeof(char) * (strlen(piece)   1));
        strcpy(str_arr[i], piece);
        piece = strtok(NULL, " ");
    }

    if (str_cpy)
        free (str_cpy);

    return (str_arr);
}

int main ()
{
    int nwords = 0;
    char str[] = "Hello World";

    char **arr = str_split (str, &nwords);

    for (int i = 0; i < nwords; i  ) {

        printf ("word %d: %s\n", i, arr[i]);
    }

    // Needs to free allocated memory...
}

Testing:

$ gcc main.c && ./a.out 
word 0: Hello
word 1: World
  • Related