C
Christopher
An open book test I am taking, tasked me to write a function with the
following prototype. Yea, its a test, so don't give me the
implementation. But it is open book, so maybe I can at least get a few
questions answered.
// returns the next token in a string found seperated by the
delimeter. upon return updates str to point to the next token in
// the string after the one returned
const char * nextToken(const char ** str, const char delimeter);
When I look at this, it looks very c-style to me. I think it is
unsafe.
1) I don't see a way to return a different string without allocating
it in the function body and leaving it to the caller to clean the new
string up.
2) Why we have a pointer to a pointer as a parameter isn't clear to
me. Even after all these years with the Windows API, I don't see the
purpose here. Why not just use a const char *?
These attempts failed with compiler errors, when trying to update the
str param
str = str + indexOnePastDelimeter; // If it was a const
char *, this is what I'd do
str = &(*str + indexOnePastDelimeter); // I don't see why the
compiler complains about this one
str = &((*str)[indexOnePastDelimeter]);
I am going to submit a more c++ implementation (below) with a
different prototype, because I failed at updating the str parameter in
all my attempts and the c-style implementation came out very ugly.
However, if anyone can address those 2 issues for me, I'd like to know
what the thinking was.
#include <string>
#include <iostream>
//--------------------------------------------------------------------------------------
/// \brief Tokenizes a string
/// \detail Gets a substring from a string, from a given start
position to the position
/// of a given delimeter. If the delimiter is not found,
everything from the start
/// position to the end of the given string is returned
/// \param str The string to tokenize
/// \param delimiter Characterer that seperates one token from the
next
/// \param start_pos [IN,OUT] position of the string to start looking
for the next token.
/// When a token is found, this parameter is updated
to the start position
/// of the next token in the string. If no next token
has been found
/// before reaching the end of the string, this
parameter will be set to
/// std::string::npos.
/// \return std::string The next token found in the string from the
given start position.
/// If the str param is empty or the start_pos
param is past the end of
/// the string, then an empty string will be
returned.
std::string nextToken(const std::string & str, const char delimiter,
std::string::size_type & start_pos)
{
// Check for valid params
if( str.empty() || start_pos >= str.size() )
{
start_pos = std::string::npos;
return "";
}
std::string::size_type orig_start_pos = start_pos;
std::string::size_type delim_pos = str.find(delimiter,
start_pos);
// Check if the delimiter was not found
if( delim_pos == std::string::npos )
{
start_pos = std::string::npos;
return str.substr(orig_start_pos, std::string::npos);
}
// Update the start position
if( delim_pos + 1 < str.size() )
{
start_pos = delim_pos + 1;
}
else
{
start_pos = std::string::npos;
}
// Return a substring that is from the start position to right
before the delimeter
return str.substr(orig_start_pos, delim_pos - orig_start_pos);
}
//--------------------------------------------------------------------------------------
int main()
{
// Test 1
const std::string testString1 = "Mary,Autumn,Susie,Sally";
std::string::size_type start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString1, ',', start_pos) <<
std::endl;
}
system("Pause");
// Test 2
const std::string testString2 = "C:\\Windows\\System32\\Drivers\
\Etc\\";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString2, '\\', start_pos) <<
std::endl;
}
system("Pause");
// Test 3
const std::string testString3 = "";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString3, ',', start_pos) <<
std::endl;
}
system("Pause");
// Test 4
const std::string testString4 = ",";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString4, ',', start_pos) <<
std::endl;
}
system("Pause");
// Done
return 0;
}
following prototype. Yea, its a test, so don't give me the
implementation. But it is open book, so maybe I can at least get a few
questions answered.
// returns the next token in a string found seperated by the
delimeter. upon return updates str to point to the next token in
// the string after the one returned
const char * nextToken(const char ** str, const char delimeter);
When I look at this, it looks very c-style to me. I think it is
unsafe.
1) I don't see a way to return a different string without allocating
it in the function body and leaving it to the caller to clean the new
string up.
2) Why we have a pointer to a pointer as a parameter isn't clear to
me. Even after all these years with the Windows API, I don't see the
purpose here. Why not just use a const char *?
These attempts failed with compiler errors, when trying to update the
str param
str = str + indexOnePastDelimeter; // If it was a const
char *, this is what I'd do
str = &(*str + indexOnePastDelimeter); // I don't see why the
compiler complains about this one
str = &((*str)[indexOnePastDelimeter]);
I am going to submit a more c++ implementation (below) with a
different prototype, because I failed at updating the str parameter in
all my attempts and the c-style implementation came out very ugly.
However, if anyone can address those 2 issues for me, I'd like to know
what the thinking was.
#include <string>
#include <iostream>
//--------------------------------------------------------------------------------------
/// \brief Tokenizes a string
/// \detail Gets a substring from a string, from a given start
position to the position
/// of a given delimeter. If the delimiter is not found,
everything from the start
/// position to the end of the given string is returned
/// \param str The string to tokenize
/// \param delimiter Characterer that seperates one token from the
next
/// \param start_pos [IN,OUT] position of the string to start looking
for the next token.
/// When a token is found, this parameter is updated
to the start position
/// of the next token in the string. If no next token
has been found
/// before reaching the end of the string, this
parameter will be set to
/// std::string::npos.
/// \return std::string The next token found in the string from the
given start position.
/// If the str param is empty or the start_pos
param is past the end of
/// the string, then an empty string will be
returned.
std::string nextToken(const std::string & str, const char delimiter,
std::string::size_type & start_pos)
{
// Check for valid params
if( str.empty() || start_pos >= str.size() )
{
start_pos = std::string::npos;
return "";
}
std::string::size_type orig_start_pos = start_pos;
std::string::size_type delim_pos = str.find(delimiter,
start_pos);
// Check if the delimiter was not found
if( delim_pos == std::string::npos )
{
start_pos = std::string::npos;
return str.substr(orig_start_pos, std::string::npos);
}
// Update the start position
if( delim_pos + 1 < str.size() )
{
start_pos = delim_pos + 1;
}
else
{
start_pos = std::string::npos;
}
// Return a substring that is from the start position to right
before the delimeter
return str.substr(orig_start_pos, delim_pos - orig_start_pos);
}
//--------------------------------------------------------------------------------------
int main()
{
// Test 1
const std::string testString1 = "Mary,Autumn,Susie,Sally";
std::string::size_type start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString1, ',', start_pos) <<
std::endl;
}
system("Pause");
// Test 2
const std::string testString2 = "C:\\Windows\\System32\\Drivers\
\Etc\\";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString2, '\\', start_pos) <<
std::endl;
}
system("Pause");
// Test 3
const std::string testString3 = "";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString3, ',', start_pos) <<
std::endl;
}
system("Pause");
// Test 4
const std::string testString4 = ",";
start_pos = 0;
while( start_pos != std::string::npos )
{
std::cout << nextToken(testString4, ',', start_pos) <<
std::endl;
}
system("Pause");
// Done
return 0;
}