在C ++中使用变量作为system()输入WITHOUT c_str()

时间:2014-11-13 12:47:00

标签: c++ windows system

这与“为什么简单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() )

但它失败了,不过。编译很好,但是当像这样调用system()时 - 系统说它无法找到指定的路径。

但是,当我将其恢复并在直接系统调用中使用c_str()时,例如像这样:

string tmp = (string)systemRunner->getSystemRunCString();
system( tmp.c_str() );

这很好用。

如果我创建一个与c_str()返回相同内容的方法,可以预期
const char*,我会得到相同的结果,但我没有得到它......

我甚至试图将两个输入都放在system()但文件中 - 相同的结果,因此它存储相同的信息......

我错过了什么吗?这甚至可能吗?


PS:我说的是在Windows 7控制台应用程序中使用system() ...

编辑:那么@ravi对于导致这个特定示例失败的原因是正确的 - 但是主题的答案在标题中是什么 - 是否可以调用系统(变量)没有直接调用c_str()吗? :)

4 个答案:

答案 0 :(得分:5)

return this->prepareStream.str().c_str();

将返回const char *。该指针将是指向字符串类使用的内部字符指针的指针。通过这个操作,你可以访问字符串的内部数据,但是因为它是const指针,你将无法修改它的内容。

这里发生的事情是在执行此函数后,字符串(您仍然保留其内部数据)超出范围。所以,你只是在处理其字符串超出范围的句柄。

你永远不应该依赖于此。

答案 1 :(得分:3)

@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,只要c_str()的实例未被销毁,systemRunner返回的指针就会有效。此外,对于您的示例中的简单格式,您不需要stringstream,您可以使用append()to_string()方法。

答案 2 :(得分:2)

只要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

这也适用于Rudolfs Bundulis的回答。

答案 3 :(得分:1)

我将分解操作prepareStream.str().c_str();以准确显示发生的情况。

让我们改写:

const char* getSystemRunCString(){
    const string s = prepareStream.str();
    const char * c = s.c_str();
    printf("%s - %p\n", c, c);
    return c;
}

它工作正常并显示准备命令行

但是如果我使用

,则返回方法
const char *c = systemRunner->getSystemRunCString();
printf("%s - %p\n", c, c);

指针地址相同,但字符串本身已经消失。

解释:

在幕后,prepareStream.str().c_str();创建一个本地字符串,并在其内容上获得const char *。但是由于字符串没有保存在任何地方,因此它超出范围并且其内容消失。

所以你的问题不在system级别,但与stringstream ssss.str().c_str()不正确的事实有关,因为你得到一个指向一个字符串的指针指示结束时的范围。

如果您编写string s = prepareStream.str().c_str();,它会起作用,因为内部字符串仅在指令末尾超出范围,而在指令期间将值复制到新字符串。< / p>