Home > C++ Archive

C++ Archive

Visual Studio デバッグ中のウォッチウィンドウにおける配列ウォッチ方法の一検討

ということで、前にも書いたような気がするけど探せなかったのでメモします。
Visual Studioでデバッグ中、ウォッチウィンドウに配列の名前を入力するとその配列の中身が見えるんですが、ポインタの場合は見られない。ポインタの先が配列でもダメ。


int a[10];     // 「a」で見られる
int *b;
b = a;         // 「b」だとアドレスが見られるだけ

b[0]とかb[1]とかウォッチウインドウに入れればその値は見られるけど配列としてざーっとは見られない。
そんなときには以下です!


b,10

と入力すればサイズ10の配列と解釈して表示してくれるのです!!ばばーん!

というわけで他愛もないメモでした。

以上

C++覚え書き

  • 2010-04-03 (土)
  • C++

北斗無双中です。

最近覚えたC++のメモ。

1.placement new
普通のnewはヒープからメモリ領域を取ってくるが、placement newはすでにある領域にコンストラクタを適用するためのものっぽい。


class Hoge
{
public:
    int fuga;
    Hoge(){}
    Hoge(int val) {
        fuga = val;
    }
};

int main(int argc, char *argv[])
{
    Hoge a;
    Hoge *b;
    b = new(&a) Hoge(100);
    std::cout << b->fuga << std::endl;
    std::cout << a.fuga << std::endl;
    return 0;
}

100
100

となる。


new(メモリ領域のアドレス) コンストラクタ;

クラスの配列の各要素に引数付きコンストラクタを適用したいときとかに使えるな。
参考:http://marupeke296.com/TIPS_No13_ClassArrayInitialize.html

2.テンプレートに数字を渡す
普通はtypenameで型を渡すが数字も渡していいらしい。


template <int n>
int comp(const void *a, const void *b)
{
   const int *na = static_cast<const int*>(a);
   const int *nb = static_cast<const int*>(b);
   if (n == 0) {
      return *na - *nb;
   } else {
      return *nb - *na;
   }
}
int main(int argc, char argv[]) {
   int data[] = {0,1,2,3,4,5,6,7,8,9};

   qsort(data, sizeof(data)/sizeof(int), sizeof(int), comp<1>);
   for (int i = 0; i < sizeof(data)/sizeof(int); i++) {
      std::cout << data[i] << ",";
   }
   std::cout << std::endl;

   qsort(data, sizeof(data)/sizeof(int), sizeof(int), comp<0>);
   for (int i = 0; i < sizeof(data)/sizeof(int); i++) {
      std::cout << data[i] << ",";
   }
   std::cout << std::endl;

   return 0;
}

9,8,7,6,5,4,3,2,1,0,
0,1,2,3,4,5,6,7,8,9,

マクロみたいなもんだな。これは便利かも知らん。

以上

3つ以上の整数の最小公倍数を求める

2つの数の最大公約数を求める→2つの数の最小公倍数を求める。
求めた最小公倍数と次の数の最小公倍数を同じ手順で求める。
繰り返す。

こんな感じ?

・ユークリッドの互除法で2つの数の最大公約数を求める関数


int gcm(int a, int b) {
	int result = a;
	int k = 0;
	int n = b;
	do {
		k = result % n;
		result = n;
		n = k;
	} while(k != 0);
	return result;
}

・最大公約数を利用して2つの数の最小公倍数を求める関数


int lcm(int a, int b) {
	int g;
	g = gcm(a, b);
	return a*b/g;
}

・2つの数の最小公倍数を順次求めて3つ以上の数の最小公倍数を求める関数


int lcm_n(vector<int> &numbers) {
	int l;
	l = numbers[0];
	for (int i = 1; i < numbers.size(); i++) {
		l = lcm(l, numbers[i]);
	}
	return l;
}

悔しいからここに書く。

以上

VC2008のバッファオーバーラン?

なぜかエラーにならない。


void overrun(void) {
	int i = -3;
	int test[100];

	test[i] = 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
	overrun();

	return 0;
}

2003くらいだとエラーになる。/GSオプション入れとけばエラーが出ることもあるけど、どこでエラーなのか分からない。大丈夫か2008!

以上

std::getline

  • 2008-12-08 (月)
  • C++

std::getlineってよく使い方分からないんだけど、どうなんだ。fstreamのgetlineも同じ話だと思うけど、いつeofになるのか。たぶん最後まで読み込んだ時点ではeofにならない。その次にgetlineしたときに何も読み込めなくて、eofになるんじゃないかなあ。
なので、



 std::ifstream ifs("hoge.txt");
 std::string line;
 while (!ifs.eof()) {
      std::getline(ifs, line);
      std::cout << line << std::endl;
  } 

こんな感じにすると最後空文字列が出力される気がする。というわけで下のようにしてる。


 std::ifstream ifs("hoge.txt");
 std::string line;
 while (true) {
      std::getline(ifs, line);
      if (ifs.eof()) break;
      std::cout << line << std::endl;
  } 

追記(2009/04/13):
ってやってたんだけども上記はバグ。最後の行に改行がない場合、lineに読み込めていてもifs.eof()がtrueを返すので最後の行を出力する前にbreakしてしまう。
正しくは下記。(匿名さんの投稿より)


std::ifstream ifs("hoge.txt");
std::string line;
while ( std::getline(ifs, line)) {
   std::cout << line << std::endl;
}

getlineはifsの参照を返すのでその状態を調べるという。入出力ストリーム(basic_ios)は!演算子をオーバーロードしていて、「!ifs」などでfail()とかそういうのを呼び出してくれるので


if(!ifs) {
}

って感じで状態を調べられる。上記では!演算子ではなくvoid*型への変換演算子を用いて状態を判断している。
匿名さん、ありがとう。

以上

あれ?joinなくね?

  • 2008-10-17 (金)
  • C++

C++ってjoinないんじゃない?あるの?というわけで、あるのかどうかよく知らないけど、テンプレートを思い出すために作った。


/* イテレータ::value_typeでイテレータが示す要素の型を取れる。
 * ただし、typenameをつけておかないとコンパイラに「なんのこっちゃ?」って怒られる。
 */
template< typename InIt >
typename InIt::value_type join(InIt begin, InIt end, typename InIt::value_type sep)
{
	typename InIt::value_type result;

	for (InIt it = begin; it < end; it++) {
		result += *it;
		if (it + 1 < end) result += sep;
	}
	return result;
}

int main(int argc, char* argv[])
{
	std::vector<std::string> a;
	a.push_back("abc");
	a.push_back("def");
	a.push_back("ghi");

	std::string a_joined(join(a.begin(), a.end(), ":"));
	std::cout << a_joined << std::endl;

	std::vector<std::wstring> b;
	b.push_back(L"abc");
	b.push_back(L"def");
	b.push_back(L"ghi");

	std::wstring b_joined(join(b.begin(), b.end(), std::wstring(L":")));
	std::wcout << b_joined << std::endl;

	return 0;
}

abc:def:ghi
abc:def:ghi

こんなんでいいのかしら?まあ、上記レベルでは使えたからいいや。
そんなことよりwstringってwcoutで表示できるのかー。

以上

2008-10-17 : 修正
value_typeを使うようにした。

簡単なことが実はできてない

例えばnCrをどうやって計算するか。私は素直なので以下のようにやってしまいます。


int nPr(int n, int r)
{
    int retval = 1;
    if (n < r) return 0;
    for (int i = n; i > (n-r); i--) {
        retval *= i;
    }
    return retval;
}

int nCr(int n, int r)
{
    return nPr(n, r)/nPr(r, r);
}

数学的には上のような感じでいいはず(nとかrの不正値について無視すれば)。でもこれだとオーバーフローするらしいのです。速攻で。まあ、そりゃそうかも。階乗だし。例えばrを10にしたら分母のnPr(r,r)がもうオーバーフローします。なのでnCr(10,10)なんて簡単に1になることが分かるのに、計算できないわけです。まあ、この例ならnCr(10,10)=nCr(10,0)=1って計算しろよ、なんですが、まあすぐオーバーフローすると。で、どうしたらいいかというと漸化式で計算すればいいらしいです。


int nCr(int n, int r)
{
    int retval = 1;
	for (int i = 1; i < r; i++) {
		retval = retval * (n-i+1)/i;
	}
	return retval;
}

プログラムって微妙に数学と違うところが難しい。

以上

VC++でデバッグ出力してソースの特定行へ飛ぶ

VCでコンパイルエラーになると出力ウィンドウにメッセージが表示されて、そこをマウスでダブルクリックすると対応行へ飛ぶことができる。
これを自分でもやりたいときどうしたらいいのかと少し悩んだが、エラーメッセージの書式を同じにしたらできた。
OutputDebugString()で以下のような書式で出力すればよい。


ソースファイルパス(行番号) : メッセージ

つまり以下のような感じ。


#include <windows.h>
void myOutputDebugString(LPCTSTR format, ...)
{
    TCHAR errorMsg[1024];

    va_list vargs;
    va_start(vargs, format);
    wvsprintf(errorMsg, format, vargs);
    OutputDebugString(errorMsg);
    va_end(vargs);
}

#define JumpMessage(x) myOutputDebugString(_T("%s(%d) : %s\n"), _T(__FILE__) , __LINE__, (x))

int main(int argc, char *argv[]) {
   JumpMessage(_T("test"));
   return 0;
}

VC6とVC2008ではちゃんと動くことを確認した。デバッグにちょっと便利かも。

以上

C++ ランダムソート 1

C++でファンクタだけでランダムソートを作ろうとちょっとがんばってみたけどだめだった。


template< typename T >
class RandomSorter {

public:
    RandomSorter(){}

    bool operator()(T a, T b) {
        int seedA = 0;
		int seedB = 0;
		int memorySize;
		int randA;
		int randB;

		memorySize = std::min(sizeof(T), sizeof(int));

		memcpy(&seedA, &a, memorySize);
		memcpy(&seedB, &b, memorySize);

		srand(seedA);
		randA = rand();
		srand(seedB);
		randB = rand();

		return randA < randB;
    }
};

引数のa, bを無理やりint型に当てはめて、その値でsrand()することで乱数の値を一定にし、最後の比較をソート処理全体で矛盾が生じないようにしたつもりなんだけども、どうもsrand()のシードの大小とその結果作成されるrand()の大小が一致するようだ。例えばTがint型だったらseedA = a, seedB = bとなるわけだが、ほとんどの場合でseedA > seedB ⇒ randA > randBとなる(VS2008の場合)。したがって意図したようなソートにならない。もう一工夫必要なのか。

以上

ブレークポイントの罠

  • 2008-07-19 (土)
  • C++

VC++で条件をつけるとブレークポイントが意外と重い。
例えば下のような単純なコード


int val = 0;
for (int i = 0; i < 1000000; i++) {
	val++;
}

デバッグモードで実行しても一瞬で終わるけど、例えばval++のところにブレークポイントをつけて条件にval == 1000001とかってやるとすごく遅くなる。これに気づかず、ちょっとはまったゆえ。

以上

Home > C++ Archive

Search
Feeds
Meta
 合計:064749
 今日:0162 昨日:0165

Return to page top