1

This piece of code was working fine, until I modified it.

int main(int argc, char** argv)
{
    char command[1024];
    gets(command);
    char *delim = " \t\f";
    char **tokens;
    int i=0;
    /* Extracting tokens from command string */
    for(tokens[i] = strtok(command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))
    {
       i++;
    }
    return 0;
}

And here's the code that crashed with a Segmentation Fault on line for(tokens[i] = strtok(command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))

Code:

void commandProcess(char command[])
{
    char *delim = " \t\f";
    char **tokens;
    int i=0;
    /* Extracting tokens from command string */
    for(tokens[i] = strtok(command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))
    {
       i++;
    }
}

int main(int argc, char** argv)
{
    char command[1024];
    gets(command);
    process(command);
    return 0;
}

I know that char command[] decays to a pointer link, and also that strtok() modifies its first parameter and in my case it might be an undefined behaviour. link

So, could anybody please provide me some other way around, so that I can work out with the same function signature and still avoid the problem?

This seems a trivial problem, but I cannot make through it. :\ I even tried this,

void commandProcess(char command1[])
{
    char command[1024];
    int length = strlen(command1);
    strncat(command, command1, length);
    command[length] = '\0';

    char *delim = " \t\f";
    char **tokens;
    int i=0;

    /* Extracting tokens from command string */
    for(tokens[i] = strtok(temp_command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))
    {
       i++;
    }

but then again crashes on the line

for(tokens[i] = strtok(temp_command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))

I think that delim & tokens are not the culprits because the program without commandProcess() worked fine with them.

18
  • 1
    char command[1024]; in a function is a good recipe for stack overflow. Commented Jun 30, 2017 at 16:46
  • 3
    First of all never ever use gets. It's a dangerous function that has been removed from the latest C standard. Commented Jun 30, 2017 at 16:46
  • 1
    Secondly, the variable tokens is a pointer, but where does it point? Commented Jun 30, 2017 at 16:47
  • 2
    Fourthly, don't add language tags that aren't relevant to the language you program in. C and C++ are two very different languages. If you program in C use only that tag. Commented Jun 30, 2017 at 16:48
  • 2
    You didn't set tokens to a valid pointer in memory before attempting tokens[i]. If you declare char **tokens that just declares space for a pointer. You need to set it to a valid address before you can use it. Commented Jun 30, 2017 at 16:48

2 Answers 2

1

You write to tokens[i], but tokens is never initialized. Dereferencing an uninitialized pointer invokes undefined behavior.

This means the behavior of the code is unpredictable. It may crash, it may show strange results, or it may appear to work correctly. Also, making a seemingly unrelated code change can change how undefined behavior manifests. This is what happened in your case.

To fix this, you need to allocate space to tokens. In this case, the simplest thing to do is make a fixed size array of pointers:

char *tokens[1024];

You can also malloc the memory so you don't have a large array on the stack:

char **tokens = malloc(sizeof(char *) * 1024);

Since command is of length 1024, the number of tokens shouldn't be any larger.

Sign up to request clarification or add additional context in comments.

Comments

1

As other comments and answers have pointed out, you need to allocate space for the token pointers you collect.

Here's a fixed version, which also uses fgets() instead of the obsolete and dangerous gets(). Normally, unfortunately, fgets is a bit of a nuisance, because it leaves the trailing \n in the buffer. Here, however, that's trivial to account for, as we can simply add '\n' to the delim variable telling strtok what to split on.

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

#define MAXTOKS 100

void commandProcess(char command[])
{
    char *delim = " \t\f\r\n";
    char *tokens[MAXTOKS+1];
    int i=0;
    /* Extracting tokens from command string */
    for(tokens[i] = strtok(command, delim); tokens[i] != NULL; tokens[i] = strtok(NULL, delim))
    {
       i++;
       if(i > MAXTOKS)
       {
          fprintf(stderr, "too many tokens\n");
          exit(1);   
       }
    }
    for(i = 0; tokens[i] != NULL; i++) printf("%d: \"%s\"\n", i, tokens[i]);
}

int main(int argc, char** argv)
{
    char command[1024];
    fgets(command, sizeof(command), stdin);
    commandProcess(command);
    return 0;
}

1 Comment

Thanks for suggesting fgets() as well :) .

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.