Search code examples
ctokentokenizec-stringsstrtok

Tokenizing a string and return it as an array


I'm attempting to tokenize a passed string, store the tokens in an array and return it. I'm running this on ubuntu. I'm stumped when it comes to this language apparently.

Sample input: coinflip 3

My code thought process reads as follows:

take: string
if string = null: return null
else:
while temp != null
   token[i++] = temp
   temp = get next token
return

Here's my current solution. The delimiter is whitespaces. C hasn't been my strong suit for a while.

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

//Clears the screen and prompts the user
void msg()
{
    static int init = 1;
    if(init)
    {
        printf("\e[1;1H\e[2J");
        init = 0;
    }
    printf("%s", "uab_sh > ");

}

//Reads in line
char *readIn(void)
{
    char param[101];
    fgets(param, 101, stdin);
    return param;
}

//parse string - still working out the kinks :)
char **parseString(char *cmd)
{
    char delim[] = " ";
    char* temp = strtok(cmd, delim);
    if (temp == " ")
    {
        return NULL;
    }
    else
    {
        int i = 0;
        char** tokens = malloc(3 * sizeof(char*));
        while (temp != NULL)
        {
            tokens[i++] = temp;
            temp = strtok(NULL, " ");
        }
        for (i = 0; i < 3; i++)
        {
            printf("%s\n", tokens[i]);
        }
        return tokens;
    }
}

//Command
int command(char ** cmd)
{
    int pid;
    if (cmd[0] != NULL)
    {
        pid = fork();
        if (pid == 0)
        {
            exit(0);
        }
        else if (pid < 0)
        {
            perror("Something went wrong...");
        }
    }
    else
        return 1;
}


int main()
{
    char *line;
    char **cmd;
    int stat = 0;
    while (1)
    {
        msg();
        line = readLine();
        cmd = parseString(line);
        stat = command(cmd);
        if (stat == 1)
        {
            break;
        }
    }
    return 0;
}

Current errors:

main.c: In function ‘readIn’:
main.c:24:9: warning: function returns address of local variable [-Wreturn-local-addr]
  return param;
         ^~~~~
main.c: In function ‘parseString’:
main.c:32:11: warning: comparison with string literal results in unspecified behavior [-Waddress]
  if (temp == " ")
           ^~
main.c: In function ‘command’:
main.c:59:9: warning: implicit declaration of function ‘fork’ [-Wimplicit-function-declaration]
   pid = fork();
         ^~~~
main.c: In function ‘main’:
main.c:82:10: warning: implicit declaration of function ‘readLine’; did you mean ‘readIn’? [-Wimplicit-function-declaration]
   line = readLine();
          ^~~~~~~~
          readIn
main.c:82:8: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
   line = readLine();
        ^
main.c: In function ‘command’:
main.c:71:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

Solution

  • Well, excluding the fact that this code is not capable of handling no more than 3 tokens, it has an another basic problem: It will return an illegal pointer to memory. temp and tokens are variables which are within the stack frame of the parseString() function. So when it's execution finishes, those variables will be gone. The ideal solution here is to allocate tokens in the heap.

    Here is my solution:

    char** parseString(char* cmd)
    {
        char delimiters[] = " ";
        char* temp = strtok(cmd, delimiters);
        //If temp is NULL then the string contains no tokens
        if (temp == NULL)
        {
            return NULL;
        }
        else
        {
            int i = 0;
            char** tokens = malloc(3*sizeof(char*));
            while (temp != NULL)
            {
                tokens[i++] = temp;
                temp = strtok(NULL, " ");
            }
            for (i = 0; i < 3; i++)
            {
                printf("%s\n", tokens[i]);
            }
            return tokens;
        }
    }