36048
```

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main() 
    {
        string fpath;   //  ファイルパス変数
        cout << "ファイルをドロップしてください。\n";
        cin >> fpath;   //  パス入力
    
    
        if (fpath != "")    //  受け取ったファイルか空じゃなかったら
        {
            cout << "ファイルを受け取りました。";
    
            FILE *fp = (FILE *)malloc(sizeof(FILE));    //  変数宣言＆メモリ確保
            fopen_s(&fp, "file.pbm", "rb");             //  ファイルを開く
    
            do {
                int ch = fgetc(fp);
                printf("%X ", ch);
            } while (!feof(fp));
    
            fclose(fp);
    
        }
    }
    
```

というコードを書いたんですが、`fopen_s(&fp, "file.pbm", "rb"); //
ファイルを開く`という所でユーザから与えられた、`fpath`(ファイルパス)を与えたく  
`fopen_s(&fp, fpath, "rb");`  
とすると

> "std::string" から "const char *" への適切な変換関数が存在しません

というエラーが発生します。  
これはどう対処するべきなんですか？
CC BY-SA 3.0
2017-07-02T12:38:10.247
36036
2017-07-03T13:27:32.930
2017-07-02T16:34:51.907
5044
20192
question
c++ macos windows
C++でファイルを読み込んで、そのファイルの情報を16進数で表示する
`fopen_s`はC由来の関数でCでもC++でも使えますが、`std::string`はC++だけで使えるので`fopen_s`は直接は引数に取れません。メンバー関数`c_str()`を使ってCで扱える文字列を取得します。いくつか気になる点も一緒に修正したサンプルはこうなります。

```

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        string fpath;   //  ファイルパス変数
        cout << "ファイルをドロップしてください。\n";
        cin >> fpath;   //  パス入力
    
    
        if (fpath != "")    //  受け取ったファイルか空じゃなかったら
        {
            cout << "ファイルを受け取りました。\n";
    
            FILE *fp;   //  fpにはfopen_sが値を設定するので初期化の必要はない
            errno_t e = fopen_s(&fp, fpath.c_str(), "rb"); //  ファイルを開く
            if (e != 0)
            {
                return e;
            }
    
            for(int ch; (ch = fgetc(fp)) != EOF; )
            {
                printf("%X ", ch);
            }
    
            fclose(fp);
    
        }
    
        return 0;
    }
    
```

修正した気になる点とは

  * `fp`の値は`fopen_s`が設定するので、初期化してはいけない。  
元のコードだと確保したメモリが解放されないままリークしてしまいます。

  * 中身が空のファイルもあり得るので、表示するデータが必ずあるとは限らない。EOFのチェックはデータを表示する前にしたほうが良い。  
元のコードだと、空のファイルの時、ないはずのデータを表示してしまいます。

  * `int main()`と宣言しているので、ちゃんと戻り値を返す。

です。
CC BY-SA 3.0
2017-07-02T13:55:35.170
36040
2017-07-02T14:53:06.593
2017-07-02T14:53:06.593
3605
3605
36036
answer
コメントにも書きましたがC言語とC++言語を区別して考える必要があります。C++言語の`std::string`をC言語の`fopen_s`に渡したために齟齬が生じています。ここでC++言語でファイルを扱う型としては[`std::ifstream`](http://en.cppreference.com/w/cpp/io/basic_ifstream)が用意されており、その[コンストラクタ](http://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream)には

>
```

>     basic_ifstream( const char* filename, std::ios_base::openmode mode );
>     basic_ifstream( const std::string& filename, std::ios_base::openmode
> mode );
>  
```

と`std::string`を扱うものも用意されているため悩む必要がなくなります。  
C++言語で記述した場合は次のようになります。

```

    #include <fstream>
    #include <iostream>
    #include <string>
    
    int main() {
        std::string fpath;
        std::cout << "ファイルをドロップしてください。" << std::endl;
        std::cin >> fpath;
        if (!fpath.empty()) {
            std::cout << "ファイルを受け取りました。" << std::endl;
            std::ifstream fin{ fpath, std::ios::binary };
            if (!fin.is_open())
                return 1;
            int ch;
            while (std::ifstream::traits_type::not_eof(ch = fin.get()))
                std::cout << std::hex << std::uppercase << ch << ' ';
        }
        return 0;
    }
    
```

またC言語で記述した場合は次のようになります。

```

    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        char fpath[1024];
        printf("ファイルをドロップしてください。\n");
        scanf_s("%s", fpath, 1024);
        if (strcmp(fpath, "") != 0) {
            printf("ファイルを受け取りました。\n");
            FILE *fp;
            int ch;
            errno_t e = fopen_s(&fp, fpath, "rb");
            if (e != 0)
                return 1;
            while ((ch = fgetc(fp)) != EOF)
                printf("%X ", ch);
            fclose(fp);
        }
        return 0;
    }
    
```
CC BY-SA 3.0
2017-07-02T23:09:56.493
36048
2017-07-03T13:27:32.930
2017-07-03T13:27:32.930
4236
4236
36036
answer