スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

C++のstd::cinを思い通りに動作させる。

参考サイト様: http://takagi.in/modules/cpp_guide5/index.php?id=7



散々悩んだstd::cinのoperator>>とgetlineの使い分け…
しかしそれはC言語よりの使者、「char[]」によりあっけなく解決いたしました。

もうstd::cinの1行取得が我々を悩ませる必要はありません!!


だめな例
std::string line;
std::getline(std::cin, line); // aa bb と入力
std::string hoge;
std::cin >> hoge; // 入力すっとばされて「bb」

これはstd::cinによる入力時に
バッファが現地点から空白前までしか読み飛ばされないからです。
つまりgetlineをした時点で、std::string lineは「aa bb」になりますが、
バッファには「aa 」まで読み飛ばしたまでも「bb」が残ります。

そして次の入力待ち「std::cin >> hoge;」(いわゆるoperator>>)が
バッファに残った「bb」を「なんだ、もう既に入力されてるじゃん」と解釈され、
入力スキップされます。(hogeは"bb"になる)

解決方法
char cline[1023];
std::cin.getline(line, sizeof(line)); // aa bb と入力
std::string line(cline); // 内容をstd::stringに持ち直し
std::string hoge;
std::cin >> hoge; // 入力待機

std::getlineとstd::cin.getlineは同じものと思っておいてください。
(少なくともここでは)

これでなぜ入力スキップされないのでしょうか…?
それはstd::cin.getline(line, sizeof(line))で
std::cinに明示的に「sizeof(line)分読み飛ばしてね」と命令しているからです!!

空白とか関係ありません、sizeof(line)分きっかり読み進めるからです。

最後に「cline」はchar[]型なのでstd::stringに持ち直しています。


以上!



あいやはプログラミング仲間を探しています。
スポンサーサイト

私だけ!? VC++のfstreamの挙動の話

今回バイナリを読みつつ一部を書き換える、というコードを組んだのですが、
fstreamヘッダにあるfstreamクラスを使用する場合におかしな挙動があったのでここに残しておきます。

環境
Windows7 64bit
Visual Studio 2012


単刀直入に言うと
fstream#read関数を使った後にfstream#write関数が使えない!

例えばこうですね。
std::fstream patch("Hoge.dat", std::ios::in|std::ios::out|std::ios::binary);
while(true){
int compare;
patch.read( (char*)&compare, sizeof(int) );
if(compare == 0x0A){
int hex = 0x0B;
patch.write( (char*)&hex, sizeof(int) );
}
if(patch.fail()) break;
}


Hoge.datの中に0x0Aという価を見つけた時に、次の価を0x0Bで上書きする例です。
この場合私の環境ではwrite関数を呼び出しているにもかかわらず上書きがなされない(元の価のまま)という挙動を起こしました。

うーん、私だけなのかな…。

なお、このパターンでは適用できませんが、
fstream#seekg関数を使用してからのwrite関数ならばうまく書き込んでくれました。


gccでコンパイルしたバイナリなら普通に動きました。
早くVisualStudio2013を使え…ということでしょうか。


以下実際のコード垂れ流しです。
/*-- ヘッダの一部 --*/
enum Items {
NORMAL = 0x0a,
BURST = 0x0b,
SHOTGUN = 0x0c,
MACHINEGUN = 0x0d,
TIME_STOP = 0x0e,
CLOCK_DOWN = 0x0f
};

typedef int bin_t;
static const size_t BIN_SIZE = sizeof(bin_t);
static const int ENCRYPT_NUMS[];

/*-- cpp --*/
const int ItemHelper::ENCRYPT_NUMS[] = { 10, 2, 5, 8, 12, 3 };

void ItemHelper::writeItemStatus(Items index, bool flag){
std::fstream rewrite(ITEM_FILE, std::ios::in|std::ios::out|std::ios::binary);
//bool found = false;

//while(true){
// bin_t comp;
// rewrite.read( (char*)&comp, BIN_SIZE );
// if(rewrite.fail()) break;

// if( comp == (bin_t)index ){
// // データの書き出し
// bin_t encryptValue = (bin_t)( (int)flag * ENCRYPT_NUMS[index-0x0a] ); // 暗号化
// rewrite.write( (char*)&encryptValue, BIN_SIZE );

// found = true;
// break;
// }else{
// // 読み飛ばし
// rewrite.read( (char*)&comp, BIN_SIZE );
// }
//}

//if(!found)
// throw std::string("Index Not Found in Binary");

/* 動かんので妥協策 */
rewrite.seekg( BIN_SIZE*( ((int)index-0x0a)*2+1 ));
bin_t encryptValue = (bin_t)( (int)flag * ENCRYPT_NUMS[index-0x0a] );
rewrite.write( (char*)&encryptValue, BIN_SIZE);
}

フィールドにメンバ関数を参照する関数ポインタを含める

毎度恒例、なんかあいやさんがつぶやいてるだけの記事です。
下から上へ読んでいってください…。(手抜きごめんなさい)
あ、コピペにはTweetVim使ってます。

参考にさせていただいたサイト様
http://www.geocities.jp/ky_webid/cpp/language/034.html


13 -------------------------------------------------------------------------------------------------- 14 aiya_000 : いらんかもしれないけどメンバ関数ポインタ変数のコールバックです。
15 https://t.co/QHgmvzq77w 05:47
16 -------------------------------------------------------------------------------------------------- 17 aiya_000 : ということで、
18 「あいやはまた一歩進化を遂げた!!」 05:44
19 -------------------------------------------------------------------------------------------------- 30 aiya_000 : 余談だけどクラスや構造体(C++)に列挙体を含んだ場合、
31 staticにしなくとも勝手にHoge.Aとかいうアクセスの仕方ができる。
32 staticつけてもできる。 05:40
33 -------------------------------------------------------------------------------------------------- 34 aiya_000 : このstatic修飾子は「enum Foo」ではなく、フィールド「m_enum」に掛かる。 05:39
35 -------------------------------------------------------------------------------------------------- 36 aiya_000 : これは
37 struct Hoge {
38 static enum Foo {
39 A, B, C
40 } m_enum;
41 };
42 とした場合の「static」の掛かり方に似ているね。 05:39
43 -------------------------------------------------------------------------------------------------- 44 aiya_000 : するとすれば
45 *ins.p
46 という表現になる。
47 もちろんこの場合の間接アクセス演算子「*」は「p」にかかっている。
48 「ins.p」自体がins内のpを表しているので、
49 *insの中のp変数を表すことにはならない。 05:36
50 -------------------------------------------------------------------------------------------------- 51 aiya_000 : .*演算子と->*演算子を勘違いしていたよ。
52 これらは
53 インスタンスinsがメンバ*pを持つ場合の表現「ins.*p」ではなかったんだね、
54 この表現はできない。「.*演算子」自体が特別な役割を持っているから。 05:35
55 -------------------------------------------------------------------------------------------------- 56 aiya_000 : ああ、できた。 05:33
57 -------------------------------------------------------------------------------------------------- 58 aiya_000 : うーん、メンバ関数からメンバ関数ポインタ変数にアドレスを取ってこれないなあ。
59 うーん。 04:51
60 -------------------------------------------------------------------------------------------------- 61 aiya_000 : ラムダ式型を代入できなければ、
62 voidを列挙すればいい。
63 それができる、オブジェクト指向ならね。 http://t.co/Rg54n0iscn 04:23

C++のラムダ式でクロージャ

なぜかGoogle先生で「C++ クロージャ」を検索してもあまり簡易な説明が出てこなかったので、
「簡易な説明」を書こうと思いましたよ。

ここは「クロージャ」の概念を何か勘違いした筆者の恥晒しの場です。
鵜呑みにしないでください。


なおクロージャとは「レキシカルなスコープを持つ関数」のことです。
int main(){
int i = 10;
auto func = [&](){ return i+i; };
}

int main(){
int i = 10;
auto func = [&](){ i = 20; };
}

このような「関数の外界に干渉や読み取りを行うことのできる関数」を言います。
(ちなみにC++での参照キャプチャは推奨されていません。)




以下鵜呑みにしてはいけないゾーン。




この記事でわかること
・C++でのクロージャの方法(簡易)
・C++でのラムダ式の使い方(簡易)


クロージャ、これだけです。
int main(){
int i = []{ return 10; }();
cout << i << endl; // 10
}



Oh, The Closure...
It's so Beautiful...。



参考にさせていただいたサイトは
http://cpplover.blogspot.jp/2009/11/lambda.html
様です。
ありがとうございます!


以下ラムダ式のなんとなく的補足。

[]{
/* 処理 */
};

がラムダ式と言われるもので、
しばしば無名関数と呼ばれます。
つまり関数です。
これに「()」をつけることで実行してます。
関数だって()つけると実行されるじゃん。ねっ。

[]{
cout << "これでこれが出力されます。" << endl;
}();

ねっ☆

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。