在c++中使用变量作为系统()输入而不使用c_str()
Use variable as system() input WITHOUT c_str() in C++
这不是类似"为什么简单的system(variable)
不起作用"的重复
解决方案是将字符串存储到可由c_str()转换的变量中,然后调用:system(variable.c_str())
然而,我正在寻找一种不用c_str()
直接调用的方法。
所以我试过类似的东西
class systemRunner{
private:
stringstream prepareStream;
public:
void setProgram( string s ){
prepareStream.str(""); // empty stream
prepareStream.clear(); // reset stream - !IMPORTANT!
prepareStream << """ << s << """;
}
void appendParam( string s ){ this->prepareStream << " " << s; }
void appendParam( int i ){ this->prepareStream- << " " << i; }
const char* getSystemRunCString(){
//const std::string s = ;
return this->prepareStream.str().c_str();
}
};
然后人们会认为这将是enaugh:
system ( systemRunner->getSystemRunCString() )
但它失败了。编译很好,但当系统()像这样被调用时,系统会说它找不到指定的路径。
然而,当我恢复它并在直接系统调用中使用c_str()
时,例如:
string tmp = (string)systemRunner->getSystemRunCString();
system( tmp.c_str() );
这很好用
人们会期望,如果我创建一个返回与CCD_ 5相同的东西的方法,
即const char*
,我会得到相同的结果,但我没有得到它…
我甚至试着不把两个输入都放在system()
中,而是放在文件中——相同的结果,这样它就存储了相同的信息。。。
我是不是错过了什么?这可能吗?
PS:我说的是在Windows7控制台应用程序中使用system()
EDIT:好吧,@ravi说得对是什么导致了这个特定的例子失败,但标题中主要问题的答案是什么?是否可以在不直接调用其中的c_str()的情况下调用系统(变量)?:)
return this->prepareStream.str().c_str();
将返回const char*。该指针将是指向字符串类使用的内部字符指针的指针。通过此操作,您可以访问字符串的内部数据,但由于它是常量指针,您将无法修改其内容。
这里发生的情况是,在执行该函数后,字符串(您仍然持有其内部数据)超出了范围。所以,您只是在处理其字符串超出范围的句柄。
你永远不应该依赖这个。
@ravi已经完美地解释了代码失败的原因,因为str()
返回的值超出了范围,但由于它的注释提到了它仍然不清楚如何解决实际问题,这里有一个可能的答案:
class systemRunner{
private:
string systemCommand;
public:
void setProgram( string s ){
systemCommand.clear();
systemCommand.append(""").append(s).append(""");
}
void appendParam( string s ){ systemCommand.append(" ").append(s); }
void appendParam( int i ){
// VS 2013:
// systemCommand.append(" ").append(to_string(i)));
// VS 2010:
// systemCommand.append(" ").append(to_string(static_cast<long long>(i)));
// General stringstream conversion
stringstream argumentStream;
argumentStream << i;
systemCommand.append(" ").append(argumentStream.str());
}
const char* getSystemRunCString(){
return systemCommand.c_str();
}
};
使用string
而不是stringstream
,这样只要systemRunner
的实例没有被破坏,c_str()
返回的指针就会有效。此外,对于示例中的这种简单格式,您不需要stringstream
,只需使用append()
和to_string()
方法即可。
只要systemRunner
本身不是临时对象,就可以执行以下操作:
class systemRunner {
private:
stringstream prepareStream;
string commandLine;
public:
//...
const char* getSystemRunCString() {
commandLine = prepareStream.str();
return commandLine.c_str();
}
};
通过这种方式,您返回的指针不是指向临时字符串,而是指向与systemRunner
对象具有相同生存期的字符串。
不过,请注意,getSystemRunCString()
应该仅用作"临时"字符串的提供者,千万不要像那样使用它
const char* cmd1 = runner.getSystemRunCString();
runner.setProgram(...);
const char* cmd2 = runner.getSystemRunCString();
// cmd1 is now invalid.
system(cmd1); // UB
这也适用于鲁道夫·邦杜利斯的回答
我将分解操作prepareStream.str().c_str();
,以精确地显示发生了什么。
让我们改为写:
const char* getSystemRunCString(){
const string s = prepareStream.str();
const char * c = s.c_str();
printf("%s - %pn", c, c);
return c;
}
它运行良好,并显示准备命令行
但如果我使用,在返回方法上
const char *c = systemRunner->getSystemRunCString();
printf("%s - %pn", c, c);
指针地址相同,但字符串本身已经不见了。
解释:
在后台,prepareStream.str().c_str();
创建一个本地字符串,并在其内容上获得一个const char *
。但是,由于字符串没有保存在任何位置,它超出了范围,其内容也随之消失。
因此,您的问题不在system
级别,而是与以下事实有关:对于stringstream ss
,ss.str().c_str()
是不正确的,因为您在指令末尾获得了一个指向超出范围的字符串的指针。
如果您编写string s = prepareStream.str().c_str();
,它会起作用,因为内部字符串只在指令结束时超出范围,并且在指令期间,值会复制到新字符串。
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 检查输入是否不是整数或数字
- 正在尝试了解输入验证循环
- 读取文件并输入到矢量中
- C++如何通过用户输入删除列表元素
- 用c++从输入文件中读取另一行
- 读取文件的最后一行并输入到链接列表时出错
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何使用用户输入在C++中正确填充2D数组
- C++MySQL C api用户输入行
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 用户定义函数中的指针和输入
- 如何在C++中检查2D数组中负值的输入验证
- 如何只允许用户输入正整数
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- 为什么无论你输入什么,这"while(cin.get(str,3))"只运行一次?
- 将INT和STR输入并将它们存储到两个单独的列表中
- 限制一个str[n]的输入