Presentation is loading. Please wait.

Presentation is loading. Please wait.

C言語基礎 関数・ポインタ.

Similar presentations


Presentation on theme: "C言語基礎 関数・ポインタ."— Presentation transcript:

1 C言語基礎 関数・ポインタ

2 関数ってなによ? 関数という言葉を聞いて、最初に思うのは、やはり数学の関数でしょう。 数学でいう定義の関数とは
みたいな形だったよね。関数にxとyを渡すと結果は とかけたでしょ^^。じゃぁこれを試しにC言語で書いてみると num = f(2,3); printf(“%d”,num); と書いて、25と表示させることができそうだ。 別の例を挙げてみよう。

3 関数の概念 出力 入力 あまり「関数ってなにか」を考えたことはないでしょう^^。
「ばかにするな」っていわれるかも知れませんが、説明しましょう。 自動販売機 120円 商品1 コーラ 入力 出力 まずは図を描いてみました。関数とは入力に見合った出力をだす「機械」ですね^^

4 関数とは2 前の図を少し形式的に書いてみると 自動販売機(120,商品1)= コーラ 自動販売機(120,商品2)= ドクターペッパー
自動販売機(120,商品1)=  コーラ 自動販売機(120,商品2)= ドクターペッパー 自動販売機(100,商品1)= エラー というように、入力と出力を表せるでしょ? これが数字に限らない「関数」です。 じゃぁ関数「自動販売機(x,y)」の中身はどのようになってるのか?

5 自動販売機(金、商品のボタン) 自動販売機(金、商品ボタン)の内容
If(金<120){  結果(エラー); } if(商品ボタン==“商品1”){ 結果(コーラ排出); }else if(商品ボタン==“商品2”){ 結果(ドクターペッパー排出); }

6 C言語で関数を定義 関数名(引数1、引数2、引数3・・・)=戻り値 では、実際にC言語で関数を作ってみよう。
まず、関数には、引数と戻り値というものがあります。 関数名(引数1、引数2、引数3・・・)=戻り値 先ほどの例でいえば、引数1が「金額」、引数2が「商品番号」であり、戻り値が、「商品」ということになります。 もちろん、関数を使うまえに引数達が「数字をあらわすのか、文字をあらわすのか」をキチンと定義する必要があります。もちろん戻り値もですが^^ C言語では、これを以下のように宣言します。 戻り値型 関数名(引数型  変数名、引数型 変数名、・・・) 例) int fuction01(int a,int b) 数字のa,bを加工して、数字を返す。

7 実際の関数 #include <stdio.h> int wa(int x,int y); /* 関数を使うよ、という宣言 */
main(void) { int a=5,b=3; int res; res=wa(a,b); printf(“RES:%d”,res); } int wa(int x,int y) { return( x + y); }

8 解析1 #include <stdio.h> int wa(int x,int y); /* 関数を使うよ、という宣言 */
main(void) { int a=5,b=3; int res; res=wa(a,b); /* 関数の呼び出し */ printf(“RES:%d”,res); } int wa(int x,int y) { return( x + y); } 黄緑色の部分が、main関数、黄色部分が新しくつくった「和を求める関数、wa関数」、 水色部分が、宣言部分です。Main関数では、wa関数を呼び出して、その戻り値(結果)を RESに入れる、という形です。Wa関数の中のreturnは、その値を戻り値として返す命令です。

9 解析2 #include <stdio.h> int wa(int x,int y); /* 関数を使うよ、という宣言 */ 先ほどの宣言文、これは、このような形の関数を使います、という宣言文で、これを記述しないと、エラーが発生することがあります。そのため、しっかりと忘れないようにしましょう。この宣言の仕方は、関数の中身を記述する、 int wa(int x,int y) { return( x + y); } の部分の先頭にセミコロンをつけるだけです。

10 解析3 int wa(int x,int y) { return( x + y); } 関数の中身の定義をするとき、気をつけなれければいけないのは、変数の扱いです。もし、関数の中でループをしたい場合、変数iなどを使いたいですよね?その場合は、関数の中で変数を宣言すればいいんです。 int wa(int x,int y) { int i=0; int res=a; for(i=0;i<10;i++){ res = res +y; } return res; }

11 解析4 ひとつ前の例をみて、少し不安になったでしょうか?? 「main関数でも変数resを使っている」ということです。しかし、関数の中では、変数は独立して作ってくれますので、いくら他の関数と変数名が重複しても問題はないのです。 また、int wa(int x,int y){で部分で、xとyは宣言されたことになっているので、 宣言をする必要はありません。

12 プログラム例 引数とした文字が大文字なら0、小文字なら1を返す関数uord()を使って、入力した文字列の大文字だけ表示プログラム
int uord(char ch); main(void) { char str[500];   printf(“INPUT>”); scanf(“%s”,str); for(i=0;str[i]!=‘\0’;i++){ if(uord(str[i])==0){ printf(“%c”,str[i]); } } } int uord(char ch) { if(‘A’ <= ch && ch <= ‘Z’){ return 0: }else{ return 1; } }

13 関数なんていらない? 関数を勉強してみて、いかがでしょうか(まだ終わったわけではないですが^^) 「別に関数なんて面倒なことしなくても、mainに書いちゃえばいいじゃん」と思うかもしれません。実際学校でで出る課題だったら、関数は必要ないかもしれません。しかし、自分でプログラムを組もうとすると、関数は必須です。 例を挙げると、私は、文字列をバイナリ形式で表示する関数を必ずつくります。 データをこのように表示させる関数をあらかじめ作っておくのです。 こうすれば、データが数字として、もしくは文字として現在どのような数値が入っているのかを見ることができます。文字列を渡すと、これを表示してくれる関数を、つくっておけば、binary(str);とするだけで表示してくれるのです。これは便利でしょう??(NULL文字に関係なく指定バイト分表示してくれるよ)

14 ポインタという言葉がちらほら では、戻り値が二つ、三つある場合、どうすればいいか? ポインタですよ!

15 さぁ、そろそろポインタでもはじめっか さぁ、最後の難関、ポインタです。 がんばってついてきてね^^
まず、変数とは何かをもう一度確認してみよう。いままで、変数とは、データを持っているものであったが、では、内部ではどのような動きをしているのか? ここで、アセンブリの知識が少し必要となります。まずアセンブリでの値の参照方法は、 mov ax,[0x012345] で、メモリの番地0x012345にある数値をaxに入れるという動作をします。 mov ax,0x012345 の場合は、axに0x012345(数値)を入れるという動作をします。 つまり、プログラムにおいて、数値を「アドレス」とみなすか、「数値」とみなすかの二通りがあるということです。

16 プログラムにおいて、数値を「アドレス」とみなすか、「数値」とみなすかの二通りがある
まずはじめに プログラムにおいて、数値を「アドレス」とみなすか、「数値」とみなすかの二通りがある いままでプログラミングしてきて、そんなことを考えたこと無かったでしょう? 実は、いままでの「変数」は、アドレスとしての変数だったわけです。変数の宣言でアドレス(0x012345)が割り当てられたら、たしかにプログラムは0x012345と変数を対応付けているが、結局 mov ax,[0x012345] と置き換えてしまうので、プログラマは「どこのアドレスに在るのかよくわからないけど、とりあえず、宣言されたら、ひとつのメモリ領域が確保されるから、その値だけ考えればいいや」と割り切れるわけです。 別の表現。 変数と、メモリ番地は対応表のようなもので、関連付けられている。よって、変数に割り当てられた番地はプログラムが終了するまで変わらない。すべての命令が mov ax,[番地]などと置き換えられるのならば、プログラマは、アドレスを意識しなくても、変数名だけ気にしてれば良い。

17 変数と対応表で結ばれているのはメモリ番地である。
変数と対応表で結ばれているのはメモリ番地である。 mov ax,[test] add ax,0x50 mov [a],ax 対応表(コンパイル時に自動生成) 変数名 アドレス Test 0x12345 a 0x33BA0 I 0x12FFA mov ax,[0x12345] add ax,0x50 mov [0x33BA0],ax ほら、コンパイル時に勝手に対応表が作られるのだったら、アドレスを意識しなくてもOKだよね^^

18 変数とアドレスの関係を調べよう では理解を深めるために、このようなプログラムを書いてみよう
printf(“DATA:%d\n”,test) printf(“ADDRESS:%p\n”,&test); これを実行すると、testのメモリ番地と、その番地を参照して得ることができるデータを読む(つまり通常の動作)ことができる。 どうだろうか。変数の最初に「&」をつけることにより、変数そのものの値、つまりアドレスを参照できるわけ。 ほら、気づいたかな?この「&」、scanfで使ったよね^^。Scanfに&aとかを渡して、実行すると、aになにか数字が入っているという動作は、「アドレスそのものを関数に教えて、そこに直接書き込んでもらうという」ということをやっているわけです。

19 アドレスに直接数値を入れる 変数に&をつけることで、アドレスが参照できることが分かった。これを関数で応用すると、scanfのように「&a」と指定して、その値を変更できるような、関数が設計可能であるl。でもいまの状態ではなにもできない。 なぜなら、あるアドレスに直接書き込むということができないからだ。いままでやった変数を思い出してみても、書き込めるのは「変数が保持しているアドレス番地先」でしかないのだから。やっとここでポインタが登場する(わーい)

20 まずは・・ ポインタの宣言 ポインタ型 *ポインタ名 Char *chp; 初期化 Char *chp = &ch; 値の参照
ポインタ型 *ポインタ名 Char *chp; 初期化 Char *chp = &ch; 値の参照 Printf(“%p”,chp); printf(“%c”,*chp); *chp=‘a’; わからなければ、ここは読み飛ばしてもらってもOKです。慣れてきてから読むと「はいはい」と思うはず!

21 とりあえず、知っておくこと まぁまぁ、突っ込んでいくと教えることが多すぎるので、とりあえず、知っておくこと。
★ 内容の参照は「*」をつけて、アドレスの参照はそのまま。    例) char *cp; char ch; cp = &ch; *cp = ‘K’; ★ ポインタ型は、代入しようとしている変数と同じものにしておく。    例) char ch; int num; char *cp; cp = &ch; // ○       cp = &num // ×

22 変数とポインタは一緒? 変数 変数 :アドレスを参照した値(可変) &変数:そのアドレス自身(0x012345)(不変) ポインタ ポインタ:アドレス自身(0x012345)(可変) *ポインタ:アドレスを参照した値(可変) この(可変)とか(不変)に注意されたい。変数は宣言されたときにアドレスが固定されてしまう。だから、特定のアドレスに書き込みができない。しかし、ポインタは宣言時にその存在のみが宣言されるため、すべてが可変なのです。では、小さな例を。

23 Int *chp; int test=100; chp = &test; //変数testのアドレスをポインタに代入 *chp = 500; //変数testのアドレスに直接、数値500をぶち込む printf(“%d\n”,*chp); //ポインタが保持するアドレスを参照した値 printf(“%d\n”,test); これは意味がないやり方ですが、このような使い方もできる これを関数で応用してみよう!

24 例 void swap(int *a,int *b); //二つの変数を取り替える関数
void main(void) { int data1,data2; scanf(“%d”,&data1); scanf(“%d”,&data2); printf(“[%d %d]\n”,data1,data2); swap(&data1,&data2); printf(“[%d %d]\n”,data1,data2); } void swap(int *a,int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; }

25 じゃぁ自分で作ってみよう。 なんでもいいからポインタを使ったプログラムを作ろう。
先ほどの例を改造して、文字の交換をする関数に変えてみるとか。 とりあえず、ここまで。

26 文字列を関数に渡してみよう #include <stdio.h> int _strlen(char data[]); void main(void) { char str[512]; scanf("%s",str); printf("length:%d\n",_strlen(str)); } int _strlen(char data[]) int i; for(i=0;data[i]!='\0';i++); //これで空ループ return i; これは、文字列を渡すと、その長さを返してくれる関数。これは、相当便利だと思います。C言語にこの関数(strlen())があることが、それを物語っていますね^^

27 まず、配列はメモリ上でこのように表現されていることに注意してください。
簡単そうに見えるけど 別に、引数のところをstr[]とするだけやん!と思うでしょう。 しかし、この構造はそこまで簡単ではありません。 まず、配列についての復習をします。これを抑えないとヤバいですよ^^ アドレス ‘k’ 012000番地 ‘k’ ‘e’ ‘I’ ‘s’ ‘a’ ‘n’ ‘\0’ ‘e’ 012001番地 ‘I’ 012002番地 Str[0] Str[1] Str[2] Str[3] Str[4] Str[5] Str[6] ‘s’ 012003番地 ‘a’ 012004番地 ‘n’ 012005番地 ‘\0’ 012006番地 まず、配列はメモリ上でこのように表現されていることに注意してください。


Download ppt "C言語基礎 関数・ポインタ."

Similar presentations


Ads by Google