在尝试创建一个shell几天之后,我会请求一些帮助。我已经开始使用不同的数据结构超过4次,并请求解决以下问题。我有一个字符串,我需要打破单个参数,并有一个指向它的指针。我最终将args传递给了一个exec函数,但由于我似乎无法正确填充args我得到了有趣的结果,这里是发生了什么的简化版本
char* args[100];
int counter=0;
string temp = "some text and stuff here";
stringstream s (temp);
while(s>> temp)
{
cout << "TOKEN " << counter << " =" << temp <<endl;
args[counter]=const_cast<char *> (temp.c_str());
counter++;
}
//print the debug info
for( int ii=0; args[ii] != NULL; ii++ )
{
cout << "Argument OUT " << ii << ": " << args[ii] << endl;
}
这段代码不起作用,我无法理解为什么。 结果存储&#34; here&#34;在args的每个值中,但计数器都会改变。
TOKEN 0 =some
TOKEN 1 =text
TOKEN 2 =and
TOKEN 3 =stuff
TOKEN 4 =here
Argument OUT 0: here
Argument OUT 1: here
Argument OUT 2: here
Argument OUT 3: here
Argument OUT 4: here
答案 0 :(得分:2)
执行此操作时:
args[counter]=const_cast<char *> (temp.c_str());
您没有复制字符串,只存储指向其内容的指针。所以当然它们都指向相同的temp
字符串,这使得在打印时它们的值完全相同。
如果您只使用std::vector<std::string>
args
,这会更容易。
答案 1 :(得分:1)
可能是因为temp
对象正在重用其内部分配。存储c_str()
结果时,只存储内存地址。每次从字符串流中读取std::string
类时,c_str()
类都不创建全新的分配,而是重用已有的分配(如果可能)。
此外,在对<{1}}对象进行任何之后,使用std::string
返回的指针会调用未定义的行为。 1 < / SUP>
如果可能,只需将args
更改为std::vector<std::string>
即可。如果这不可能,那么您需要strdup()
c_str()
返回的指针,以便创建一个全新的分配,在那一刻复制字符串的值。当然,当你完成时,你必须记住free()
分配。
此外,丢弃const
限定符并写入指针会导致未定义的行为。 2 至少您需要将args
更改为{{1}但是我强烈建议使用字符串向量。
1 http://en.cppreference.com/w/cpp/string/basic_string/c_str
从
const char * args[100];
获得的指针可能会失效:
- 将对字符串的非const引用传递给任何标准库函数,或
- 在字符串上调用非const成员函数,不包括
c_str()
,operator[]
,at()
,front()
,back()
,begin()
,rbegin()
和end()
。
2 http://en.cppreference.com/w/cpp/string/basic_string/c_str
写入通过
rend()
访问的字符数组是未定义的行为。
根据您的评论表明您需要使用c_str()
,听起来您确实需要一个指针数组 - exec()
。但是,我们仍然可以使用向量来做到这一点。您需要一个向量来保存char
个对象,这些对象将拥有std::string
分配。然后你可以使用另一个向量来保存实际的指针。像这样:
char*
在这种情况下,const char * binaryPath = "/bin/foo";
std::vector<std::string> argStrings;
std::vector<char *> argPointers;
std::string temp = "some text and stuff here";
istringstream s(temp);
// argv[0] should always contain the binary's path.
argPointers.push_back(binaryPath);
while (s >> temp) {
argStrings.push_back(temp);
std::cout << "TOKEN " << argStrings.size()
<< " =" << argStrings.back() << std::endl;
// We cast away the const as required by the exec() family of functions.
argPointers.push_back(const_cast<char *>(argStrings.back().c_str()));
}
// exec() functions expect a NULL pointer to terminate the arguments array.
argPointers.push_back(nullptr);
// Now we can do our exec safely.
execv(binaryPath, &argPointers[0]);
拥有实际的字符串分配,我们只使用argStrings
来保存我们将传递给argPointers
的指针数组。 execv()
是安全的,因为const_cast
不会修改字符串。 (对于与旧C代码的兼容性,参数为execv()
;函数的行为就像参数为char * const []
。)
答案 2 :(得分:0)
你需要分别存储每个字符串,存储指向临时对象的指针是不可取的。 E.g。
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
void exec(char* args[])
{
for (int i = 0; args[i] != NULL; ++i)
cout << args[i] << endl;
}
int main()
{
string temp = "some text and stuff here";
stringstream s (temp);
vector<string> tokens;
while(s>> temp)
{
tokens.push_back(temp);
}
int counter = 0;
char *args[100];
for (auto it = tokens.begin(); it != tokens.end(); ++it)
args[counter++] = const_cast<char*>(it->c_str());
args[counter] = NULL;
exec(args);
return 0;
}
你可以运行它here