E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
hands
記事: 14
登録日時: 6年前

E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#1

投稿記事 by hands » 6年前

独習C++の練習問題 
 図書館の図書目録の項目を管理するための、cardという名前のクラスを作成しなさい。このクラスに本のタイトル、著者、在庫冊数を格納します。タイトルと著者を文字列として保存し、在庫冊数を整数として保存します。store()という名前の公開メンバ関数を使用して本の情報を保存し、show()という名前の公開メンバ関数を使用して情報を表示します。このクラスの動作を確認するために、単純なmain()関数を追加しなさい。

 に対しての解答、(以下のコード)をVisual Studio Community 2017で実行したところ
エラー (アクティブ) E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
が発生します。

これを回避するためにはどこを修正すれば良いのでしょうか。

型のパラメーターと互換性がないとはどういうことでしょうか。

コード:

#include <iostream>
#include <cstring>
using namespace std;

class card {
	char title[80];
	char author[40];
	int number;
public:
	void store(char *t, char *name, int num);
	void show();
};

void card::store(char *t, char *name, int num)
{
	strcpy(title, t);
	strcpy(author, name);
	number = num;
}

void card::show() 
{
	cout << "本のタイトル: " << title << "\n";
	cout << "著者: " << author << "\n";
	cout << "冊数: " << number << "\n";
}


int main() 
{
	card book1, book2, book3;

	book1.store("Dune", "Frank Herbert", 2);
	book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
	book3.store("The Rainbow", "D.H.Lawrence", 1);

	book1.show();
	book2.show();
	book3.show();

	return 0;
}

Bull
記事: 149
登録日時: 9年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#2

投稿記事 by Bull » 6年前

オフトピック
以前どこかで似たような回答をした記憶があるんだけど...
何でこのエラーが出るのかちょっと不思議
まずエラーになる理由ですが、C++ では文字列リテラルの型は const char [] です。これを関数の実引数に使うと const char * に変換されます。一方 void store(char *t, char *name, int num); で、関数の仮引数は const 無しですので、互換性がないと言うことです。
文字列リテラルは変更不可なのに store() 内部で文字列を変更されてしまう可能性があるので、エラーにしているのでしょう。

ただ、これは歴史的経緯で許容されているはずです。VC++ でもデフォルトではエラーにならないはずですが、/Zc:strictStrings オプションを指定するとこのようなエラーになります。Visual Studioで普通にプロジェクトを作成するとこのオプションを指定されていないと思いますが、プロパティを変更していますか?
/Zc:strictStrings オプションを指定しなければエラーにならないと思います。

また、store() の仮引数に const を付けて

コード:

void store(const char *t, const char *name, int num);
にしてもいいと思います。

アバター
tk-xleader
記事: 158
登録日時: 13年前
連絡を取る:

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#3

投稿記事 by tk-xleader » 6年前

Bull さんが書きました: ただ、これは歴史的経緯で許容されているはずです。
C++11以降は、文字列リテラルをchar*に暗黙変換できるという仕様は削除されました。

Bull
記事: 149
登録日時: 9年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#4

投稿記事 by Bull » 6年前

tk-xleader さんが書きました:
6年前
Bull さんが書きました: ただ、これは歴史的経緯で許容されているはずです。
C++11以降は、文字列リテラルをchar*に暗黙変換できるという仕様は削除されました。
あっ、そうなんですね。
C++98でもそうしたかったらしいのですが、そうできなかったという話を聞いたことがあります。

文字列リテラルは const char * で受けるのが正当なのでしょうが、それを厳密にやってしまうと、過去のソースの修正が大変なことになりそうです。そういうこともあって、多くのコンパイラーではまだ const 無しで受けることを許容しているのでしょうね。
もちろん今後作成するソースは const を付けるべきですが。

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#5

投稿記事 by hands » 6年前

Bullさん、tk-xleaderさんありがとうございます。

私もBullさんのおっしゃるように、constが付いてないからなのかな?とは思い至りました。

そこでご指摘の通りconstを付けてみました。

コード:

void store(const char *t, const char *name, int num);
オフトピック
すみません。~さんが書きました
の書き方がわかりません。
すると、

コード:

void card::store(char *t, char *name, int num)
…の方も互換性がないよという風なことを言われたので

コード:

void card::store(const char *t, const char *name, int num)
同じく修正しました…が、エラー C4996 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.が発生します。

2つ目のコードの修正の仕方が間違っていたでしょうか?

ちなみにですが、BULLさんがおっしゃる/Zc:strictStrings オプションというのは、初めて聞きました。

ですので、いじったことはないかと思うのですが、そのつもりがなくとも、変更されてしまう類のものでしょうか。

よろしければこちらの確認の方法も併せてご教授願えれば幸いです。

Bull
記事: 149
登録日時: 9年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#6

投稿記事 by Bull » 6年前

コード:

	char title[80];
	char author[40];
タイトルと作者は固定長で定義されていますが、これに 80/40 文字以上をコピーしたらどうなるでしょう?
そんなことしたら駄目ですよね。strcpy() ではそういうチェックは出来ませんから、strcpy_s() を使ってくださいと言うことなんだけど、そこは本質的なとこじゃないから、とりあえずエラー無しでコンパイルするためには、プログラムの先頭に

コード:

#define _CRT_SECURE_NO_WARNINGS
を追加してください。
オフトピック
C++なら std::string を使いましょうという話になりそうですが、それはまあ置いておいて
プロジェクトのプロパティで[C/C++]→[すべてのオプション]→[その他のオプション]に /Zc:strictString が指定されていると思われますが、前に書いたように、このオプションはデフォルトでは指定されないはずなので、指定されてなかったら私にはちょっとわかりません。

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#7

投稿記事 by hands » 6年前

ありがとうございます。

Bullさんのおかげで、ようやく先に進めます。

コード:

#define _CRT_SECURE_NO_WARNINGS
を使うやり方と

コード:

        strcpy_s(title, t);
	strcpy_s(author, name);
	number = num;
どちらもうまく行きました。

率直に申しあげますと、stringを使った方法が気になっております。
Bull さんが書きました:
6年前
オフトピック
C++なら std::string を使いましょうという話になりそうですが、それはまあ置いておいて
プロジェクトのプロパティで[C/C++]→[すべてのオプション]→[その他のオプション]に /Zc:strictString が指定されていると思われますが、前に書いたように、このオプションはデフォルトでは指定されないはずなので、指定されてなかったら私にはちょっとわかりません。
もしよろしければ、どなたかお時間のある時にコメント頂ける方いらっしゃいましたら教えてください。

尚、[その他のオプション]は空欄でした。

かずま

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#8

投稿記事 by かずま » 6年前

hands さんが書きました:
6年前

コード:

        strcpy_s(title, t);
	strcpy_s(author, name);
	number = num;
どちらもうまく行きました。
本当にうまく行きましたか?
strcpy_s は引数が 3個必要です。
https://msdn.microsoft.com/ja-jp/library/td1esda9.aspx

かずま

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#9

投稿記事 by かずま » 6年前

string を使って書くと、

コード:

#include <iostream>
#include <string>   // <-- <cstring>
using namespace std;

class card {
    string title;   // <-- char title[80];
    string author;  // <-- char author[40];
    int number;
public:
    void store(const string& t, const string& name, int num); // string
    void show();
};

void card::store(const string& t, const string& name, int num)  // string
{
    title = t;      // <-- strcpy(title, t);
    author= name;   // <-- strcpy(author, name);
    number = num;
}

void card::show() 
{
    cout << "本のタイトル: " << title << "\n";
    cout << "著者: " << author << "\n";
    cout << "冊数: " << number << "\n";
}


int main() 
{
    card book1, book2, book3;

    book1.store("Dune", "Frank Herbert", 2);
    book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
    book3.store("The Rainbow", "D.H.Lawrence", 1);

    book1.show();
    book2.show();
    book3.show();

    return 0;
}

アバター
tk-xleader
記事: 158
登録日時: 13年前
連絡を取る:

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#10

投稿記事 by tk-xleader » 6年前

かずま さんが書きました:本当にうまく行きましたか?
strcpy_s は引数が 3個必要です。
https://msdn.microsoft.com/ja-jp/library/td1esda9.aspx
VisualC++ では、C++向けに

コード:

template<std::size_t N>errno_t strcpy_s(char(&)[N],const char*);
というシグネチャのstrcpy_sがオーバーロードされるのでcharの固定長配列であれば引数2個で大丈夫です。

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#11

投稿記事 by hands » 6年前

かずまさん、strcpy_sについて教えてくださりありがとうございます。またstringを使った書き方も知ることができて嬉しいです。

tk-xleaderさんにもその知識の深さには感服致します。皆さん本当にありがとうございます。

最後に一つだけ、お聞きしたいのですが、かずまさんが書かれたコードにある
かずま さんが書きました:
6年前
public:
void store(const string& t, const string& name, int num); // string
void show();
};

void card::store(const string& t, const string& name, int num) // string
{
title = t; // <-- strcpy(title, t);
author= name; // <-- strcpy(author, name);
number = num;
}
例えばconst string& tという部分のtは参照オブジェクトでよろしいのでしょうか。

この場合、何を何で初期化してるのでしょうか、titleをtで初期化でしょうか、それとも代入でしょうか。

見当はずれな問いでしたらすみません。

かずま

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#12

投稿記事 by かずま » 6年前

hands さんが書きました:
6年前
例えばconst string& tという部分のtは参照オブジェクトでよろしいのでしょうか。

この場合、何を何で初期化してるのでしょうか、titleをtで初期化でしょうか、それとも代入でしょうか。
「参照オブジェクト」という用語が私には理解できません。

const string& t と仮引数宣言された t は参照です。
メンバ関数 store の呼び出し元に stringオブジェクトが存在し、
そのオブジェクトを参照します。

title = t; により、呼び出し元の stringオブジェクトの値が
title に代入(コピー)されます。

呼び出し元は、
book1.store("Dune", ...
となっていて、
"Dune" は stringオブジェクトではないので、
ここで、string(const char *) というコンストラクタにより
一時的な stringオブジェクトが生成されてから
store が呼ばれます。

void store(string t, string name, int num); と宣言しても
プログラムは正しく動きます。
この場合、t は参照ではなく、stringオブジェクトです。
呼び出し時に string(const char *) コンストラクタで
t が初期化され、
title = t; により、t の値が title に代入されます。

呼び出し元が
string dune = "Dune";
book1.store(dune, ...
となっているとしたら、
const string& t の場合、t は dune そのものですが、
string t の場合、t は
コピーコンストラクタstring(const string&) により
dune のコピーとして初期化されます。

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#13

投稿記事 by hands » 6年前

かずまさん 詳しく教えてくださりありがとうございます。

まず、参照オブジェクトについてですが、新版明解C++入門編(柴田望洋著)に int& a = x; で型名の後ろに&を付けて宣言された変数aが参照オブジェクトです。と記述があります。参照について学習するページ内で数回、参照オブジェクトなる語が使われている為、一般的な表現かと思い使用しましたが、著書のなかでもキーワードとして太字で書かれてはおらず、また巻末の索引にもそうした語がないことから、著者独自の表現なのかも知れません。質問の意図が捉えにくくなった点、お詫びします。

 ご回答頂いた内容ですが、初めて日が浅いためか一読した限りではなかなか理解できず、薄っすら「そうなんだ…」という感じでしたが、十数回(数えてないですけど)読んでようやく理解できたかなというところに達しましたので、今後勉強を続けながら確認していこうと思います。
 あと、void store(string t, string name, int num); の方も試してちゃんと動くことを確認できました。それまではconst をつけないとエラーがでるんじゃないの?と思い込んでました。私はこの書き方が一番好きですね。


 おかげさまで無事エラーも消せ、原因とその背景にある仕組みまで、私にとってはたいへん貴重な意見をいくつも伺うことができました。改めてお世話になりました皆さんにお礼申し上げます。細かい点においては未だ不明な箇所はありますが、疑問は学習する限り尽きることはないでしょうから、いたずらに長引かせるぬよう、本トピックはここいらで閉めさせていただればと思います。ありがとうございました。

naohiro19
記事: 256
登録日時: 13年前
住所: 愛知県

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#14

投稿記事 by naohiro19 » 6年前

<sstream>ヘッダーの std::stringstream というクラスを使えば

コード:

std::stringstream ss;
ss << "野原" << "一家";
std::string result = ss.str();
とすることで result には「野原」と「一家」が連結した状態でresultには「野原一家」いう文字列が入ります。

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#15

投稿記事 by hands » 6年前

naohiro19 さん stringstreamの情報をくださりありがとうございました。

また、別課題にあたっていたため、しばらく放置となったこと大変失礼いたしました。

そちらが一段落しましたので、コードをかいてみましたが、何分初心者でstringstreamはまったく存じ上げないばかりか、
そもそもクラスについてすら十分に把握できてないといったレベルですから、ちゃんと教えていただいたstringstreamが使えているのかがかなり怪しいです。

コードを載せますので、もし違っていれば正して頂けましたら参考になります。

コード:

// stringstream を使えば
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

class card {
	stringstream title;
	stringstream author;
	int number;
public:
	void store(string t, string name, int num);
	void show();
};

void card::store(string t, string name, int num)
{
	title.str (t);
	author.str (name);
	number = num;
}

void card::show()
{
	cout << "本のタイトル: " << title.str() << "\n";
	cout << "著者: " << author.str() << "\n";
	cout << "冊数: " << number << "\n";
}


int main()
{
	card book1, book2, book3;

	book1.store("Dune", "Frank Herbert", 2);
	book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
	book3.store("The Rainbow", "D.H.Lawrence", 1);

	book1.show();
	book2.show();
	book3.show();

	return 0;
}

かずま

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#16

投稿記事 by かずま » 6年前

string の代わりに stringstream を使うのは、やめたほうがいいでしょう。

コード:

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

struct card1 {
	char title[80];
	char author[40];
	int number;
};

struct card2 {
	string title;
	string author;
	int number;
};

struct card3 {
	stringstream title;
	stringstream author;
	int number;
};

int main()
{
	cout << "sizeof(card1) = " << sizeof(card1) << "\n";
	cout << "sizeof(card2) = " << sizeof(card2) << "\n";
	cout << "sizeof(card3) = " << sizeof(card3) << "\n";
}
実行結果

コード:

VC++ x86 (32ビット)
sizeof(card1) = 124
sizeof(card2) = 52
sizeof(card3) = 360

VC++ x64 (64ビット)
sizeof(card1) = 124
sizeof(card2) = 72
sizeof(card3) = 504

cygwin g++ (GCC) 6.4.0
sizeof(card1) = 124
sizeof(card2) = 24
sizeof(card3) = 744

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
sizeof(card1) = 124
sizeof(card2) = 72
sizeof(card3) = 792

hands
記事: 14
登録日時: 6年前

Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません

#17

投稿記事 by hands » 6年前

メモリ消費の観点からコードを記述した方が良さそうですね

返信

“C言語何でも質問掲示板” へ戻る