0

私はstd名前空間の初心者のようなもので、ディレクトリ内のすべての jpeg ファイルをループして感嘆符を削除するコードを書いています。と を使おうとしていstd::stringます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;
            }
        }
    }
}

ファイル名に含まれる感嘆符は 1 つだけであると仮定します。tempname を this として定義した場合const char*、それはポインターになるため、意味があります。tempname の値はconst、それが指すデータが変更された場合、宣言に違反することなく変更できます。しかし、ポインタを取り除いて、私は困惑しています。

4

2 に答える 2

3

tempname の宣言は、正確に 1 文字でコピーすることを意味していることに気付きましたか? それはあなたが望んでいたものではないと確信しています。

おそらく、文字列自体のコピーを作成して、次のようにコードを変更する必要があります。

            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 のドキュメントを参照してください。ここでは、文字列オブジェクトで変更メンバー関数を呼び出すと、c_str() 呼び出しの結果が無効になる可能性があることを明確に示しています。std::string と C 文字列イディオムを混在させる場合は注意が必要です。

于 2013-07-05T15:26:23.790 に答える
0

投稿したコードには未定義の動作があります。つまり、何かが起こる可能性があります。を 1 つ定義し、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 に答える