Question

In C++, I want to do

char buffer[1024] = "command insert file1 file2 ..."

and turn it into

*argv[0] = "command"
*argv[1] = "insert"
*argv[2] = "file1"

et cetera. Isn't there some simple way to do this, like split() or whatever? I can't use boost or vectors because the elements need to be c-strings for linux library functions (like execvp), and they need to compile on a server without boost or any extra libraries

I've seen examples online that use strtok, but the examples don't seem to store the values afterward, just print them. The other way seems to be some ridiculously complicated method that involves looping through and counting spaces and escape characters. Isn't there an easier way? This is driving me nuts.

EDIT: As a point of reference, this is what my main function looks like so far:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdlib>
#include <cstdio>
#include <iostream>
using namespace std;

void runCommand(char **argv);
void splitIntoArgs(char *command, char **argv);

int main()
{

   char buffer[1024];
   char *argv[5];

   while (1)
   {
       // prompt user for command to run
       cout << "Enter command: ";
       cin >> buffer; //read the buffer
       cout << endl;
       splitIntoArgs(buffer, argv); //split the command into separate arguments
       if (strcmp(argv[0], "exit") == 0)
           return 0;
       runCommand(argv);
   }

}
Was it helpful?

Solution 2

Here is a strtok() version of splitting the command:

char** split(char *command, int* size) {
  char** ret;
  char* t;
  int i;
  for(i=0, t=strtok(command, " "); t!=NULL;++i ) {
    ret[i]=t;
    t = strtok(NULL, " ");
  }
  *size = i;
  return ret;
}

You can use it like this:

char** args;
int nArgs;
args = split(buffer, &nArgs);
// you can now eg. execvp("/bin/ls", args)

OTHER TIPS

You asked this as a c++ question, so why don't you use the power of c++ in the form of the standard library which gives you std::string and std::vector

#include <vector>
#include <string>

std::vector<std::string> split(const std::string& str){
    std::vector res;
    size_t old_position = 0;
    for(size_t position = 0; position = str.find(" ", position); position != std::npos){
        res.push_back(res.substr(position, position-old_position));
        old_position = position;
    }
}
// split string str on " ". The result array has count elements, 
// so make sure count > #of spaces + 1
char** split(char* str, int count){
   char** res = new char*[count];
   int res_i = 0;
   for(int i=0; str[i] != 0 && res_i < count; ++i){
       if(str[i] == ' '){
          res[res_i++] = i + 1;
          str[i] = 0;
       }
   }
   return res;
}

A couple of notes:

  • this code is not safe use. If for example the last character of "str" is a ' ', you would get a pointer to the null-terminator '\0'.
  • the standard reply to someone using char* for not specific reason in a c++ question still applies: use std::string!
  • split destroys the original string that was passed to it
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top