初投稿です。至らない点があったらごめんなさい
[1] 質問文
[1.1] 自分が今行いたい事は何か
C++とbegin関数を利用することにより入力された文字の先頭がaだった時に「先頭の文字はaでした」と出力するプログラムを組みたい
[1.2] どのように取り組んだか(プログラムコードがある場合記載)
#include<iostream>
#include<string>
using namespace std;
int main() {
string A;
cin >> A;
auto n = begin(A);
if (n=="a")cout << "先頭の文字はaでした" << "\n";
}
[1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
E0349 これらのオペランドと一致する演算子"=="はありません
C2678 二項演算子 '==': 型 'std::_String_iterator<std::_String_val<std::_Simple_types<_Ty>>>' の左オペランドを扱う演算子が見つかりません (または変換できません) (新しい動作; ヘルプを参照)
[1.4] 今何がわからないのか、知りたいのか
まず、このエラー文はどのようなことを意味するのか。次になぜif(n=="a")で==が使えないのか。また、代わりにどのようなプログラムを記述すればよいのか。
[2] 環境
[2.1] OS
windows10
[2.2] コンパイラ名
visual studio 2017
[3] その他
・どの程度C言語を理解しているか
今月始めたばかりで知識量は全然ありません・・・
・ライブラリを使っている場合は何を使っている
ライブラリは使っていないです
C++のbeginについて
- tk-xleader
- 記事: 158
- 登録日時: 14年前
- 連絡を取る:
Re: C++のbeginについて
間違いは二か所ですね。まずエラー文
E0349 これらのオペランドと一致する演算子"=="はありません
C2678 二項演算子 '==': 型 'std::_String_iterator<std::_String_val<std::_Simple_types<_Ty>>>' の左オペランドを扱う演算子が見つかりません (または変換できません) (新しい動作; ヘルプを参照)
の意味ですが、まず「オペレータ」と「オペランド」の話をします。
オペレータは日本語で「演算子」といい、その名の通り演算を表す記号のことです。この場合は「==」がオペレータで、これは「右辺と左辺が等しいか調べる演算」を行うものですね。
一方オペランドは「被演算子」といい、こちらは演算される側の記号を指します。この場合は「n」と「"a"」ですね。
エラー文「これらのオペランドと一致する演算子"=="はありません」は、つまり「『==』を使って『n』と『"a"』を比べることはできないよ」と言っているわけです。ではなぜ比べられないのでしょうか?
それにはbegin()の機能を説明する必要があります。恐らくguraidoさんはbegin()が「文字列の先頭の文字を返す関数」だと思われていたのだと思いますが、まずここに誤解があります。begin()は文字列の先頭の文字への「イテレータ」を返す関数です。
C言語は今月勉強を始めたばかりとのことですが、「ポインタ」はもう勉強されたでしょうか?ここでは詳しい説明は避けますが「イテレータ」は「ポインタ」の拡張概念で、かみ砕いた言い方をするならbegin()で返ってきて「n」に代入されたものは文字列の先頭の文字の「住所」を表しているのです。こうなってくると「n == "a"」という式は、かたや「住所」、かたや「文字」を比べようとしているわけですから、「==」が「おいおい、そんなもんどうやって比べればいいんだよ」と文句を言っているわけですね。それでエラーが返ってきたわけです(ほかにももう一つエラーの原因はありますが)。
「==」には「文字」と「文字」を比較する仕事をしてほしいわけですから、ここでは「(nが表す住所に住んでいる文字) == "a"」という式にする必要があります。それはどうすればいいのかといえば簡単で、「n」のかわりに「*n」と書いてやればいいのです。
ただ、このように修正してもまだエラーが返ってくると思います。多分こんな感じのエラーだと思います。
オペランド型に互換性がありません ("char" と "const char *")
C言語のややこしいところが「文字」と「文字列」は違うものだということです。上のエラー文は要するに「『文字』(char型変数)と『文字列』(char*型変数)を『==』で比較することはできない」といっているのです。
「え?"a"って一文字じゃん、どこが『文字列』なんだよ」と思われるかもしれませんが、C言語では「シングルクォーテーション」(これ→ ' )で囲まれたものは「文字」、「ダブルクォーテーション」(これ→ " )で囲まれたものは「文字列」として扱われます。
もうお分かりですよね。「"a"」が文字列として扱われてしまっていた理由はダブルクォーテーションで囲まれていたからなんですね。なのでこれをシングルクォーテーションで囲みなおしてプログラムは完成です。
さて、最後に身もふたもない話をします。そもそもやりたかったことは「文字列の一文字目がaなのか調べる」ことでしたが、それだったらわざわざbegin()なんぞ使わなくても「A[0]」、これだけで十分です。
お疲れさまでした。
E0349 これらのオペランドと一致する演算子"=="はありません
C2678 二項演算子 '==': 型 'std::_String_iterator<std::_String_val<std::_Simple_types<_Ty>>>' の左オペランドを扱う演算子が見つかりません (または変換できません) (新しい動作; ヘルプを参照)
の意味ですが、まず「オペレータ」と「オペランド」の話をします。
オペレータは日本語で「演算子」といい、その名の通り演算を表す記号のことです。この場合は「==」がオペレータで、これは「右辺と左辺が等しいか調べる演算」を行うものですね。
一方オペランドは「被演算子」といい、こちらは演算される側の記号を指します。この場合は「n」と「"a"」ですね。
エラー文「これらのオペランドと一致する演算子"=="はありません」は、つまり「『==』を使って『n』と『"a"』を比べることはできないよ」と言っているわけです。ではなぜ比べられないのでしょうか?
それにはbegin()の機能を説明する必要があります。恐らくguraidoさんはbegin()が「文字列の先頭の文字を返す関数」だと思われていたのだと思いますが、まずここに誤解があります。begin()は文字列の先頭の文字への「イテレータ」を返す関数です。
C言語は今月勉強を始めたばかりとのことですが、「ポインタ」はもう勉強されたでしょうか?ここでは詳しい説明は避けますが「イテレータ」は「ポインタ」の拡張概念で、かみ砕いた言い方をするならbegin()で返ってきて「n」に代入されたものは文字列の先頭の文字の「住所」を表しているのです。こうなってくると「n == "a"」という式は、かたや「住所」、かたや「文字」を比べようとしているわけですから、「==」が「おいおい、そんなもんどうやって比べればいいんだよ」と文句を言っているわけですね。それでエラーが返ってきたわけです(ほかにももう一つエラーの原因はありますが)。
「==」には「文字」と「文字」を比較する仕事をしてほしいわけですから、ここでは「(nが表す住所に住んでいる文字) == "a"」という式にする必要があります。それはどうすればいいのかといえば簡単で、「n」のかわりに「*n」と書いてやればいいのです。
ただ、このように修正してもまだエラーが返ってくると思います。多分こんな感じのエラーだと思います。
オペランド型に互換性がありません ("char" と "const char *")
C言語のややこしいところが「文字」と「文字列」は違うものだということです。上のエラー文は要するに「『文字』(char型変数)と『文字列』(char*型変数)を『==』で比較することはできない」といっているのです。
「え?"a"って一文字じゃん、どこが『文字列』なんだよ」と思われるかもしれませんが、C言語では「シングルクォーテーション」(これ→ ' )で囲まれたものは「文字」、「ダブルクォーテーション」(これ→ " )で囲まれたものは「文字列」として扱われます。
もうお分かりですよね。「"a"」が文字列として扱われてしまっていた理由はダブルクォーテーションで囲まれていたからなんですね。なのでこれをシングルクォーテーションで囲みなおしてプログラムは完成です。
#include<iostream>
#include<string>
using namespace std;
int main() {
string A;
cin >> A;
auto n = begin(A);
if (*n == 'a')cout << "先頭の文字はaでした" << "\n";
}
お疲れさまでした。
Re: C++のbeginについて
tk-xleaderさん、Reiさん、お二方ともご丁寧な解説本当にありがとうございます。
おかげ様で理解することができました!
おかげ様で理解することができました!
Re: C++のbeginについて
おまけ
A が "" のとき A.data() はまずいかも。
#include<iostream>
#include<string>
using namespace std;
int main()
{
string A;
cin >> A;
if (A[0] == 'a') cout << " A[0] == 'a'\n";
if (A.at(0) == 'a') cout << " A.at(0) == 'a'\n";
if (*begin(A) == 'a') cout << " *begin(A) == 'a'\n";
if (*A.begin() == 'a') cout << " *A.begin() == 'a'\n";
if (*cbegin(A) == 'a') cout << " *cbegin(A) == 'a'\n";
if (*A.cbegin() == 'a') cout << " *A.cbegin() == 'a'\n";
if (*A.data() == 'a') cout << " *A.data() == 'a'\n";
if (A.data()[0] == 'a') cout << " A.data()[0] == 'a'\n";
if (*A.c_str() == 'a') cout << " *A.c_str() == 'a'\n";
if (A.c_str()[0] == 'a') cout << " A.c_str()[0] == 'a'\n";
if (rend(A)[-1] == 'a') cout << " rend(A)[-1] == 'a'\n";
if (crend(A)[-1] == 'a') cout << " crend(A)[-1] == 'a'\n";
if (A.rend()[-1] == 'a') cout << " A.rend()[-1] == 'a'\n";
if (A.crend()[-1] == 'a') cout << " A.crend()[-1] == 'a'\n";
cout << "---\n";
if (A.find('a') == 0) cout << " A.find('a') == 0\n";
if (A.find("a") == 0) cout << " A.find(\"a\") == 0\n";
if (A.find_first_of('a') == 0) cout << " A.find_first_of('a') == 0\n";
if (A.find_first_of("a") == 0) cout << " A.find_first_of(\"a\") == 0\n";
cout << "---\n";
if (A.substr(0, 1) == "a") cout << " A.substr(0, 1) == \"a\"\n";
if (string(A, 0, 1) == "a") cout << " string(A, 0, 1) == \"a\"\n";
if (string(A.data(), 1) == "a") cout << " string(A.data(), 1) == \"a\"\n";
if (string(A.c_str(), 1) == "a") cout << " string(A.c_str(), 1) == \"a\"\n";
if (string(begin(A), begin(A) + 1) == "a") cout << " string(begin(A), begin(A) + 1) == \"a\"\n";
if (string(A.begin(), A.begin() + 1) == "a") cout << " string(A.begin(), A.begin() + 1) == \"a\"\n";
if (string(cbegin(A), cbegin(A) + 1) == "a") cout << " string(cbegin(A), cbegin(A) + 1) == \"a\"\n";
if (string(A.cbegin(), A.cbegin() + 1) == "a") cout << " string(A.cbegin(), A.cbegin() + 1) == \"a\"\n";
}
Re: C++のbeginについて
まずいのは、A.at(0) でした。かずま さんが書きました: ↑7年前A が "" のとき A.data() はまずいかも。
out_of_range 例外を投げます。