Yes, pointer arithmetic and memcpy. However, seeing as you're using C++, let's stick to std::strings and assume they do a memcpy for us.
std::vector<std::string> output;
output.reserve(line.length() / 21 + (line.length() % 21) ? 1 : 0);
auto i = line.begin(), j = i + 21;
for(; line.end() - j > 21; i = j, j+= 21)
{
output.emplace(i, j)
}
if(j != line.end())
{
output.emplace(j, line.end());
}
So, what is going on here? For our purpose, it is good enough to think of a std::string as a char array and a length variable.
First, we reserve enough space for our output. You did this too.
Next, we define 2 variables i and j. i represents the beginning of the current substring and j the one-past-the-end iterator. Iterators here can be thought of as pointers into the internal structure of the string's char array - they may even be char*s!
We then iterate over the original string a line at a time. emplace just constructs a new element of a vector in the correct place. The call is equivalent to output.push_back(std::string(i, j)) and is only available in C++11.
To finish, we check whether there is another whole chunk using line.end() - j > 21; line.end() is the one-past-the-end iterator for the char array - it points at the NUL character (if there is one). If there is not a whole chunk, we check for a partial chunk using j != line.end().
doubleis even involved at all? This indicates some very low-quality code. Not to mention the dupe call tostrlen()... And no, you can't have array operations better thanO(n), you have to walk through the array. Also, you forget to NUL-terminate the substrings. And don't reinvent the wheel, use the standard library instead of rolling your ownstrcpy().