C++のbeginについて

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

C++のbeginについて

#1

投稿記事 by guraido » 1ヶ月前

初投稿です。至らない点があったらごめんなさい
[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言語を理解しているか
   今月始めたばかりで知識量は全然ありません・・・

 ・ライブラリを使っている場合は何を使っている
  ライブラリは使っていないです

アバター
tk-xleader
記事: 145
登録日時: 7年前
住所: 関西某所
連絡を取る:

Re: C++のbeginについて

#2

投稿記事 by tk-xleader » 1ヶ月前

std::begin関数が返してくるのはstd::string::iteratorですので、デリファレンスしてから文字定数と比較します。
ですから、

コード: 全て選択

auto iter = begin(A);
if(*iter == 'a' /*<- ここでデリファレンスして、"文字"定数と比較する。*/) cout<< ...(以下省略)
と書くことになります。

Rei

Re: C++のbeginについて

#3

投稿記事 by Rei » 1ヶ月前

間違いは二か所ですね。まずエラー文

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";
}
さて、最後に身もふたもない話をします。そもそもやりたかったことは「文字列の一文字目がaなのか調べる」ことでしたが、それだったらわざわざbegin()なんぞ使わなくても「A[0]」、これだけで十分です。

コード: 全て選択

#include<iostream>
#include<string>

using namespace std;
int main() {
	string A;
	cin >> A;
	if (A[0] == 'a')cout << "先頭の文字はaでした" << "\n";
}
お疲れさまでした。

guraido
記事: 2
登録日時: 1ヶ月前

Re: C++のbeginについて

#4

投稿記事 by guraido » 1ヶ月前

tk-xleaderさん、Reiさん、お二方ともご丁寧な解説本当にありがとうございます。
おかげ様で理解することができました!

かずま

Re: C++のbeginについて

#5

投稿記事 by かずま » 1ヶ月前

おまけ

コード: 全て選択

#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";
}
A が "" のとき A.data() はまずいかも。

かずま

Re: C++のbeginについて

#6

投稿記事 by かずま » 1ヶ月前

かずま さんが書きました:
1ヶ月前
A が "" のとき A.data() はまずいかも。
まずいのは、A.at(0) でした。
out_of_range 例外を投げます。

返信

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