2

I was trying to create function, that takes as a string as an argument, divide it into strings, whitch where words separated by spaces, save it to an array and returns it via pointer. Despite static allocation of memory to array, whitch adress was took, program crashes, because of segmentation fault. What is wrong with this code?

void separate_words(char* full_text, char *matrix[], int* how_many)
{
char tmp;
int actual_letter,which_letter=0;
for(actual_letter=0;actual_letter<strlen(full_text);actual_letter++)
{
    if(full_text[actual_letter]!=32)
{


    full_text[actual_letter];
    matrix[*how_many][whitch_letter]=full_text[actual_letter];//here crashes
}
else
{  
    *how_many++;
    which_letter=0;
}
}

//*how_many
}

/*...*/
char words[20][20];
char text[20];
int number_of_words=0;
separate_words(text,words,&number_of_words);
Hassan
  • 75
  • 6

2 Answers2

1

This is a typical problem when you may utilize strtok

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

void separate_words(char* full_text, char *matrix[], int* how_many)
{
    char *pch;
    pch = strtok (full_text," \t\n");
    int i = 0;
    while (pch != NULL)
    {
        matrix[i++] = pch;
        pch = strtok (NULL, " \t\n");
    }
    *how_many = i;
}

int main ()
{
    char str[] = "apple   banana orange pineapple";
    char *matrix[100] = { NULL };
    int how_many = 0;
    separate_words(str, matrix, &how_many);

    int i;
    for( i = 0; i < how_many; i++ )
    {
        if( matrix[i] != NULL )
        {
            printf( "matrix[%d] = %s\n", i, matrix[i] );
        }
    }
    return 0;
}

Output:

matrix[0] = apple
matrix[1] = banana
matrix[2] = orange
matrix[3] = pineapple
artm
  • 17,291
  • 6
  • 38
  • 54
0

It is often useful to pass the delimiters to use with strtok as a parameter to the function to separate the string into tokens. You can also make use of a for loop with strtok to tidy up the code in certain circumstances.

Since the count of the number of pointers assigned to the resulting array can never be negative, a data type choice of size_t or unsigned can help the compiler point out if the variable is later used improperly.

Lastly, if using a static sized array of pointers to hold the pointers for each token, it is important to test the number of pointers assigned, to prevent writing beyond the end of your array. note: if you allocate pointers dynamically (with malloc or calloc), you can call realloc when your initial limit is reached, and subsequently, as needed.

Putting the various pieces together, an alternative would be:

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

#define MAXP 100

void separate_words (char *a[], char *s, char *delim, size_t *n);

int main (void)
{
    char str[] = "apple  banana orange pineapple";
    char *delim = " \t\n";
    char *matrix[MAXP] = { NULL };
    size_t how_many = 0;
    size_t i;

    separate_words (matrix, str, delim, &how_many);

    for (i = 0; i < how_many; i++)
        printf ("matrix[%zu] = %s\n", i, matrix[i]);

    return 0;
}

/* separate 's' into tokens based on delimiters provided in 'delim'
 * with pointers to each token saved in 'a' with 'n' updated to hold
 * the number of pointers contained in 'a'.
 */ 
void separate_words (char *a[], char *s, char *delim, size_t *n)
{
    *n = 0;
    char *p = strtok (s, delim);
    for (; p; p = strtok (NULL, delim)) {
        a[(*n)++] = p;
        if (*n == MAXP) {
            fprintf (stderr, "warning: pointer limit reached.\n");
            return;
        }
    }
}

Output

$ ./bin/strtok_static
matrix[0] = apple
matrix[1] = banana
matrix[2] = orange
matrix[3] = pineapple

Making Use of a Return

Additionally, you can make use of the function return to return the number of tokens in the string. This eliminates the need to pass a pointer variable as a parameter to the function:

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

#define MAXP 100

size_t separate_words (char *a[], char *s, char *delim);

int main (void)
{
    char str[] = "apple  banana orange pineapple";
    char *delim = " \t\n";
    char *matrix[MAXP] = { NULL };
    size_t how_many = 0;
    size_t i;

    how_many = separate_words (matrix, str, delim);

    for (i = 0; i < how_many; i++)
        printf ("matrix[%zu] = %s\n", i, matrix[i]);

    return 0;
}

/* separate 's' into tokens based on delimiters provided in 'delim'
 * with pointers to each token saved in 'a'. The number of tokens is
 * returned.
 */ 
size_t separate_words (char *a[], char *s, char *delim)
{
    size_t n = 0;
    char *p = strtok (s, delim);
    for (; p; p = strtok (NULL, delim)) {
        a[n++] = p;
        if (n == MAXP) {
            fprintf (stderr, "warning: pointer limit reached.\n");
            break;
        }
    }
    return n;
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85