【初心者歓迎】C/C++室 Ver.49【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2008/02/20(水) 12:33:41ただしその場合、質問者は必ず環境を書きましょう。
※sage禁止です(と代々スレに書いてありますが自己判断で)。
【前スレ】
【初心者歓迎】C/C++室 Ver.48【環境依存OK】
http://pc11.2ch.net/test/read.cgi/tech/1202141921/
【アップローダー】(質問が長い時はココ使うと便利)
http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/joyful.htm
0285デフォルトの名無しさん
2008/02/23(土) 14:26:18実際やってみると
cuで2が、gguで3が、ijcoで4が返ってきます
これは、s[i] == cと、s[i] == 0の判定が成されていないという事ですよね?
しかし、while関数自体は終わってるので、s[i]は判定されている
どういうことなんでしょうか?
また、ご指摘を受けて、whileをdo-whileに変更しました、ありがとうございます
0286デフォルトの名無しさん
2008/02/23(土) 14:27:110287デフォルトの名無しさん
2008/02/23(土) 14:30:00てか絶対使わないようにしてるんだが、違うのか
0288デフォルトの名無しさん
2008/02/23(土) 14:31:58単なる構文糖衣じゃない。
参照の参照というのは存在しないが、
ポインタのポインタというのは存在する。
これは大きな違いで、適当な教え方してると >>207 みたいなやつが出てくる。
0289デフォルトの名無しさん
2008/02/23(土) 14:33:55むしろ使った方が綺麗になる状況では使う。
でも、上のは break; 使えば解決できることで、
goto を使って解決すべきじゃない。
0290デフォルトの名無しさん
2008/02/23(土) 14:37:52>>284
当面はあまり気にしなくてよさそうですね
どうもありがとうございました
0291デフォルトの名無しさん
2008/02/23(土) 14:39:03いいや、気にしろ。
0292デフォルトの名無しさん
2008/02/23(土) 14:42:06せいぜいクラスのテンポラリオブジェクトを作るのに関数風のキャストを使うくらい。
0293デフォルトの名無しさん
2008/02/23(土) 14:47:55それはキャストよりもコンストラクタ呼び出しのほうがしっくりくる
0294デフォルトの名無しさん
2008/02/23(土) 14:49:300295デフォルトの名無しさん
2008/02/23(土) 14:52:190296デフォルトの名無しさん
2008/02/23(土) 14:54:36すいません
気にしろとだけ言われましてもなにに気を使えばいいのかわかりません
まずい点でもでてくるのか
だとかを教えていただけませんか
0297デフォルトの名無しさん
2008/02/23(土) 14:58:130298デフォルトの名無しさん
2008/02/23(土) 14:58:20CreateWindowとCreateControlWindowはどう違いますか?
0299デフォルトの名無しさん
2008/02/23(土) 15:00:58C風のキャストはなんでもかんでもキャストできてしまうので、
プログラマの意図と違ってても警告が出ない
const void *p = 〜;
char *q = (char*)p; // charにキャスト・・・あれ? constも外しちゃったよ! でも警告は出ない
char *r = static_cast<char*>(p); // コンパイルエラー: static_castでconstは外せない
char *s = const_cast<char*>(static_cast<const char*>(p)); // constも外したい意図の場合はこう書く
0300デフォルトの名無しさん
2008/02/23(土) 15:03:54gotoのほうが行き先が明確になるので、理解しやすかったので、用いていますが
なぜ怖いのでしょうか
それと、「これは、s[i] == cと、s[i] == 0の判定が成されていないという事ですよね?
しかし、while関数自体は終わってるので、s[i]は判定されている
どういうことなんでしょうか? 」
これにも答えていただけると非常にありがたいです
0301デフォルトの名無しさん
2008/02/23(土) 15:04:05キャストというのは基本的にマズい処理。
アップキャストだけは例外的に安全だが、
それ以外は基本的にはあまりやるべきではない。
でも、実際にはどうしてもやる必要が出てくる事もある。
こればっかりは仕方が無い。
そういう時、C 風のキャストを使ってしまうと色々と問題が発生する。
・ 間違って危険なキャストをしてしまうかもしれない。
例えば、const を付けるべきところで const を付け忘れたり。
こういう時、static_cast なら危険な const の付け忘れがあるとコンパイルエラーになる。
C 風キャストだと問答無用でキャストされてしまう。
これが一番の問題。
・ キャストが原因っぽいバグが見つかった時、どこにキャストがあるのか探すのが面倒。
C++ のキャストだと検索でキャストを行っている箇所を簡単に見つけられる。
・ キャストがあまり目立たない。
危険な処理を行っている箇所が目立たないのは危険。
C++ のキャストは非常に目立つ。
・ 打鍵数が少ないので気軽にキャストをしてしまう。
C++ のキャストは打ち込むのが面倒で、キャストを本当に使うべきなのか
立ち止まって考えるよう思考を誘導してくれるかもしれない。
・ 今行おうとしているキャストはどういうものかをあまり意識しないかもしれない。
キャストという処理を軽く見ているのはよろしくない。
0302デフォルトの名無しさん
2008/02/23(土) 15:06:01gotoが必要になるのは言語の構造化能力を超えた構造が必要になる場合であって、
この場合はそういう場合でない。
0303デフォルトの名無しさん
2008/02/23(土) 15:06:12論理的に記述しようぜ。
「while を終了する」 と 「指定位置に移動する」 では
前者の方がより論理的だ。
論理的なコードは、一般に変更に強く、バグが出にくい。
まあ、break すらみだりに使うべきじゃないという人もいるけどね。
0304デフォルトの名無しさん
2008/02/23(土) 15:07:500305デフォルトの名無しさん
2008/02/23(土) 15:09:39不可能
0306デフォルトの名無しさん
2008/02/23(土) 15:10:05template <size_t N> void foo(char (&hoge)[N]);
と区別できなくはない。
0307デフォルトの名無しさん
2008/02/23(土) 15:12:020308デフォルトの名無しさん
2008/02/23(土) 15:12:33template <size_t N> inline void foo(char (&hoge)[N]) { foo(hoge, N); }
もちろん、こう実装するんだぜ。
0309デフォルトの名無しさん
2008/02/23(土) 15:13:120310デフォルトの名無しさん
2008/02/23(土) 15:13:14>cuで2が、gguで3が、ijcoで4が返ってきます
その書き方はおかしい
strch_idxには引数が2つあるので、cuとかgguだけでは結果は決まらないはずだ
0311デフォルトの名無しさん
2008/02/23(土) 15:13:24逆。
gotoの方がどこにでも飛ばせるせいで行き先が不明確になる。
自分の書いたコードを他人に読ませることを想像してごらん。
breakならどこに飛ぶのか一目瞭然だけど、gotoだといちいちラベルを検索しないといけない。
しかもbreakなら「ループの終了」という意図が一目瞭然だけど、
gotoだとどういう意図で飛ばしたのかを考えないといけない。
そういう理由でgotoは避けられるため、安易にgotoが入っているとさらに、
「gotoを使わなければいけないどんな理由があったのか?」と考えさせることになる。
0312デフォルトの名無しさん
2008/02/23(土) 15:14:13あと、コンテナの最後の要素以外を処理する時、
std::vector<T> container;
for (int n = 0; n < static_cast<int>(container.size()) - 1; ++n) container[n] = ...;
ってやる?
0313デフォルトの名無しさん
2008/02/23(土) 15:23:01俺はstatic_castを使う
コンテナの方は
for (size_t n = 0; 〜
って書けばいいのでは
本当は std::vector<T>::size_type の方が適切なのかもしれんが
0314デフォルトの名無しさん
2008/02/23(土) 15:23:54>int⇔floatの変換
うん。
>最後の要素以外を処理
unsigned使う。
0315デフォルトの名無しさん
2008/02/23(土) 15:31:10使う。
>コンテナの最後の・・・
for (std::vector<T>::size_type n = 0, size = container.size(); n + 1 < size; ++n) container[n] = ...;
ってやると思う。
符号無しの値を符号付きにキャストするのは基本的に危険だと思う。
0316デフォルトの名無しさん
2008/02/23(土) 15:32:52if( !c.empty() )
for( size_t n=0; n<c.size()-1; ++n)
で何か問題あるのか?
0317デフォルトの名無しさん
2008/02/23(土) 15:34:18n + 1 < c.size() で判定すれば empty チェックは要らない。
0318デフォルトの名無しさん
2008/02/23(土) 15:36:12まあ T をそういう意味で使ってるとは限らないが。
0319デフォルトの名無しさん
2008/02/23(土) 15:39:01>>311での説明とほぼ同じという理解でよろしいでしょうか
>>311
gotoよりbreakを使うべきというのは、よく理解でき、納得できました
しかし、怖いというのは一体
>>310
すみませんが、もうすこし噛み砕いて説明願えないでしょうか
const char* sには、任意の文字列が入って、char cで、検索する文字を固定という事ではないんですか?
そのconst char* sにcuですとか、gguですとかが入っているので、これで十分だと考えているのですが
0320デフォルトの名無しさん
2008/02/23(土) 15:43:08goto はまず特定の状況でしか使われない。
それ以外で使われると混乱するし、
何のために使われているかすぐに分からないので不気味で怖い。
0321デフォルトの名無しさん
2008/02/23(土) 15:44:11goto は意図が不明確。
goto のあるコードを変更することになった場合、
その意図が 100% 分からなければ、
手を加えて変なことになりかねないので怖い。
0322デフォルトの名無しさん
2008/02/23(土) 15:44:56一番怖いのは、バグの温床になること。
コードの分かりにくさってのはバグに直結する。
0323デフォルトの名無しさん
2008/02/23(土) 15:47:14イテレータ使うならこうだな。
前進イテレータでさえあれば、これでいけるはず。
if(! container.empty()) {
Iter it_next = container.begin();
++it_next;
for(Iter it = container.begin(), end = container.end(); it_next != end; ++it, ++it_next) *it = ...;
}
0324デフォルトの名無しさん
2008/02/23(土) 15:52:18const char* s が cu でも c の方は
strch_idx("cu", 'c') とか
strch_idx("cu", 'u') とか
strch_idx("cu", 'x') とか色々指定できるわけで
0325デフォルトの名無しさん
2008/02/23(土) 15:53:30なるほど、よく理解できました
ご親切にありがとうございます
1、意図が不明で不気味で怖い
2、バグを招きやすいから怖い
この二点ですね
そして、本筋のほうもできたら説明していただきたいのですが
0326デフォルトの名無しさん
2008/02/23(土) 15:53:540327デフォルトの名無しさん
2008/02/23(土) 15:58:000328デフォルトの名無しさん
2008/02/23(土) 15:58:55一般に、コンパイルに時間がかかる方が、
コンパイル時にある程度処理を行ってくれているため、速くなる。
ただ、コードがあまりにも肥大してくると、
キャッシュの効きが悪くなって遅くなる事もある。
0329デフォルトの名無しさん
2008/02/23(土) 16:02:03いくつか修正したみたいだけど今はどうなってるの?
0330デフォルトの名無しさん
2008/02/23(土) 16:05:44最初から全文現すべきでしたね、申し訳ありません
#include <iostream>
using namespace std;
int strch_idx(const char* s, char c)
{
int i = 0;
do {
if(s[i] == c) goto end;
else if(s[i] == 0)
{
i = -1;
break;
}
i++;
} while(s[i]);
return i;
}
int main()
{
cout << "文字列を入力:"; char p[] = ""; cin >> p;
char c = c; cout << strch_idx(p, c);
return 0;
}
>>327
forだと、終了させるための条件が思いつかなかったので、whileにしましたが、やはりforのほうが良い理由があるのでしょうか
0331デフォルトの名無しさん
2008/02/23(土) 16:07:30>char c = c;
これはなによ
0332デフォルトの名無しさん
2008/02/23(土) 16:08:43continue した時でもインデックスが増えてくれるのと、
インデックスをなめていく操作を行っているという意図が伝わりやすいのと。
終了条件は while の時と同じでいいじゃん?
0333デフォルトの名無しさん
2008/02/23(土) 16:16:31goto end ってどこに飛んでるの?
0334デフォルトの名無しさん
2008/02/23(土) 16:17:17goto endが一個消し忘れ。
×char c = c;
○char c = 'c';
-1を返したいのは文がヌル文字だけだった場合?それとも文字が見つからなかった場合?
前者ならループのたび判定するのは無駄だから最初に一回だけ判定させたらいい。
後者ならヌルが見つかった時点でループが終わってるから中のlese-if節は判定してくれない。
最初に文字列の長さを測って最後までループが回った場合に-1を返すようにしないと。
0335デフォルトの名無しさん
2008/02/23(土) 16:26:11構造体を参照渡ししてもだめでした 下は期待通りの動作をします 何がいけないのかわかりません
#include <string.h>
#include <stdio.h>
typedef struct STRDATA{ char *start; char *end;}strdata;
f(strdata x){
delete x.start;
x.start = new char [20];
strcpy(x.start,"++++++++++++++"); }
main(){
char *ch=new char [10]; strcpy(ch,"uuuu");
strdata x;
x.start=ch; x.end=ch+strlen(ch);
f(x);
printf("%s",ch);}
0336デフォルトの名無しさん
2008/02/23(土) 16:26:35もっと単純に考えようぜ。
まず、文字を1つずつ取得していくループを書く。
for(i = 0; /* 文字列が終了するまで */; i++) {
/* s[i] で文字を先頭から順番に走査していける */
}
んで次に、c が見つかったらインデックスを返すようにする。
for(i = 0; /* 文字列が終了するまで */; i++) {
/* s[i] が c なら i を返す */
}
そして、検索しても c が見つからなかった場合は -1 を返す。
for(i = 0; /* 文字列が終了するまで */; i++) {
/* s[i] が c なら i を返す */
}
/* -1 を返す */
これでおk。
0337デフォルトの名無しさん
2008/02/23(土) 16:29:05Cならシーキビだろ
C++か?
template<typename T>
struct IsArray {
enum { value = 0 };
};
template<typename T, size_t N>
struct IsArray<T[N]> {
enum { value = 1 };
};
template<typename T>
bool test(const T&) {
return IsArray<T>::value;
}
template<typename T>
void f(const T& t) {
if(test(t)) cout << "配列だ" << endl;
else cout << "配列じゃない" << endl;
}
0338デフォルトの名無しさん
2008/02/23(土) 16:29:460339デフォルトの名無しさん
2008/02/23(土) 16:30:19f の呼び出し後、ch は既に delete された後のアドレスを保持することになるから
絶対にアクセスしちゃダメ。
そもそも生のポインタで確保されたメモリを扱ってるからそういう事が起きる。
コンテナ使え。
0340デフォルトの名無しさん
2008/02/23(土) 16:30:21f(strdata *x){
delete x->start;
x->start = new char [20];
strcpy(x->start,"++++++++++++++"); }
main(){
char *ch=NULL;
strdata x;
x.start=ch; x.end=ch+strlen(ch);
f(&x);
printf("%s",ch);}
0341デフォルトの名無しさん
2008/02/23(土) 16:31:18chに割り当てたnew char[10]はfの中でdeleteされてるから、
printf("%s",ch) は違法。
それからnew[]した配列はdeleteではなくdelete[]しないといけない。
0342デフォルトの名無しさん
2008/02/23(土) 16:34:08char *ch=NULL;
x.end=ch+strlen(ch);
ヌルポインタに整数を足しても有効な値にはならない。
0343デフォルトの名無しさん
2008/02/23(土) 16:35:22>>335をどう変更すればできますか?
0344デフォルトの名無しさん
2008/02/23(土) 16:37:350345デフォルトの名無しさん
2008/02/23(土) 16:38:25それはともかく、std::string 使え。
#include <string>
void f(string& str) {
str = "++++++++++++++";
}
int main() {
std::string str("++++");
printf("%s\n", str.c_str());
f(str);
printf("%s\n", str.c_str());
}
0346デフォルトの名無しさん
2008/02/23(土) 16:38:32f(strdata x){
delete x.start; x.start = new char [20];
strcpy(x.start,"++++"); }
main(){
char *ch=NULL;
strdata x;
x.start=ch;
f(x);
printf("%s",ch);}
f(strdata *x){
delete x->start; x->start = new char [20];
strcpy(x->start,"++++"); }
main(){
char *ch=NULL;
strdata x;
x.start=ch;
f(&x);
printf("%s",ch);}
0347デフォルトの名無しさん
2008/02/23(土) 16:38:490348デフォルトの名無しさん
2008/02/23(土) 16:41:160349デフォルトの名無しさん
2008/02/23(土) 16:42:49ポインタが参照渡しでどうのこうの言ってた奴だよな?
頼むからポインタとは何かを一から勉強し直してくれ。
0350デフォルトの名無しさん
2008/02/23(土) 16:44:23関数に渡された数値は数値がコピーされただけの別物。
だから関数内でx.start = new char [20];とかやっても呼び出し元のxには変化は無い。
0351デフォルトの名無しさん
2008/02/23(土) 16:44:320352デフォルトの名無しさん
2008/02/23(土) 16:45:30まともな本読め。
そこにいくらでもサンプルは書いてあるし、
詳細な解説も載ってる。
0353デフォルトの名無しさん
2008/02/23(土) 16:46:24後者はアドレス渡しですけど・・・
0354デフォルトの名無しさん
2008/02/23(土) 16:47:42後者では x は書き換えられるが ch は書き換えられない。
0355デフォルトの名無しさん
2008/02/23(土) 16:47:47アドレスの指す先の内容を書き換えると呼び出し元へ反映されるというだけのこと。
0356デフォルトの名無しさん
2008/02/23(土) 16:50:34ってやっても、ch と x->start がリンクされるわけじゃない
x->start の内容が変化しても、chには関係ない
0357デフォルトの名無しさん
2008/02/23(土) 16:52:12#include <string.h>
#include <stdio.h>
typedef struct STRDATA{ char **start; char **end;}strdata;
f(strdata x){
delete *(x.start); *(x.start) = new char [20];
strcpy(*(x.start),"++++++++++++++"); }
main(){
char *ch=NULL;
strdata x;
x.start=&ch;
f(x);
printf("%s",ch);}
0358デフォルトの名無しさん
2008/02/23(土) 16:52:50ch, x, そして動的に確保されたメモリが
実際にメモリ上でどう置かれていてどう参照していて
何を実行するとどう変化するか。
0359デフォルトの名無しさん
2008/02/23(土) 16:54:53それでとりあえずまともに動くね。
推奨されるコードかと言うとまたそれは別だが。
new 使ってるから C++ なんでしょ? コンテナ使えば楽だぜ。
0360デフォルトの名無しさん
2008/02/23(土) 16:58:05・>357のfに渡す前に、xはいつnewされてるの?
・関数の一行目がdeleteって、ものすごく気持ち悪いんだけど、よくつかう手法なの?
0361デフォルトの名無しさん
2008/02/23(土) 17:00:09deleteにNULLを渡しても何も起こらないことになっているから、
最初にnewされていないというのは大丈夫。エラーにはならない。
最初にdeleteというのは必要に応じて使えばいいと思うけど、
俺も書いた覚えない(clear()とかいかにもそれだけを行う関数というのでもない限り)。
0362デフォルトの名無しさん
2008/02/23(土) 17:03:440363デフォルトの名無しさん
2008/02/23(土) 17:04:300364デフォルトの名無しさん
2008/02/23(土) 17:04:41大問題。
0365デフォルトの名無しさん
2008/02/23(土) 17:05:560366デフォルトの名無しさん
2008/02/23(土) 17:06:160367デフォルトの名無しさん
2008/02/23(土) 17:07:46>deleteにNULLを渡しても何も起こらないことになっているから、
>最初にnewされていないというのは大丈夫。エラーにはならない。
なるほど、どうもです。
>最初にdeleteというのは必要に応じて使えばいいと思うけど、
>俺も書いた覚えない(clear()とかいかにもそれだけを行う関数というのでもない限り)。
なるほど。
よく考えたらC++になってからnewなんてほとんど使ったこと無かった気がします。
動的な配列が必要になったらだいたいvectorにつっこんでた。
0368デフォルトの名無しさん
2008/02/23(土) 17:10:42std::vector<int>().swap(v); みたいにしないとメモリは解放できない。
解放した方がいいかどうかは状況次第だが。
0369デフォルトの名無しさん
2008/02/23(土) 17:32:26大問題ってことで軽くググってみたら、
・配列に対して、delete [] としなかった場合、1個目の要素のみデストラクタが走り、残りの要素は走らない
・確保された領域(配列)は一応開放される(デストラクタで開放されるべき領域は除く)が、
要素数保持のための隠れた確保領域は開放されずに残る
ってな、感じかな
0370デフォルトの名無しさん
2008/02/23(土) 17:37:02#include <stdio.h>
main(){
char *ch=new char[200*1024*1024];
getchar();
printf("delete 実行\n");
delete ch;
getchar();}
0371デフォルトの名無しさん
2008/02/23(土) 17:40:15#include <stdio.h>
main(){
int n;
char **ch=new char*[200];
for(n=0;n<200;n++)ch[n]=new char [1024*1024];
getchar();
printf("delete 実行\n");
for(n=0;n<200;n++)delete ch[n];
getchar();}
0372デフォルトの名無しさん
2008/02/23(土) 17:42:39strch_idx関数に渡すためのcを、main関数のほうで作っておかないとだめかなと考えまして
>>332
あまり理解できませんが、なるべくforを使うようにします
>>333
消し忘れです
ご指摘ありがとうございます
>>334
理屈を丁寧に解説していただきありがとうございました
>>336を参考にやってみて、できました
>>336
ご丁寧にありがとうございました
その指針でできました
最後にご丁寧に、教えるのもわずらわしいような初歩的な愚問に答えていただき、ありがとうございました
0373デフォルトの名無しさん
2008/02/23(土) 17:44:350374デフォルトの名無しさん
2008/02/23(土) 17:47:40>>371
特に勘違いしてるところはないと思うが・・・
要素数を保持する領域はないってことを言いたいのか?
組み込み型にはないけど、クラスにはあるみたいなことが書いてあったんだが
0375デフォルトの名無しさん
2008/02/23(土) 17:49:37#include <stdio.h>
main(){
char **ch=new char*[200];
for(int n=0;n<200;n++)ch[n]=new char [1024*1024];
getchar(); printf("delete 実行\n");
delete[] ch; // delete ch;
getchar();}
0376デフォルトの名無しさん
2008/02/23(土) 17:50:41そもそもnew[]したものをdeleteするとどうなるかは未定義。
そういう挙動になったという話は、たまたまその実装ではそうだったということでしかない。
0377231
2008/02/23(土) 17:51:43MyArrayの方はデフォルトコンストラクタか引数を省略できるコンストラクタを
呼んでいるようなのですが、これのタイミングが分かりません。
コンストラクタを通過するそぶりもないし、一応初期化はされてるっぽいし・・・
特にデストラクタのタイミングも分からないのが心配です。
いつ開放されるんでしょうか?
0378デフォルトの名無しさん
2008/02/23(土) 17:54:33どこかでnew[]やdelete[]しているだろ?そのときだ。
0379デフォルトの名無しさん
2008/02/23(土) 18:04:57newで割り当てたものはdelete、new[]で割り当てたものはdelete[]で解放します。参照の深さは関係ありません。
0380デフォルトの名無しさん
2008/02/23(土) 18:12:04main(){
char *ch=new char [50];
char **start, **end;
start=&ch; //これは成功します
end=&&ch[20];
// end=&(ch+20);
}
0381デフォルトの名無しさん
2008/02/23(土) 18:24:57それを参照渡ししようとしたら&&ch[20]のはず・・・
0382デフォルトの名無しさん
2008/02/23(土) 18:26:38end = &chend;
0383デフォルトの名無しさん
2008/02/23(土) 18:33:33コンパイルはできましたが、startと動作が違うようです
main(){
char *ch=new char [50]; strcpy(ch,"abcdef");
char **start, **end;
start=&ch;
char * chend = &ch[20];
end = &chend;
printf("%c\n", ((*start+1)[2]) );
printf("%c\n", ((*end-5)[2]) );
}
0384デフォルトの名無しさん
2008/02/23(土) 18:34:48これだとうまくいきました サンクス
char * chend = &ch[6];
end = &chend;
printf("%c\n", ((*start+1)[2]) );
printf("%c\n", ((*end-5)[2]) );
■ このスレッドは過去ログ倉庫に格納されています