-1

My code is

void function(string line) {
   char str[line.length()] = line;
   const char s[2] = " ";
   char *token;

  token = strtok(str,s);
  while (token != NULL) {
      printf( " %s\n",token);
      token = strtok(NULL,s);
  }
}

int main() {
  function("Slovakia 5 #948384");
  return 0;
}

Which does not compile unless I assign str explicitly like this:

char str[line.length()] = "Slovakia 5 #948384";

However, that defeats the purpose of having a variable string passed as a parameter to the function. How can I fix this?

mch
  • 9,424
  • 2
  • 28
  • 42
  • 5
    You fix this by learning, first of all, that `char str[line.length()]` is invalid C++, no matter what gets assigned to it. Which C++ textbook are you using that gives this kind of an example, and teaches others to write something like this? Also by learning about `std::string`'s methods like `find()`, `substr()`, as well as very useful iterators that will implement what the shown code actually tries to do in C, but in proper C++. Trying to use C code like `strtok()`, in C++, always ends in tears. – Sam Varshavchik Feb 10 '22 at 14:32
  • `char str[line.length()]` isn't allowed in C++. The size of the array has to be a compile time constant. If you want to copy an `std::string` to a `char` array you need to use `memcpy` or `strcpy`. Null terminated `char` strings are features inherited from C and need to be manipulated using C style functions. – François Andrieux Feb 10 '22 at 14:33
  • 1
    Please don't use the `strtok()` function to split strings, it's error Prozent in many ways. – πάντα ῥεῖ Feb 10 '22 at 14:34
  • 1
    You don't need to copy `line` to a C-style array here. You can operate directly on `line.data()`. – Paul Sanders Feb 10 '22 at 15:03
  • While the duplicate is excellent advice for the OP, I'm not certain that's it's genuinely a _duplicate_ of the question asked here. – Drew Dormann Feb 10 '22 at 15:04
  • 1
    Reopened. The "duplicate" is clearly not a duplicate. – Pete Becker Feb 10 '22 at 15:11
  • The best solution is to simply not use `strtok()`, which is a destructive function. There are many different ways to tokenize a `std::string`, see [Parse (split) a string in C++ using string delimiter (standard C++)](https://stackoverflow.com/questions/14265581/). – Remy Lebeau Feb 10 '22 at 18:58

1 Answers1

2

The simple answer is a shrug and "that's the way it is".

char arrays are rather primitive; they hold a sequence of char values, and there are a bunch of functions in the standard library that treat them like strings. But they're not like C++ std::string. They're just arrays.

int x[4] = { 1, 2, 3, 4 };
int y[4] = x; // illegal, arrays aren't automatically copied

Same thing for an array of char:

char x1[4] = { 'a' , 'b', 'c', '\0' };
char y1[4] = x1; // illegal, arrays aren't automatically copied

The typical copy operation on an array of char assumes that the sequence of characters is terminated by a nul character, and strcpy looks for that:

char y1[4];
strcpy(y1, x1); // okay; copies the contents of x1 into y1

And there's a special rule for arrays that are initialized by a string literal:

char y2[4] = "abc"; // okay, copies string literal into y2, including nul terminator

The red herring in the question is the combination of a variable length array with an attempted initialization from another array. Variable length arrays are not part of C++, so char str[line.length()] isn't legal. C allows runtime determination of array sizes, and some compilers allow this as an extension in C++.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165