質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

12074閲覧

'const char [6]' から 'char *' へ変換できません。 と出ます。どうすればよいでしょうか?

type33

総合スコア1

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/10/18 20:34

前提・実現したいこと

現在、ロベールのc++講座にて独学中のプログラミング初心者です。
ポインタについての学習中、
例の通りにコードを打ち込んだのですが、エラーが出たため、解決方法を知りたいです。

発生している問題・エラーメッセージ

エラー C2664 'void ShowLength(char *)': 引数 1 を 'const char [6]' から 'char *' へ変換できません。 ```c++ 以下、該当ソースコード #include<iostream> using namespace std; size_t StrLen(char* str) { char* p; for (p = str; *p != '\0'; ++p) { //何もしない return p - str; } } void ShowLength(char* str) { cout << "文字列「" << str << "「の長さは" << StrLen(str) << "バイトです。" << endl; } int main() { ShowLength("Hello"); }

試したこと

エラーコードから解決ページで調べましたが、大半がまだ未学習の内容で理解があまりできませんでした。

・指定された関数のプロトタイプを確認し、エラー メッセージに示された引数を修正してください。
・必要に応じて、明示的な変換を指定してください。

との記載がありましたが、修正する必要はないように思い、困っています。

補足情報(FW/ツールのバージョンなど)

開発ツールは visual studio 2019を使用しております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

文字烈リテラル("Hello")は、const char[]です。
なので、size_t StrLen(char* str)は、size_t StrLen(const char* str)としましょう。

投稿2020/10/18 21:12

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

type33

2020/10/19 06:21 編集

回答ありがとうございます。 無事解決できました。
guest

0

ベストアンサー

現象としては、仮引数と実引数の型が一致していなければいけない、それだけです。コレ、本当に習っていないのですか?

もし、実引数を仮引数に暗黙の型変換で変換できるならそれでもよいのですが、変換出来なければエラーになります。
この場合は、実引数の方がconstがついていて変更禁止なのに、仮引数にconstがついていないので、もしかしたら引数として受け渡した先で変更しようとする可能性がある、なので暗黙の(自動的には)変換は出来ない、ということです。
C++の先祖のCでは型についてかなりいい加減だったので、コンパイル時にはエラーは出ませんがしかし実行したときには変更禁止領域を書き換えようとしてトラブルになる...という可能性があったりした、その可能性を潰したのですね。その分、型なんて知らない動けばいいやなプログラミングが通用しなくなりました。そのへんの歴史もあって、2007年のロベールさんの時代のVC++はそれがデフォルトで通っていたのかも知れません(VC2005とか2008の環境は残していないので確認が出来ません。手元でgcc Ver 7で試してみるとデフォルトではエラーになりませんでした。)

今回で言えば、文字列リテラルはconst char[]なわけで、const charには変換出来てもこれをcharに渡そうとすればエラーになる、ということです。明示的な手段で型を合わせましょう。

  • 出来るけど、ほぼやってはいけない手段

キャストで無理やりねじ伏せる
ShowLength((char*)"Hello");
あるいは
ShowLength(const_cast<char*>("Hello"));
これでエラーが出なくなったぜ、OK! ...ではないです(C/C++では特に、コンパイルでエラーが出ないことでは正しいプログラムであることは全く保証されません)。キャストでconstを外すのは、例えば関数側がすでに作り込まれたライブラリで、どうにも変更が出来ないなどの場合の最後の手段、なにが起こってもプログラマが責任を取るとの覚悟の上で使う飛び道具です。

  • まぁ、だめとも言い切れない手段

文字列リテラルだから変更出来ないのです。実引数のほうをそもそも変更が許される、constでないものに変えればいい。

C++

1 char str[]="Hello"; 2 ShowLength(str);

でも、変更はされないんですよね? だったら、そうするべきかは疑問。

  • たぶんこれが本来の手段

関数内の処理ではポインタの指示先を書き換えてないことを十分に確認しましたか? であれば、仮引数の型にconstをつければいいです。この関数はポインタの指示先を書き換えていないことを公に宣言しましょう。そうすればコンパイラは文句を言わずに引数を渡してくれるでしょう。
もちろん、関わるポインタ処理は全てconstになってなきゃいけません。

C++

1size_t StrLen(const char* str) { 2 const char* p; 3<> 4void ShowLength(const char* str) {

投稿2020/10/18 23:29

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

type33

2020/10/19 06:23 編集

回答ありがとうございます。 仮引数と実引数の型が一致していなければいけないという点に関しては理解していましたが、文字列リテラルに関してあまり触れていなく、char型のなにか、という風にとらえておりました。 教えていただいた例には非常に納得させられました。僕が初心者ということがあり、大変わかりやすく多くのことを回答していただき助かりました。無事解決できました。
guest

0

解決法

文字列リテラルの型は const char[] です。 ですから受け取るのであれば char* ではなく const char* 型の変数 (仮引数) が必要です。

経緯

const の扱いがいいかげんな資料が存在することには若干の歴史的経緯があります。

古い規格

C++03 (2003 年に発行された C++ の規格の通称) では文字列リテラルを char* へ変換することが許されていました。 ですから質問者が提示したプログラムはその時代には問題ありませんでした。 とはいえ、推奨しないとも書かれていますし、将来の規格改定で維持されることを保証できない (変更される可能性が高い) と明記している程度の悪い機能だったのです。

文字列リテラルの場合に限らず const を外す操作は問題を引き起こしやすいと考えられており、意識しにくい形で暗黙に const を外してしまうのは全体の整合性を考えると奇妙なルールです。 C との互換性の都合でやむなく入れていた変換規則でした。

悪い機能だとはいえ、規格が許している以上は当時のコンパイラは許容せざるをえませんでした。

現状

C++11 (2011 年に改定された規格の通称) でその変換ルールは削除されました。 多くのコンパイラはそれに追従しました。

ただ、マイクロソフトのコンパイラは比較的後まで文字列リテラルから const を外す変換を許容してしたようです。

資料

このような経緯から、 C++11 発行以前の資料では古い規格に基づいて const の付け方がいいかげんなものが少なからずあります。

念のために強調しておきますが、 C++11 発行以前でも規格が許容してはいたとはいえ const を外すのはとても悪い作法でした。

投稿2020/10/19 00:05

SaitoAtsushi

総合スコア5686

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

type33

2020/10/19 06:22 編集

回答ありがとうございます。 なるほど、そういった経緯があったのですね・・・ 解決法に加え、本に関して抱いた疑問も非常に丁寧に取り除いてくださり、助かりましたし、勉強になりました。無事解決できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問