僕はプログラミングに今から初めて挑戦します。vc++を使ってCを
勉強していきますヨン。
まず猫本で基本的なことを学んで見ました。
ポインタ、配列、文字列、構造体と初めてのものが
次々に出て来ますがメゲマセン・・・。
では、今日、僕が学んだことを書きます。
#include <stdio.h>
int main(){
printf("hello,world\\n");
printf("%s\\n","hello,world");
return 0;
}
初めてのプログラミングといえばhello,world、ということくらい
僕だって知ってるよっ。。
猫本(使ってる本)には"hello,world"という式自体は先頭文字h
のアドレスを表していると書いてある。重要だから線を引いといたほうが
良いらしい。
このことを知っていれば下のコードも納得がイクンダ。
#include <stdio.h>
int main(){
char *s="hello,world\\n";
printf(s);
return 0;
}
sはchar型へのポインタ、すなわち先頭文字hのアドレスが
入ってるってことダ。んで、そのアドレスをprintf関数に
渡しているだけだ。ヨシッ。
<つづく>
>>130
4文字入力したときは強制的に改行'\\n'の部分に’\\0’が入るわけですね。
でないと配列を飛び出してしまいます。
ですから上のコードは4文字未満、すなわち3文字までの入力の場合は
最後の改行をヌルに置き換えてしまっているのです。
また、5文字入力した場合は最後の要素の中身が自動的に\\0に
置き換えられるのです。そうしなければ文字列として扱えません。
文字列は最初の要素から\\0までであるからです。
>>124
#include <stdio.h>
#include <string.h>
int main( void )
{
char buf[256] ;
int test = 100000 ;
strcpy( buf, (char*)&test ) ;
printf( buf ) ;
return 0 ;
}
ナルホド。確かにtestは文字列ではない、のです。
そこで
itoa(test,格納先のポインタ,10);
として
返り値のポインタをstrcpyの第二引数に渡せばイケマス。。。。ネッ。
こんな風に・・・・
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main( void )
{
char buf[256] ;
int test = 100000 ;
char str[30];
itoa(test, str, 10);
strcpy( buf, str ) ;
printf( buf ) ;
return 0 ;
}
if( strlen(buf) < 4 ){
p = strpbrk(buf,"\\n");
*p = '\\0';
}
別にこの strlen(buf) < 4 なくてもいいよ。
俺も前疑問感じて確かめたけど、fgets は 例え sizeof 分超えて書き込んだと
しようや。例えば10文字入力。そしたら、改行コードが入らず、3文字分切って
4文字目に'\\0'を入れるみたいだ。もう一度いうと、その場合改行コード入らないけどね。
改行コードが入ってないとしても '\\0' が最後にあって、buf は文字列として
正常に動作するから、 strpbrk も問題なく動作。
みつからなかった場合はどうだった? ヘルプみてもわかるけど、NULL が返る
ってあるはず。
if (p = strpbrk(buf,"\\n"))
*p = '\\0' ;
でいいハズ。
>>134
いいぞ!
>fgets(buf, (int)sizeof(buf), stdin);
これはどーなんだ? うーん、初めて見たな。
おれもなんとも言えないけど、たしかに第2引数は int なんだよね・・・
size_t で得られるサイズの型は size_t 型。けど、これは大抵の処理系
で int だと思うし、うーん。
まぁ、ヘルプよく見てるって言えばよく見てる^^。
そうそう、よく警告が出て、無理やりキャストして誤魔化そうとする人も
いるけど、警告は警告であって、エラーではない。別に放っといてもよいと思う。
せっかくコンパイラが教えてくれたメッセージだから後々のために残しておくのも
いい。
まー、放っとくのも気持ちが悪いもんで、消すのも良いと思うけど、そういう
考え方もある、というのも記憶に留めておいてくれ。
>>129
サイト紹介ありがとうございます。
自分、そこのSDKのとこぐらいしか見なかったけど、C言語のもあるんですね。
本と同じかな。だとしたら、Cデビュー氏はどこまで進んでおるのかな。
一応一通り読んだ? 明日、あさって辺りにはもうWindowsプログラミング入った
方がいいかな、微妙だ。
///////////////////////////////////////////////////////
ビット処理
算術シフトと論理シフトについて
& | ^ 使えるか
2の補数表現と絶対値表現の違い
ポインタ
関数ポインタ
ポインタのポインタ
ファイル分割
2重インクルードガード? もう当たり前
静的変数(static)、 大域変数(extern) 理解できてるか
現段階で、どこまで行けそう?
ビット処理は飛ばしてもいいと思うけど、一応。
例えば、ポインタのポインタなら、
こんなの見ても、「んっ?!」って思わないでくれよ。
#include <stdio.h>
int main( void )
{
char a = 10 ;
char *p;
char **pp;
char ***ppp;
p = &a ;
pp = &p ;
ppp = (char***)&a ;
printf( "a: %d\\n" , *p ) ;
printf( "a: %d\\n" , **pp ) ;
printf( "a: %d\\n" , *(char*)ppp ) ; //char ** として見る
return 0 ;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main( void )
{
char buf[256] ;
int test = 100000 ;
char str[30];
int j=0;
char *i;
sprintf(str, "%d", test);
strcpy( buf, str ) ;
printf( buf ) ;
printf("\\n");
for (i=buf;buf[j] != '\\0';i++){
printf("buf[%d] = %c\\n", j,buf[j]);
j++;
}
return 0 ;
}
sprintfでもイケマシタ。ちゃんと配列におさまり、文字列に変換された
わけです。(アタリマエデハアリマスガ。。。。)
初心者の人とかに良くありがちだけど、
char が文字だけしか入れちゃいけないとか思ってる。
それは間違いね。扱える記憶領域が違うってだけ。
現段階で char は1バイト。2の補数表現で扱える数として
-128 〜 127 まで
絶対値表現で、
-127 〜 127 までで、一個扱える数が違う。この辺は大丈夫?
int 型は大抵の処理系で、2の32乗。計算が面倒なので省略。
ここいらは、検索とかかけて調べるとダルいだろうから、知りたければ、
聞きなさい ( ・ω・) もう少し掘り下げて教えようて。
>>136
>>fgets(buf, (int)sizeof(buf), stdin);
> これはどーなんだ? うーん、初めて見たな。
> おれもなんとも言えないけど、たしかに第2引数は int なんだよね・・・
私もアレッと思って調べてみました。
確かにintですねぇ。
これ、仕様のバグのような気がします。
逆に言えばそれだけ使ってる人が少ないと…。
for (i=buf;buf[j] != '\\0';i++){
printf("buf[%d] = %c\\n", j,buf[j]);
j++;
}
i は何のために使ってるんだ? 消すの忘れたか? 使ってないのの
散らばりが目立つぞよ。
あとカンマ演算子はご存知?
for (i=buf;buf[j] != '\\0';i++,j++){
printf("buf[%d] = %c\\n", j,buf[j]);
}
こうやって、j を上のように納めてしまえるよ。
>>141
そう、ですか。仕様のバグとかよく聞きますな。
Windowsの関数とか、こう言ったのはバラバラあるそうで。
そのへんあんま詳しく知らんけど。
さてさて、今回も課題を書き残しておいてしばしの終了といたすか。
conio.h の中に getch という関数がある。
昨日あっぷした DosCS は君のPCに健在かな?
それを使って、キーボード矢印キーを押すごとに、画面に表示した
" & " を移動させるプログラムを作って見れ。
getch は多少くせがある。その辺はヘルプ見ながら、しっかり
やりなはれ。
スペースキーを押すと、画面の色を変える、というオプションも出来ればつけてくれ。
やるも、やらぬもあなたしだいっすけど。頑張りや
わからんかったらわからんでいいよ。解答用意してあげるから。
これ switch 文使ってね。まぁ、使うことになると思うけど、
if 文でづらづら並べる形にしちゃダメだよ。
こりは、多少 Windows プログラミングにも精通するところがある!
文字コードの理解も少しいるよ。
これは非常にムツカシイなぁ・・・
カーソルを任意の位置にウゴカセナイ(ノ_-;)
うまく動作しないときもあるなァァ( ´△`)
んーーーーーーー!
今回は致命的だったぞ。
ゲームのアイデアとしては面白かったけどね(笑
というか、こんな遊びの部分を入れてもらえたのは意外だった。
140点ぐらいまでなんか、ぼーっと動かしてたな。
修正してみたやつだが、目を通しておくと良い。
http://rivernet.cool.ne.jp/upmini/200504b/20050501214551_9028.lzh
新しいプロジェクト作ったら、
プロジェクト →プロジェクトへ追加 →ファイル、から全てCtrlキーなりで
選んで、全部追加。そんでメッセージが出ても無視してビルドすればOKだ。
で、
なにが致命的かっていうと、不自然な空白にはまず驚かされた。
int o,p,point =0;
SCREENCLS();
LOCATE(x,y);
printf("&");
こんな感じだったか。
まずインデントの修正から入った。
http://rivernet.cool.ne.jp/upmini/200504b/20050501215517_8702.txt
これも目を通しておくといい。
もしかして、私があっぷしといたシューティングのやつに入ってた
あの空白を真似たのかな・・・だとしたら、ごめん。
あれ、めちゃくちゃいらないコメントが入ってたんだわ。
それ一気に機械的に消して、めんどかったからあのまんまにして渡したんよ。
参考にしないでよ?(;´Д゚)
良し悪しは全てあなたの目にかかってる。
>>152 の方が自分的には見やすいけど、>>151 のような修正前のが
見やすいっていうんなら、もう何も言わないけどね。
ま、そこら辺はひとそれぞれだし。
あと、細かい指摘の部分していこうか。
まず、処理の流れが頭に描けていないように思うよ。
case 左:case 右: case 上: ・・・
全部の所で、
LOCATE(x,y);
printf("&");
これが入ってた。じゃ、外に出しちゃえばいいじゃん。って思った。
コピペでどんどん増やしていったような、そんなやり方を漂わすね。
コピペは全然いいけど、最低限処理の流れは考慮しとこう。
どんどん行数が増して、どこが while の終わりかわかりにくかった。
#それぞれ ってなんだよ・・・ 名前間違ってるし �(゚Д゚ll)
>>154 の続き
そこでファイル分割してみたわけ。
あなたのこの前やった、電話帳のプログラム。
あれもヘッダファイルは出来てたけど、
#ifndef XXXXX
#define XXXXX
#endif
の部分はまだ理解できていなかったみたいね。
それよか、#define の部分の理解も妖しいぞ。
まず、#define から。
これは何のためにあるか。
右。0x4d 左 0x4b とか即値を書いていったら、後々見直した時
わかりにくいでしょ。だからこうして名前つけとくんよ。
Windowsプログラミングでも、VK_LEFT とか VK_RIGTH とかちゃんと
わかりやすい名前がついてるからさ。
>CURON(true);
この部分。自分なりに解析して入れたんだと思うけど、惜しかった!
警告が出たはずだよね。
前に警告はエラーではない、みたいなこと書いたけどさ、これはあんまり
無視しない方がいいと思うよ。その見極め、ちゃんと自分で出来るように
なろうな。
コンパイルしたら、C4002 (?) だったか、とにかく番号が出たでしょ?
あれをドラッグして色反転させた状態で、F1 キー押したら、きっとヘルプ
が出るよ。エラーの時もまた然り。
OS ウィンドウズだよね? わかんないから、その方向で勝手に話すすめてるけど。
#define はとにかく文字列を置き換えるプリプロセッサ。
コンパイル前の処理として働く。
#define CURON() scr.Cursor(true) で
CURON()
と書けば、それは
scr.Cursor(true) に置き換わる。文字列置換と一緒と思っていい。
同じような使い方。マクロ関数。これも初め「んっ?!」って
感じるかもしれないけど、冷静に考えれば簡単なこと。
#define COLOR(n) scr.Color((n)) で、
scr.Color((aaa))
と書けば、それは
scr.Color((aaa)) に置き換わる。
#define LOCATE(x,y) scr.Locate((x),(y))
は・・・もういいね。
#include <stdio.h>
#define START int main( void )
#define TASIZAN(x,y) ((x),(y))
START
{
printf( "%d" ,TASIZAN(1,2) ) ;
}
こんなかんじ。
極端な例だから決して参考にしないこと。
つぎ
srand((unsigned)time(NULL));
これはループの外に出しておいた。
srand がなく、rand とだけ書いてしまった場合、ご存知の通り決まった数字
しかでないね。
srand は rand の種を生成する。ちょっと表現がむずいな。
seed rand の略か? とにかく、一回で良いんだ。わざわざループの
中に放りこむと無駄が発生するよ。
つぎだ
if(x==o && y==p){
SCREENCLS();
LOCATE(x,y);
ここは、問題ないけど、もし人の心があるならばコメントを入れよ ってね。
まぁ、このくらいのプログラムならば問題ないけど、わかりにくそうだなぁ、
とか思ったら、コメントを入れておこう。
変数の c ってがあったな。これにも言えるね。
一瞬なにかわからなかったけど、フラグだったんだ。
こういう、c とか a とか 言うの、本番プログラムではわかりやすい
名前をつけよう。
けど、一時的な使い捨て変数とかには別にいいと思うけど。
c よか flg とかの方がわかりやすいっしょ? どうよ?
っていっても難しい問題ではあるけどね。
実際、自分もコメントのつけ方と、変数名のつけ方は下手だからなんとも・・・
SCREENCLS();
を要所要所でしているね。
俺ならこういうやり方はしなかった。
新しい機能をどんどん使っていこう! という心構えは非常にすばらしい。
けど、今回のプログラムの場合、一番の無駄と言っていいかな。
要するに画面更新だね。
移動するたびに画面が更新されるんだよ。
だから連続でキーを押すとちらつきが発生するんだ。
& を更新すればいいだけの話だろ?
だったら、temp_x とかで前の値を残しておいて、printf( " " ) の空白
で置き換えてもそれは同じじゃん。
だったら、そっちを使おうや。更新が画面全体に及ばない。
これもまたWindowsプログラミングにかかわってくる大事な部分と言えるんじゃないかな。
とにかく、ある程度プログラムの組めるようになったら、
処理の効率とかを、もう少し考えるのをお勧めする。
結果いろいろ修正を加えたわけだけど、多少わかり辛い部分があると
思う。
static int c ;
で、
c ^= 0x1 とか入れてたね。
これ結構有名なやり方だけど、トグルスイッチとでも言おうか。
一回スペースキー押したら、 0 と 1 の排他的論理和で 1 になる。
もう一回押したら、 1 と 1 の排他的論理和で 0 になる。
ビット処理、大丈夫?
【問題】
-----------------------------------
� 0101 � 1010 � 1110
1111 1100 1000
�の排他的論理和を求めよ。xor
�の論理積を求めよ。 and
�の論理和を求めよ。 or
ここいらも、BitBlt とかのラスタオペレーションでたまに使ったりする。
やっぱ、ビット処理はやっておいたほうがいいかもね。
static #ifndef とかはまた今度ね。
自分で出来るなら、どんどん進めていってくれ。
とりあえず、どこまで出来るんだ?
どこまで解説入れるべきなんだ?
全てわからないことを前提に勝手に話すすめていってるけど、
こんな感じでよいのだろうか。
あー、あと 0xE0 ね。
ヘルプ見てあったように、
解説
_getch 関数はコンソールからエコーなしで 1 文字読み込みます。_getche 関
数はコンソールから 1 文字読み込み、読み込んだ文字をエコーします。どち
らの関数も、Ctrl+C は読み込めません。ファンクション キーまたは矢印キー
を読み込むときは、_getch と _getche を 2 回呼び出します。最初の呼び出
しは 0 または 0xE0 を返し、2 度目の呼び出しは実際のキー コードを返しま
す。
これはどういつことか。
つまるところ、
#include <stdio.h>
#include <conio.h>
main()
{
int c ;
while( 1 )
{
if( c = getch() )
printf( "testes\\n" ) ;
if( c == 'e' ) break ;
}
}
これ。(全角でスペース入れてるから注意)
矢印キー押してみ。testes が2ついっぺんに表示されるね。
これで解説みればわかるかな。
まず 0xE0 を取り出した後、もう一度、getch を呼び出した時、0x4d
を取り出すっつーこと。
書いてあるとおりでしょ?
そうそう、よた話ですけど、Ctrl + C で途中やめれるって知ってた?
はじめてこれ知った時、結構嬉しかったな。
>>163 の問題やってみなよ。
あと、もうすぐここいらをやってもらおうと思う。
よく考察しておくこと。
#include <stdio.h>
void foo( int n )
{ printf( "foo: %d\\n" ,n ) ; }
void bar( int n )
{ printf( "bar: %d\\n" ,n ) ; }
int main( void )
{
typedef void (*FUNCP[])( int ) ;
FUNCP func_p = { foo, bar } ;
func_p[0]( 10 ) ;
func_p[1]( 20 ) ;
return 0 ;
}
� 0101 � 1010 � 1110
1111 1100 1000
---------------------------
1010 1000 1110
教えてくれる人がいるってすっごい良いことですね。
僕も良い先生が欲しかったです..いや、欲しいです。
>>168
こういう時の、にせものうざ・・・
そろそろ潮時みたい
どーも、癪に障ってんのかねw ( ´,_ゝ`)プッ
じゃね、あと一人で頑張り
もーレスしねーからさ
ビビっと演算子の学習を始めマス。
このスレをたててから1週間を超えました。
つまり、ボクがCをはじめて触ってから1週間が経ったわけであります。
winプログラミングまでの道のりは非常に長そうです・・・・( ´△`)
ところでそもさんはwinアプリを作っておられるのですか。
>>149
>140点ぐらいまでなんか、ぼーっと動かしてたな。
遊んでくれてアリガトウ!!
>>157
> OS ウィンドウズだよね?
ハイ。win xpですゥ。
>>160
>srand は rand の種を生成する。ちょっと表現がむずいな。
seed rand の略か? とにかく、一回で良いんだ。わざわざループの
中に放りこむと無駄が発生するよ。
なるほど。
>>163
>static int c ;
で、
c ^= 0x1 とか入れてたね。
これ結構有名なやり方だけど、トグルスイッチとでも言おうか。
一回スペースキー押したら、 0 と 1 の排他的論理和で 1 になる。
もう一回押したら、 1 と 1 の排他的論理和で 0 になる。
cのような変数をフラグというのですね。知らず知らずノうちにフラグ
を使っちゃいましたョ。
^XOR演算子。A XOR B 2つのオペランドを排他的論理和で計算し、その
結果とBをさらにXOR演算すると、またAに戻る。これを
使えばスクリーンの背景色を切り替えられますね。( ̄▽ ̄)
つまり、スペースきーを押すたびに0,1,0,1・・・と切り替わっていくわけです。そして、その0と1の値を条件演算子により真偽別に背景色を
変更しているということです。
>>121
>save_data 関数内のこの場所が、今回の問題みたいだ。
for (i=0;i<no;i++){
fwrite(p+i,sizeof(adrData),1,fp);
}
"data.adr"をノートパッドで開いたところ、俺のはゴミが一杯入っていたぞ。
そっちはどうかな? というか、OS なに使ってんの?全然関係ないけど、
忘れなければ明記しといて。
ゴミというのは、やはりfgets関数なりで入力してもらったときに
最後の改行を、きちんとヌルに置き換えてあげないと入ってしまうノデスネ。。
os win xp
実際、そもさんの電話帳プログラムは名前や電話号のあとの改行を
strchrで\\0にしてあります。
フウ、今日からwinプログラミングのお勉強ですよッ。
Cとwin32 api関数郡を使うそうです。
ですから、Cそのものの勉強も引き続き続けていきます。
まずは窓を作る。。。。デスッ!
WM_PAINTメッセージが来るたびに四角形を1000個、いろいろな大きさ、
色で描画する。
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
DRAWTEXTPARAMS dtp;
HPEN hPen1;
HBRUSH hBrush;
int a,b,c,d,e,f,g,h,i,j,k,z;
char *szStr ="\\n文字列を表示\\nしちゃいますよ!";
switch (msg){
case WM_CREATE:
srand((unsigned)time(NULL));
break;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps);
GetClientRect(hWnd,&rc);
for(z=0; z<1000; z++){
a=rand()%256;
b=rand()%256;
c=rand()%256;
e=rand()%256;
f=rand()%256;
g=rand()%256;
h=rand()%rc.right+1;
i=rand()%rc.bottom+1;
j=rand()%rc.right;
k=rand()%rc.bottom;
hPen1 = CreatePen(PS_SOLID, 10, RGB(a,b,c));
SelectObject(hdc, hPen1);
hBrush = CreateSolidBrush(RGB(e,f,g));
SelectObject(hdc,hBrush);
Rectangle(hdc, h,i,j,k);
DeleteObject(hBrush);
DeleteObject(hPen1);
}
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default :
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
>>Cデビューさん
はやっ。
僕なんてWin32まで行くのに半年以上かかりましたよ。
猫本でビットマップの表示を覚え、スクリーンセーバーの作り方の
ところまでまでやってみた。
・・・・
・・・・
・・・・
・・・・
くだらん画像を一定時間ごとに動かすだけのスクリーンセーバーを
作った。出来上がった実行ファイルの拡張子をscrに変え、
起動。
や、や、、、っヤリマシターー ワーーイ
早くゲームを作ってみたナア( ´△`)
才能なんだろうなぁ
デビューさんも覚えが良さそうだし
がんばってください。応援してるよー
>>180
tokuさん、コニチハ。
ゴールデンウィークも終わった上に、winプログラミングに突入したわけで
勉強のペースも落ちつつありますがガンバッテミマス。
ッテ・・・・・だれもプログラミングデビューするひとはいないのか・・・・・(´;ェ;`)