【初心者歓迎】C/C++室 Ver.103【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
エスケープシーケンスやWin32APIなどの環境依存なものもOK そのような質問は必ず環境を書きましょう 半角空白やタブでのインデントはスレに貼ると無くなります コードを貼れる所 http://codepad.org/ https://ideone.com/ 前スレ 【初心者歓迎】C/C++室 Ver.102【環境依存OK】 http://mevius.5ch.net/test/read.cgi/tech/1509780815/
>>282 ->>285286 ありがとうございます せっかく回答貰ったのですがunsigned charがどういう型なのかとかそういった説明が 本書で無いのでやはり何度読み返しても理解できませんでした 今は文字を符号なしの整数に直すおまじないってことで覚えておこうと思います まず補数についてお勉強しなさい まずそっから そしてそれを8bit、16bit、32bitで表現するとどうなるか 考察しなさい わかった? https://ideone.com/gFxr1T どっかから拾ってきた関数のソース(なんかのlibcのソース)をコピペして signed charとunsigned charの2進表現をダンプしてやったから 補数のお勉強が捗ったら、あとで参考にしなさい 繰返すが、言語仕様上はビット表現についてたいした決まりがあるわけではない。 表現できる範囲に着目した方が理解しやすいんでないかなぁ。 決まりがなかったら ビット演算なんかできない バカのいうことなんか ほっといていいからな 実際に決まってないもんは決まってない。 1 の補数を使うようなのも許されるし、実際に存在する。 ポータビリティに配慮しなければなんでも出来るのが C/C++ の良いところだが、 ガチで規格を把握しようとすると未定義の罠だらけなんよな。 きっとバカのオツムでは リトルエンディアンとビッグエンディアンの計算機では ビット演算の結果がかわる もしくは変わるようなクソみたいなコードを書く もう察しがつくのが怖いわ。。。 少なくとも >>293 の結果は言語仕様的に保証されない uint32_t aho; unsigned char* baka = (unsigned char*)&aho; 知恵遅れはこんなことを平気でする そして計算機によって結果がかわっておかしいおかしいとかいうワケ 数値のビット表現に2の補数が使われるとは限らないってだけの話な。 >>292 キャストの必要性と負の数の内部表現は全く関係ないように思うけど 負の数の内部表現は 少なくとも以下の3種類は存在する 1の補数 2の補数 符号ビット マイナスゼロはトラップ値として使ったりする https://ideone.com/ub97A1 すいません↑の29行目のコードって何してるんですか? int size = sizeof student / sizeof *student; sizeofで studentと*studentが3に化けて 3,3で割り算して1じゃないんですか 意味がよく分かりません; >>304 配列の定義が見えてる場合 "sizeof 配列名" は配列全体の総バイト数になるのよ。 対して "sizeof *配列名" は "sizeof 配列名[0]" と同じで配列要素1個のバイト数。 配列全体のバイト数 / 配列要素1個のバイト数 == 配列の要素数 配列の要素数を知るためのイディオムだな。 ちなみに sizeof student も sizeof *student も 3 にはならないと思うよ。 むしろ sizeof student / sizeof *student の計算でようやく 3 が得られる。 >>304 配列の要素数を計算しているかと sizeof studentは、配列のバイト単位の長さ sizeof *studentは、student型のバイト単位のサイズ >>305-306 これ割り算じゃないんですね なんとなく理解できました。ありがとうございます この方法を使うと配列が増えてもループのとこ書き直さなくてもいいということですか >>307 割り算だよ バイト単位で配列のサイズ(個数)を算出しているだけ >この方法を使うと配列が増えてもループのとこ書き直さなくてもいいということですか そう >>302 そう。 キャストについてはビット表現は関係ない。 だから (規格ではっきり決めていない) ビット表現を中心に理解しようとするのは余計なことだっていう主張ね。 でも具体的なビット表現、0か1がいくつか並んだものを見せて 「符号なしなら数値として〜、2の補数表現なら〜と解釈される。 それを符号拡張なりゼロ拡張なりすると…」 という具合に教えた方が理解は容易な気がするよ。 「規格では(値の範囲は決まっているが)ビット表現は決まっていない」の 一点張りで、抽象的な説明だけをしても分からんでしょ。 とりあえずcharは8ビット、負数は2の補数表現、のモデルで 話が飲み込めれば、その先のcharが8ビットじゃない処理系や 負の数の表現方法が異なる場合に進める。 どうせ大半の処理系は8ビット・2の補数だから無駄にもならんし。 8ビット・2の補数に凝り固まることのないよう、気をつけて教えるってことで。 >>310 俺も先にアセンブラを触ってたタイプだからビット表現からの理解をしたのでそれが自然なんだけど、 0 と 1 の集まりで表される世界が、 表現範囲が決まっているという考え方よりも感覚的にわかりやすいだろうかと冷静に考えると 一般的にはそうでもなくない? って思えてるってのもある。 レイヤを分けて考えるってのはそんなに簡単ではないよ。 「コンピュータの中でこう処理されている」というのを知った上でそれを忘れて (抽象の壁の向こうに追いやって) 「言語の考え方 (規格) ではこうなっている」という理解を持てるかどうか……。 どうせ C を使ってるとやっぱり現実のコンピュータが透けてみえちゃうんだから、 「言語の考え方はこう」というのを押さえておけば あとは自動的に「それを実現するために内部ではこうなっている」という風に理解していけると思うんだがなぁ。 >>311 具体的なものがあるからこその抽象化じゃないの。 抽象化したものだけでは具体的に動かすことができないから理解するのは難しいでしょ。 >>312 アセンブラの色々を自動化したみたいな立場からのスタートだから、 歴史的には具象から抽象へという形で成立しているが、 あくまで C を学び始めた人のスタート地点として、 「ビット表現、あるいは範囲が決まった値のどちらがなじみやすいか」という話。 普通の人が日常的に数値を扱うことはあるし、 その中には上限・下限が決まっているということもある。 でも、 0 と 1 の集合で表現するという考え方を日常的にしている人はかなり少数派だよ。 馴染みやすい方から入って行って最終的に「なるほど内部ではこう表現されるのか」 に至るのってそんなに不自然な道筋かな? >>313 だから具体的に動作させられる環境がないと勉強出来ない。 小学校で1+1を学んで中学でx+yのように抽象化してきたでしょ。 >>314 数値型変換の規則とかも数値として決まってる。 動作させるのにビット表現で考える必要は無いだろ。 なんらかのビット表現を割り当てて動作はするけど、 そりゃコンパイラの考えることで、 人が最初からどうしても把握しておかなきゃならないもんではない。 >>315 ビット表現を最初から考えておく必要も把握しておく必要もないけど、具体的な実体を知っていた方がイメージしやすく理解しやすいと思う。 そこまで忌避する理由が分からない。 >>316 繰返すが、数値のビット表現は世間一般の感性からすると全く異質だ。 だから「(いきなり最初には) イメージしやすくない」と言ってるの。 無理してでも最初に身につけられたら後が楽ってことはあるかもしれんが、 イメージしやすいってことは無い。 ビット表現は C に慣れた人にとってあまりにも当然の大前提すぎて、 それをわからん奴にはだいぶんイラつくが、 すんなりとは納得できない方が普通だよ。 はいはい 頭悪いからビット演算できないと だからどうした >>318 入門者の大多数が (十分に) 頭が良いと想定するのはそれこそ馬鹿げた判断だ。 とんでもない方向の思い違いが勢ぞろいなのが普通。 健常者に届かないぐらい頭悪いから オレはビット演算はあきらめた と自白されても困るワケ 外野から見ると自分は頭が良いと思い込んでそうなID:/wwW4VSsよりはちみつの方が賢そう オレは頭いいとか ひとことも書いてないからな キミラが健常者に程遠いほど 頭悪いわけ それがわからない? まず途方もないほど頭悪いという自覚がない それが致命的 バカを自覚できないからバカが治らない はちみつさんの主張「初心者にビット表現から教える必要はない」を 当人がビット演算できない僻み、とか捉えるのは明らかに間違いだろ。 対立が昂じて厳しい言葉を使いそうになった場を茶化すのは俺も好きだけど。 (余計に険悪になったところで「お呼びでない…」と立ち去る流れまで込み) 実際のところ「初心者に2進数での数値表現を理解させることが困難か?」 については、今なら「コンピューターの中ではゼロイチで情報が記憶される」 くらいの基本知識は持ってるだろうから、昔よりは敷居が低いんじゃないかな。 …とは言え自分もマシン語ハンドアセンブル相対ジャンプ暗算から 入ったクチだから、経験に基づいたバイアスが強いかも知れん。 ビット表現を使わず初心者に説明する良い資料があるなら読んでみたい。 たぶん得るところは大きい。 "はちみつ餃子"でググってもそういうのが出てこない… >>326 必ず半角カナを使ってレスしてるいつもの人は、常に持論は正しく相手は低能というスタンスで一方的に断定しかしないから、深く考えても仕方ないよ。 半角君のいってることはまともなこともあれば的はずれなこともあるけど、常に共通するのは周りの指摘や疑問には耳を貸さず、議論の流れも無視して自分の主張を繰り返すだけということ。 だから、斜め読みして受け流すだけでいいと思うよ。 なるほど 知恵遅れは議論したつもりになってんのか 知恵遅れの場合議論できるレベルに到達してない まずそこの自覚がない C形式の二次元配列は先頭から一次元配列みたいな顔して普通にアクセスできると思うんですが C++11以降でネストしたstd::arrayでもポインタを使って一次元配列のようにアクセスしても規格上セーフですか? ↓のコードのようにforループ一つで上下左右方向の繰り返しを済ませたいです https://ideone.com/HbRfZu 1次元の可変の列を行とみなして そのそれぞれの行に可変の1次元の列がある状態になってる つまり、行毎にバラバラにそれぞの行のヒープができる作りになる そもそもC++の規格とか関係ない 低学歴であれば低学歴であるほど 言語の規格なんかぜんぜん分かってないくせに 自分を大きくみせるために言語の規格がどうこういってるのだけは よおく分かったわ >1次元の可変の列を行とみなして >そのそれぞれの行に可変の1次元の列がある状態になってる >つまり、行毎にバラバラにそれぞの行のヒープができる作りになる というのはどういうことでしょうか 行ごとにバラバラなので行をまたいでのアクセスはできないという意味でしょうか C形式の多次元配列もネストされたstd::arrayも、各要素は連続したメモリ領域に置かれていますよね というかC形式の(少なくとも)二次元配列は一次元配列として全要素にアクセスできると思っていたのですが 間違っていますか? array 1個作ったら1個ヒープできるのはわかる? >>326 昔から C を使っている人ってまさにそういう感じの低レイヤや それに付随するあれこれの知識と一緒に習得してきた人が多いと思う。 だけど、 Teratail とか StackOverflow とかでの質問を見てると、 俺らがあまりにも当然の前提と思ってそこにあることにすら気づいてなかったものが 今の入門者にとってはハードル高いのかもしれないと感じることが結構あって、 教え方も昔の通りにはいかないんじゃないかねと思えてるの。 >>330 Cでも未定義動作だよ。 JIS C (JIS X 3010:2003) 6.5.6 加減演算子 > 整数型をもつ式をポインタに加算又はポインタから減算する場合,結果は,ポインタオペランドの型を > もつ。(中略)ポインタオペランド及びその結 > 果の両方が同じ配列オブジェクトの要素,又は配列オブジェクトの最後の要素を一つ越えたところを指し > ている場合,演算によって,オーバフローを生じてはならない。それ以外の場合,動作は未定義とする。 >>334 それって単にプログラミングをする人の増加の問題では バカは自分で引用してる文章の意味がわかってない ホントなかわいぞうなぐらい頭悪い バカはなんでとてつもなく自分がバカであるか 分かることは永遠にない >>333 mallocしないとできんのじゃないの? Cだし >>333 ヒープというのは動的に確保されたメモリのことでしょうか ネストしたstd::arrayというのは、std::array<std::array<int, 2>, 3>というような意味で使っていました(リンク先のコードにある通り) その場合メモリは動的確保されないと思いますが… >>335 Cのその「配列オブジェクト」というのは多次元配列を一つのオブジェクトとして見るのではないということですか ポインタと要素数を引数にとる関数に多次元配列を渡すコードをこれまで少なからず見てきた(教えられた)から勘違いしてたかも ヒープといのはオレがウソ書いてた そのまま書いたら固定で配列がスタックにできる アホが引用してるのは あきらかに全然関係ない頭悪いのを引用してる array ┣array ┃┣ int ┃┗ int ┣array ┃┣ int ┃┗ int ┗array ┣ int ┗ int こうなる アホが引用してる部分は たとえばこんなソースがあった場合、 int* ai_aho[3] = {1, 2, 3} int* pi_aho = ai_aho; for (int i = 0; i < 3; ++i, ++pi_aho) { *pi_aho = 1; } pi_ahoはループを抜けたあと pi_ahoはソース上適切でないアドレスをさしてるが こいつを参照しなければ問題ないということが書いてある >>341 int a[N][M] に対して a + i するときの「配列オブジェクト」は要素型 int [M] で要素数 N の配列のこと。 N を超えて加算すると未定義動作になる。 a[0] + i するときの「配列オブジェクト」は要素型 int で要素数 M の配列のこと。 同じく M を超えて加算すると未定義動作になる。 ポインタを受け取る関数に a[0] あるいは &a[0][0] を渡した場合も M を超えて加算した場合は同じ理由で未定義動作になる。 期待した動作をすることも多いだろうけど、信頼性や移植性は損なわれる。 おまえのたとえばは前科があるから信用できん コピペしろコピペ (正)int ai_aho[3] = {1, 2, 3}; (誤)ai_aho[3] = {1, 2, 3} 目視で確認した コレでいける な、低学歴知恵遅れはなにも分かってない まずなにも分かってないのに規格読んで分かったふりしてるのがよく分かる 低学歴知恵遅れが規格読んでも 規格なんか分かるわけがないからな そもそも基本的にポインタがどう加算されるかすら分かってないのに uint32_t aho[4]; uint32_t* p_aho32 = aho; uint8_t* p_aho_8 = (uint8_t*)aho; p_aho32++; p_aho_8+=4; どっちのアドレスも同じになる 配列の場合どうなるか 考え方はまったく同じだな あとはもう分かるハズだ ロベール05-09の関数内に引きこもりって章のサンプルコードが長すぎて読めません(3ページ使用) <algorithm>ってファイルを始めてincludeしてるにも関わらず其れに関して何ら説明ないし… この章に関しては静的変数はグローバル変数と同じように使えてプログラムが終わるまでずっと同じメモリを参照している と覚えられれば必要十分ですか? 何か簡単なコードを書いて教えてくれると助かります よろしくお願いたします。 例によってロベール著を読んでないし、下のコードはCだけど、 関数内static変数の説明なら、CもC++も変わらんだろう。 (行数節約のため詰め込み・省略してるので良いスタイルじゃない) #include <stdio.h> static void in_static(void) { static int cnt = 0; /* staticな変数 */ cnt++; printf(" static %d 回目!\n", cnt); } static void not_static(void) { int cnt = 0; /* staticじゃない変数 */ cnt++; printf("not_static %d 回目?\n", cnt); } int main(void) { in_static(); not_static(); in_static(); not_static(); in_static(); not_static(); return 0; } こんな感じかな。 このコードには盛り込んでないけど、グローバル変数と違って 「関数内static変数には、基本的には関数の外からはアクセスできない」 という性質もある。 >>353 違う言語にも関わらず書いていただきありがとうございます 実際に実行してみてかなりスッキリしました 自動変数と静的変数の違い、しかと理解できました 関数についてるstaticも気になるところですが読み進めたいと思います char str[]={"aaaaaa","iiiiiiiii","uuuuuuu"}; は出来ないのに char* str[]={"aaaaaaa",iiiiiii","uuuuuuu"}; が出来るのはなぜですか? ポインタと配列は密接な関係にあるんじゃないんですか よろしくお願い致します "aaaaaa" とか "iiiiiiiii" とか "uuuuuuu" がchar*型だから char型の配列に入れようとしても無理な話 仮に出来たとしてどういう結果になって欲しいのだろう? char str[]={"aaaaaa"};はできる char str[]={"aaaaaa","iiiiiiiii","uuuuuuu"};はできない char *str[] = {"aaaaaa","iiiiiiiii","uuuuuuu"};はできる char str[][9] = {"aaaaaa","iiiiiiiii","uuuuuuu"};ならできる 一番目は長さを指定しない配列変数の宣言で初期化により長さが指定されている。 二番目は{"aaaaaa","iiiiiiiii","uuuuuuu"}は文字列の配列なので変数の型と一致しないためエラーになる 三番目はポインタの配列なので配列の各要素を対応する文字列で初期化できる 四番目は配列の配列なので文字列の配列で初期化できる(ただし要素数の指定は必要) >>355 前者の[]は、文字の「列」を表すから 後者の[]は、文字列ポインタの「配列」を表すから charはcharacterの略称、characterは文字、それが複数個集まった列が文字列 列となっているものが根本的に違う >>357 なんかこの違いを仕様で片付けて覚えるのはあまりよろしくないみたいなこと本に書いてあったので 違いが知りたかったです >>356 ,358,359 ありがとうございます 文字列リテラルはポインタ型だったんですね それなら代入出来ない理由も納得出来ます。スッキリしました >>360 厳密にいえば文字列リテラルの型は配列だよ。 具体的に言えば const char[] ね。 暗黙の型変換で const char* として解釈される場合も多いってだけ。 そのリテラル文字列はNULでターミネートされる 配列の長さが+1される べつにNULターミネートしなくても 文字列は扱える つまり長さが保存されないかわりに NULでターミネートされてる それをcでは文字列と呼称している そして、charの配列要素が 1つの文字を表してるとは当然限らない MBCのように連続する複数の配列の要素が 1つの文字を表すことが多い で、strlen()で文字の数が返却されないのは当然 >>360 曜日の出力もこれで簡単になる int wday = 4; printf("%c", "SMTWTFS"[wday]); >>364 それだと土曜日と日曜日の区別がつかないw そいつをlongのポインタにする知恵があれば誉めてあげるんだが int wday=5; char week[] = "SunMonTueWedThuFriSat"; printf("%.3s",&week[wday*3]); これでどうだw 悪い例 (キャストの悪用、データサイズの勝手な仮定) int wday = 5; printf("%.4s\n", &((int*)"Sun.Mon.Tue.Wed.Thu.Fri.Sat.")[wday]); 軽いジョークのつもりで書いてみたけど、セグメンテーション・フォールトが出て 動くまでに予想外に手間取ってしもうた。 原因はアドレス演算子 & の付け忘れだった。 それを.3sで表示すれば371と同じ結果にならなかね? 表示幅の指定で .3 なら >>371 と同じになるよ。 英単語の省略形にピリオドをつけたいのは好みの問題なの。 今は曜日も月名もピリオドを付けないのが一般的なのかな。 <time.h> の asctime() も3文字3文字だね。 たびたび失礼、そしてまるっきり実用の役に立たない話ですまぬ。 &((int*)"Sun.Mon.Tue.Wed.Thu.Fri.Sat.")[wday] 「いったん[]で配列形式でアクセスしてから要素のアドレスを得る」 なんて回り道をしないでも (int*)"Sun.Mon.Tue.Wed.Thu.Fri.Sat." + wday と素直にポインタの足し算だけでいけたね。 …難解Cプログラムに凝る人の気持ちがちょっと分かった気がする。 intのサイズがcharのサイズの4倍でないと動かない 難解ではなくただの知恵遅れのコード sizeofがイマイチ分からないです 型や変数のサイズを出す演算子ってのは分かったんですが 例えばこの例↓どういう風に化けてるんですか? https://ideone.com/szVAAP sizeof studentで要素数3だから3に化けると思うんですが、右の*studentは何に化けてるんですか? sizeof が返すサイズってのはバイト数だというのがよくわかってないのかな。 もう C++ では type_traits の std::extent を使って欲しい気持ち。 >>378 分かってないです ロベールの入門書読んでるんですが説明が少なすぎてこの27行目の式が分かりません。 構造型のバイト数も分かりませんし…int3個とchar一個だから13バイト? >>379 すいません、分かりません sizeof(student) / sizeof(Student);が何に化けてるのか検討も付きません ありがとうございます。 https://ideone.com/aPMXLA コレでなにが分からないか自分で説明できないなら すべてを諦めたほうがいい >>380 int のサイズは処理系依存なので、具体的に何バイトとは言えない。 でもまあ現代的なパソコンなら 4 バイトのことがほとんどだろうね。 さらに言えば仕様上は構造体の要素の間にスキマがあいててもかまわない。 > int3個とchar一個だから13バイト? この構造体中の char は MAX_NAME+1 個じゃん。 まあそれはそれとして、 sizeof student というのは、 student という配列の大きさを「バイト数で」返してきて、 sizeof *student というのは student 配列の要素ひとつの大きさをバイト数で返してくる。 つまり、配列全体の大きさを配列の要素の大きさで割ったら配列に含まれる要素の個数になる。 この場合は 3 ってこと。 sizeof *student が配列の要素ひとつを表現しているっていうのがちょっと分かり難いかなぁ。 >>377 , >>380 前にも質問してた人だな まず、sizeofはメモリ上に確保された対象のバイト単位のサイズを返す(charは1バイト、intは4バイト) sizeof studentは、配列全体(要素数 x Student型のサイズ)のバイト単位のサイズを返す、配列の要素数は返さない sizeof *studentは、Student型のバイト単位のサイズを返す それらの割り算をしてるのだから、結果は要素数になる >>382 >sizeof *student が配列の要素ひとつを表現しているっていうのがちょっと分かり難いかなぁ。 個人的にそういう表記は嫌だわw 変数のサイズを求めるなら、その型名でって思う >>384 へー、私は逆に型名よりも変数名で書きたい派。 これは変数 student について調べたいのであって、 型 Student について調べたいわけでは無いので。 >>382 すいません、おかげさまでどういう計算してるのか理解できました 確かにポインタにすると何で要素一つのサイズなのか理屈づけて説明できません…sizeof student/sizeof student[0]とかだと分かりやすいです ありがとうございます。意味が理解できたので応用して使えそうです >>384-385 私が sizeof *student が分かり難いと述べたのは 配列名に * を付けたものが配列の先頭要素になるルールの背景にある暗黙の型変換が分かり難いって話。 C/C++ を使ってると空気みたいにやっちゃうんだけど、これ実際のところだいぶんアレなルールですよ。 >>385 型が表すサイズの定数だから、変数から取得するってのが気持ち悪いよ sizeofなんて何か細かいことワチャワチャしたい時に型のサイズ欲しいよねーって感じの演算子だものw >>388 この場合くらいの小さなサンプルだとあまり気にならないけど、 その変数が何の型であるか知っていなければならないっていうのが、 読むときの負荷が高いと感じてしまう。 自分を信用してないというか、自分がアホだということを信用しているので、 色々忘れて読んでも良いように書きたいと思ってる。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる