0

我是std命名空间的菜鸟,我正在编写循环遍历目录中所有 jpeg 文件并删除任何感叹号的代码。我正在尝试使用std::stringand std::vector。我的问题是我的变量 tempname:const char tempname = (char) *filelist[j].c_str();随着向量中的字符串的filelist变化而变化(它不应该 - 它是一个常量变量。这是我的 WinMain 函数的内容:

std::vector<std::string> filelist;
if (!dirExists(directory)) //checks if a directory exists
{
    CreateDirectory("resized", NULL);
}
std::vector<std::string> filelist = findFiles("*.jpg"); //finds files in its directory with a given extension
int result; //for rename function
for (unsigned int j=0; j< filelist.size(); j++)
{
    std::string::size_type pos = filelist[j].find("!"); //check for exclamation points
    if (std::string::npos != pos) //found one at index "pos" in the string
    {
        switch (MessageBox(window, (LPCSTR)filelist[j].c_str(), "Illegal filename - Rename?", MB_YESNO)) //user input
        {
            case IDYES:
            {
                const char tempname = (char) *filelist[j].c_str(); //the problem
                //attempt to remove the exclamation point
                result = rename(&tempname, filelist[j].erase(pos, 1).c_str());
                if (result == 0)
                    MessageBox(window, "Renamed File", "Information", MB_OK);
                else
                    MessageBox(window, "Error renaming file", "Error", MB_OK);
                break;
            }
            case IDNO:
            {
                break;
            }
        }
    }
}

假设文件名包含不超过一个感叹号。如果我将 tempname 定义为 aconst char*这将是有意义的,因为它将是一个指针 - 如果 tempname 指向const的数据发生更改,则 tempname 的值可以更改而不会违反声明。但是拿走指针,我很困惑。

4

2 回答 2

3

您意识到您的 tempname 声明意味着您将复制一个字符吗?我很确定这不是你想要的。

您可能想要复制字符串本身并按如下方式更改代码:

            std::string const tempname = filelist[j];
            //attempt to remove the exclamation point
            result = rename(tempname.c_str(), filelist[j].erase(pos, 1).c_str());

至于为什么如果您操纵基础字符串,您的所谓 const 变量会更改其值,请记住,在您的原始声明中, tempname 是一个指向值的指针,而您所说的只是指针不会改变其值。它没有,但指针做到了。

此外,当将 c_str 与字符串操作相结合时,您几乎进入了危险的领域 - 在这里查看 c_str 的文档,它清楚地指出在字符串对象上调用 mutating 成员函数可能会使 c_str() 调用的结果无效。将 std::string 与 C 字符串习语混合时必须小心。

于 2013-07-05T15:26:23.790 回答
0

您发布的代码具有未定义的行为,这意味着任何事情都可能发生。您定义一个char, tempname,然后将其地址传递给rename. rename需要一个指向'\0'终止字符串的指针;唯一合法的一个字符串是空字符串。

如果将定义替换为tempname

char const* tempname = filelist[j].c_str();

然后你以后有未定义的行为;调用 filelist[j].erase使此指针无效。实际上,它实际上会继续指向中的数据filelist[j] (因为实际上erase不会重新分配,因此 tempname会继续指向 中的第一个字符 filelist[j])。

你可能想要的是这样的:

std::string newName( filelist[j] );
newName.erase( std::remove( newName.begin(), newName.end(), '!' ),
               newName.end() );
result = rename( filelist[j].c_str(), newName.c_str() );
filelist[j] = newName;
于 2013-07-05T16:52:44.570 回答