C++ Strtok在C++;给了我意想不到的行为
我有这个函数:C++ Strtok在C++;给了我意想不到的行为,c++,C++,我有这个函数: void simple_shell::parse_command(char* cmd, char** cmdTokens) { // TODO: tokenize the command string into arguments char *token = strtok(cmd, " "); int count = 0; while (token != NULL) { count = count + 1; cout << t
void simple_shell::parse_command(char* cmd, char** cmdTokens) {
// TODO: tokenize the command string into arguments
char *token = strtok(cmd, " ");
int count = 0;
while (token != NULL) {
count = count + 1;
cout << token << endl;
token = strtok(NULL, " ");
}
char *secondToken = strtok(cmd, " ");
*cmdTokens = new char[count];
count = 0;
while (secondToken != NULL) {
cmdTokens[count] = secondToken;
cout << secondToken << endl;
secondToken = strtok(NULL, " ");
count = count + 1;
}
}
void simple_shell::parse_命令(char*cmd,char**cmdTokens){
//TODO:将命令字符串标记为参数
char*token=strtok(cmd,“”);
整数计数=0;
while(令牌!=NULL){
计数=计数+1;
coutstrtok()
将以null结尾的字符串作为输入进行操作,但它会在字符串运行时修改字符串。当它在字符串中找到分隔符时,会在分隔符所在的位置插入nul字符,并返回指向插入的nul前面的标记的指针。在使用null输入指针的下一次调用中,搜索将在上一个nul之后开始y注入nul
因此,当您运行第一个循环时,所有内容都正确输出,但是strtok()
更改了cmd
的内容,将所有空格字符替换为nul字符。因此,当您运行第二个循环时,它在cmd
中找不到任何空格字符,并在到达第一个标记后停止查找nul字符,即使它实际上不是字符串中的最后一个nul
所以,你有几个选择
您可以在每个循环上复制cmd
。您还必须复制存储在输出数组中的每个令牌,因为它们将指向临时内存:
int simple_shell::parse_command(char* cmd, char*** cmdTokens)
{
*cmdTokens = NULL;
char *dup = strdup(cmd);
if (!dup)
return -1;
int count = 0;
char *token = strtok(dup, " ");
while (token)
{
++count;
token = strtok(NULL, " ");
}
free(dup);
try {
*cmdTokens = new char*[count];
}
catch (const std::bad_alloc&) {
return -1;
}
if (count > 0)
{
dup = strdup(cmd);
if (!dup)
{
delete[] *cmdTokens;
return -1;
}
token = strtok(dup, " ");
count = 0;
while (token)
{
cmdTokens[count] = strdup(token);
if (!cmdTokens[count])
{
for(int i = 0; i < count; ++i)
free(cmdTokens[i]);
delete[] *cmdTokens;
return -1;
}
++count;
token = strtok(NULL, " ");
}
}
return count;
}
char**tokens;
int numTokens=shell.parse_命令(“helloworld”、&tokens);
如果(numTokens!=-1)
{
对于(int i=0;i STD::C++在C++中不使用<代码> Sttokor()/Case>来分割字符串。对于重新进入来说,它容易出错,而且不可靠。这里有一些更好的方法:在使用C++时,也不要停止使用<代码> char *<代码>和<代码>新< /代码>。
修改它的缓冲区参数。这就是它的工作原理。阅读它的描述。因此,在第一次遍历字符串时,char
缓冲区被彻底破坏,并被strtok()
。显示的代码天真地期望cmd
在第二次通过时成为其原始的原始自我。不幸的是,这不会发生。祝你下次好运。我基本上使用cmd并将其以空格作为分隔符进行拆分。--有趣。将该代码与您尝试的strtok
进行比较。有什么建议吗n获取我需要的输出?在每个循环之前使用strdup(cmd)
,然后标记重复的字符串,或者根本不要使用strtok()
。还有其他方法可以标记字符串而不改变它。@HumanCyborgRelations放弃strtok()
并使用更稳定的东西。@Remy“使用strdup(cmd)
每次循环“我闻到内存泄漏”之前:P@user0042当然,但是当使用C++风格的内存管理时,会发生这种情况。
char** tokens;
int numTokens = shell.parse_command("hello world", &tokens);
if (numTokens != -1)
{
for (int i = 0; i < numTokens; ++i)
{
std::cout << tokens[i] << std::endl;
free(tokens[i]);
}
delete[] tokens;
}
const char* nextToken(const char *str)
{
if (!str)
return NULL;
while (*str == ' ')
++str;
if (*str == '\0')
return NULL;
return str;
}
const char* endOfToken(const char *str)
{
if (!str)
return NULL;
while ((*str != ' ') && (*str != '\0'))
++str;
return ptr;
}
int simple_shell::parse_command(char* cmd, char*** cmdTokens)
{
*cmdTokens = NULL;
char *ptr = cmd;
int count = 0;
const char *token = nextToken(ptr);
while (token)
{
++count;
token = nextToken(endOfToken(token));
}
try {
*cmdTokens = new char*[count];
}
catch (const std::bad_alloc&) {
return -1;
}
if (count > 0)
{
ptr = cmd;
count = 0;
token = nextToken(ptr);
while (token)
{
const char *end = endOfToken(token);
int len = (end-token);
try {
cmdTokens[count] = new char[len+1];
}
catch (const std::bad_alloc&) {
for(int i = 0; i < count; ++i)
delete[] cmdTokens[i];
return -1;
}
memcpy(cmdTokens[count], token, len);
cmdTokens[count][len] = '\0';
++count;
token = nextToken(end);
}
}
return count;
}
char** tokens;
int numTokens = shell.parse_command("hello world", &tokens);
if (numTokens != -1)
{
for (int i = 0; i < numTokens; ++i)
{
std::cout << tokens[i] << std::endl;
delete[] tokens[i];
}
delete[] tokens;
}
struct token_info
{
char* token;
int length;
}
const char* nextToken(const char *str)
{
if (!str)
return NULL;
while (*str == ' ')
++str;
if (*str == '\0')
return NULL;
return str;
}
const char* endOfToken(const char *str)
{
if (!str)
return NULL;
while ((*str != ' ') && (*str != '\0'))
++str;
return ptr;
}
int simple_shell::parse_command(char* cmd, token_info** cmdTokens)
{
*cmdTokens = NULL;
char *ptr = cmd;
int count = 0;
const char *token = nextToken(ptr);
while (token)
{
++count;
token = nextToken(endOfToken(token));
}
try {
*cmdTokens = new token_info[count];
}
catch (const std:bad_alloc&) {
return -1;
}
if (count > 0)
{
ptr = cmd;
count = 0;
token = nextToken(ptr);
while (token)
{
const char *end = endOfToken(token);
cmdTokens[count].token = const_cast<char*>(token);
cmdTokens[count].length = (end-token);
++count;
token = nextToken(end);
}
}
return count;
}
token_info* tokens;
int numTokens = shell.parse_command("hello world", &tokens);
if (numTokens != -1)
{
for (int i = 0; i < numTokens; ++i)
std::cout << std::string(tokens[i].token, tokens[i].length) << std::endl;
delete[] tokens;
}
std::vector<std::string> simple_shell::parse_command(const std::string &cmd)
{
std::istringstream iss(cmd);
return std::vector<std::string>(
std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>()
);
}
std::vector<std::string> tokens = shell.parse_command("hello world");
for (auto &token: tokens)
std::cout << token << std::endl;