1

This C program splits the string "1 2 3 4 5 6 7 8 9 10" into tokens, stores these in buf, and prints the contents of buf.

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

/* Fills an array with pointers to the tokens of the given string.
 * string: A null-terminated char*
 * buf: A buffer to be filled with pointers to each token. 
 */
void get_tokens(char * string, char ** buf) {
    char tmp[100];
    strncpy(tmp, string, 100);
    char * tok = strtok(tmp, " \n");
    int i = 0;
    while (tok != NULL) {
        buf[i] = tok;
        tok = strtok(NULL, " \n");
        i++;
    }
}

int main() {
    char ** buf = malloc(10 * sizeof(char*));
    char * string = "1 2 3 4 5 6 7 8 9 10";
    get_tokens(string, buf);

    int i;
    for (i = 0; i < 10; i++) {
        printf("  %s\n", buf[i]);
    }
}

The output:

  1
  2
  3
  4
   s�c8
  �c8
  8

  9
  10

Why is my output being mangled?

7
  • 4
    The root cause is tmp being out of scope after returning from get_tokens. Commented Feb 22, 2016 at 23:04
  • char tmp[100]; is local variable. Address of that part invalid at out of scope. Commented Feb 22, 2016 at 23:05
  • But the pointers returned by strtok are not pointers to tmp, they are independent strings made with malloc Commented Feb 22, 2016 at 23:06
  • 4
    "they are independent strings made with malloc". Really? Which part of the code does that? char * tok = strtok(tmp, " \n"); buf[i] = tok;. tok points to a position within tmp. Commented Feb 22, 2016 at 23:07
  • 2
    I think I get it now, thank you. The reason the input string to strtok is mangled is that strtok just replaces the delimiter with \0 and returns a pointer to the start of each token within tmp. Commented Feb 22, 2016 at 23:09

1 Answer 1

1

The array tmp is a local array of the function with the automatic storage duration. It is destroyed after the function exit. So all pointers that point to elements of the array become invalid.

I can suggest the following solution

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

size_t get_tokens( char ** buf, size_t n, const char *string ) 
{
    char tmp[100];
    strncpy( tmp, string, 100 );
    tmp[99] = '\0';

    size_t i = 0;
    char * tok = strtok( tmp, " " );

    while ( i < n && tok != NULL ) 
    {
        buf[i] = malloc( strlen( tok ) + 1 );
        strcpy( buf[i++], tok );
        tok = strtok( NULL, " " );
    }

    return i;
}

int main( void ) 
{
    const size_t N = 10;

    char ** buf = malloc( N * sizeof( char * ) );
    char * string = "1 2 3 4 5 6 7 8 9 10";

    size_t n = get_tokens( buf, N, string );

    for ( size_t i = 0; i < n; i++ ) 
    {
        puts( buf[i] );
    }

    for ( size_t i = 0; i < n; i++ ) free( buf[i] );
    free( buf );

    return 0;
}

The program output is

1
2
3
4
5
6
7
8
9
10

As for your program then at least you should declare the array with storage specifier static.

For example

static char tmp[100];
^^^^^^
strncpy( tmp, string, 100 );
tmp[99] = '\0';
^^^^^^^^^^^^^^^
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.