• 検索結果がありません。

ヒントスライドPDF プログラミング演習2 #prog2bkc net

N/A
N/A
Protected

Academic year: 2018

シェア "ヒントスライドPDF プログラミング演習2 #prog2bkc net"

Copied!
40
0
0

読み込み中.... (全文を見る)

全文

(1)

第2週 配列とポインタ

プログラミング演習2

(2)

2

ポインタ(pointer)とは

 変数,配列,関数などの(メモリ上の)アドレスを

指し示す

• ポインタ変数の中身はアドレス

「~へのポインタ」

 C言語を代表する非常に便利な機能

 メモリ空間をイメージすることが理解への早道

アドレスの理解

今日のキーワード

・メモリ空間

・アドレス

・ポインタ変数

・ポインタの演算

(3)

3

メモリとアドレス

CPU

Core(TM) 2 Quad プロセッサ 2.50GHz

メモリ

4GB デュアルチャネル DDR2-SDRAM メモ

(4)

4

メモリ空間とアドレス

4Gバイト

=0x0 ~ 0xffffffff

0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xffffffff

1バイト

アドレスの先頭 アドレス

16進数で表すことが多い

(5)

5

復習:変数

変数

• 数値や文字を格納する箱のようなもの

• 型によってサイズが違う

– char 型:1 バイト

– short 型:2バイト

– int 型:4バイト(環境によって異なる)

1バイト

2バイト

4バイト int main(void){

char c; short s; int num; ...

return 0; }

型名 変数名

(6)

6

変数とアドレスの関係

int main(void){ int a;

a=100; ...

return 0; }

(7)

7

変数とアドレスの関係

int main(void){ int a;

a = 100; ...

return 0; }

4バイト

(8)

8

変数とアドレスの関係

int main(void){ int a;

a = 100; ...

return 0;

}

今日のポイント1

変数aのアドレスとは、

変数aの置かれた先頭の

アドレスのことである

この場合は0x1004

(9)

9

変数のアドレスの取得方法

int main(void){ int a;

a = 100;

printf(“変数aのアドレスは%p”,&a); ...

return 0; }

今日のポイント2

変数の前に&をつけると

変数のアドレスを取得できる

変数aのアドレスは0x1004 実行結果

(10)

10

復習:ポインタ (pointer) とは

 変数,配列,関数などの(メモリ上の)アドレスを

指し示す(参照する)

• ポインタの中身はアドレス

「~へのポインタ」

4バイト ポインタ変数

(11)

11

ポインタの使い方 (ポインタ変数の宣言)

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”,*pa);

...

return 0;

}

今日のポイント3

ポインタ変数の宣言は

型名 * ポインタ変数名;

(12)

12

ポインタの使い方(変数の宣言)

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”,*pa);

...

return 0;

}

(13)

13

ポインタの使い方 (アドレスの取得)

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”,*pa);

...

return 0;

}

今日のポイント2

変数の前に&をつけると

変数のアドレスを取得できる

(14)

14

ポインタの使い方 (値の代入)

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”,*pa);

...

return 0;

}

(15)

15

ポインタの使い方(ポインタ変数の出力)

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”,*pa);

...

return 0;

}

変数aのアドレスは0x1008 実行結果

今日のポイント4

ポインタ変数の中身は

アドレスである

(16)

16

ポインタの使い方(ポインタの指す先変数の値)

変数aのアドレスは0x1008 変数の値は100

実行結果

int main(void){

int *pa;

int a;

pa = &a;

a = 100;

printf(“ 変数aのアドレスは%p”,pa);

printf(“ 変数aの値は%d”, *pa);

...

return 0;

}

今日のポイント5

ポインタ変数に*をつけると ポインタ変数の指している先 の変数の値を参照できる

(17)

17

ポインタを利用して何がうれしい/できる?

アルゴリズムとデータ構造

リスト(7,8週)

木構造(12週)

関数にデータを渡す(4週)

• 2つ以上の結果を受け取りたい場合

配列を渡したい場合

• 関数内で渡したデータを編集したい場合

動的メモリ確保(3週)

関数ポインタ(上級)

コールバック

(18)

18

必須課題2-1

1. p4 のプログラムを入力

2. 実行

3. 次ページの理解補助シートと出力結果を照らし合

わせて考えてみよう

4. コメントを入力

5. TA/ES に確認してもらう

(良くわからない人は1ステップ毎に、

TA/ES に確認してもらいましょう)

(19)

19

必須課題2-1:理解補助シート(1/2)

a = 10;

printf("a: %d¥n", a);

printf("&a: %p¥n¥n", &a);

//上の続き p = &a;

printf("p: %p¥n", p); printf("*p: %d¥n", *p); printf("&p: %p¥n¥n", &p); ステップ1

ステップ2

(20)

20

必須課題2-1:理解補助シート(2/2)

//前ページの続き a = 20;

printf("a: %d¥n", a);

printf("&a: %p¥n¥n", &a); printf("p: %p¥n", p);

printf("*p: %d¥n", *p); printf("&p: %p¥n", &p); ステップ3

(21)

21

復習:配列

配列

• 複数の同じ型の変数をまとめたもの

int a[ 4 ];

名前 要素数

(22)

22

文字列(char型の配列)

char s[9] =“Ritsumei”;

文字列の決まり事

文字列の最後は

‘¥0’

“ (ダブルクォーテーション):文字列を”で囲む

‘(シングルクォーテーション):文字1文字を’で囲む

(23)

23

文字列とポインタ

char s[9] =“Ritsumei”;

s

s はs[0]のアドレス(&s[0])

を示す

(s+1)

=&s[1]

(s+2) =&s[2]

*(s+1)

=s[1]

*(s+2)

=s[2]

(24)

24

必須課題2-2:理解補助シート(1/4)

c = 'A'; p = &c;

printf("c: %c¥n", c);

printf("&c: %p¥n¥n", &c); printf("p: %p¥n", p);

printf("*p: %c¥n¥n", *p);

ここの代入が終了した時点の状態を考えてみましょう ステップ1

(25)

25

必須課題2-2:理解補助シート(2/4)

//前ページの続き

*p = 'B';

printf("c: %c¥n", c);

printf("&c: %p¥n¥n", &c); printf("p: %p¥n", p);

printf("*p: %c¥n¥n", *p);

ここの代入が終了した時点の値とアドレスを考えてみよう ステップ2

(26)

26

必須課題2-2:理解補助シート(3/4)

//前ページの続き

printf("s: %s¥n", s);

printf("s[0]: %c¥n", s[0]); printf("s[1]: %c¥n", s[1]); printf("s: %p¥n", s);

printf("&s[0]: %p¥n", &s[0]); printf("*s: %c¥n", *s);

printf("*(s+1): %c¥n¥n", *(s+1));

出力結果と照らし合わせて、何が出力されているか考えてみよう ステップ3

char s[12] = "Ritsumeikan";

(27)

27

必須課題2-2:理解補助シート(4/4)

//前ページの続き

*(s+2) = 'T';

printf("s: %s¥n", s);

Tはどこに代入されるか考えてみよう ステップ4

(28)

28

ポインタの加算、減算

char s[9] =“Ritsumei”;

char *p = s;

p++;

ここの時点

&s[0]

(29)

29

ポインタの加算、減算

char s[9] =“Ritsumei”;

char *p = s;

p++;

ここの時点

&s[1]

ポインタを加算/減算すると、ポイン

タ型のサイズ分(一箱分)アドレスが

ずれる

例:ポインタ変数名がpの場合

加算:p++ または p = p+1

減算:p-- または p = p-1

(30)

30

必須課題2-3:理解補助シート(1/3)

char *p1, *p2;

p2 = “ Winter ”; p1 = p2;

A1 A2 A3 A4 A5 A6 A7

p1とp2の値はA1~A7のどのアドレスどれでしょう?

(31)

31

必須課題2-3:理解補助シート(2/3)

//前ページの続き

while ( *p1 != '¥0' ) {

__________________________ ; // 文字列の最後を検索 }

A1 A2 A3 A4 A5 A6 A7

文字列の最後を検索するためのp1の動作を考えてみよう

(32)

32

必須課題2-3:チェックシート(3/3)

//前ページの続き

while ( _________________ ) { // アドレスを比較 __________________________ ;

putchar( *p1 ); //アドレスを制御して文字を1つずつ出力 }

A1 A2 A3 A4 A5 A6 A7

p1の動作をA1~A7を使って考えよう

p1とp2の関係も考えてみよう

(33)

33

まとめ(通常の変数とポインタ変数)

通常変数 ポインタ変数

宣言方法 int a; int *pa;

変数名: a

型: int 型 変数名: pa 型: int 型へのポインタ型

値の代入 a = 16; pa = &a;

変数aの中身は(int型の)数値 変数paの中身は(int型変数であ る)aのアドレス

値の表示 printf("%d", a); printf("%p", pa);

整数値を表示するには%dを使用 アドレスを表示するには%pを使用

演算子 読み方 意味 使用法

* (変数宣言の時) アスタリスク

(asterisk)

ポインタ変数 int *pa;

* (変数宣言以外) アスタリスク ポインタが指す

先の内容 *pa = 100;

printf("%d", *pa);

& アンパサンド

(ampersand)

変数のアドレス int a; pa = &a;

(34)

標準入出力 (stdin, stdout)

プログラム

入力 出力

file file

stdin stdout

fp

(自分で決めたファイルポインタ)

fprintf(stdout, "Hello");

printf("Hello");

同じ意味

34

(35)

リダイレクション

35

プログラム

input.txt outp.txt

stdin stdout

stdout

stdinの入力元, stdoutの出力先を変更

• プログラムを実行するときに次のように入力

% ./a.out <input.txt >outp.txt

stdin

× ×

入力元変更 出力先変更

35

(36)

不正な参照(1)

segmentation fault (セグメント例外)

• プログラム中で使えるアドレスの範囲の外を

参照すること

• 例: int *p=NULL;

(*p)++;

• 例: int *p;

int x=0;

p=x;

NULLはアドレス0 (無効なアドレス)を示す

無効なアドレスの値に対して 演算しようとした

構文エラーではないが、 不正な参照の原因

36

(37)

不正な参照(2)

互換性のないポインタ型の代入

• char ch=‘A’;

char *q=&ch;

int *p=&ch;

構文エラーではない が、不正な参照の原

0x0a01

… …

‘A’ ch

p

0x0a02 ?????

q

0x0a01

0x0a01

q の参照先

p の参照先

(int 型は 4 バイト )

37

(38)

補足: コンパイルエラーの読み方

gccが出力するメッセージを読むには

英語に慣れる

専門用語を知る

エラーや警告の例:

– test.c:10: error: 'y' undeclared (first use in this function) (10行目で宣言されていない変数yを使っている)

→対処例: yを宣言する、変数名の間違いを直す – test.c:5: error: redeclaration of 'x'

(5行目ですでに宣言されている変数xを重複して宣言した)

→対処例: 重複している宣言の削除

– test.c:10: 警告: 互換性のないポインタ型からの代入です

(違う型のポインタを代入した ex. int型ポインタにchar型ポインタを代入)

→対処例: ポインタの型を修正

38

(39)

発展:セグメント例外の箇所の確認方法

39

gcc –g –o prog prog.c

gdb prog (gdb) run ...

Program received signal SIGSEGV, Segmentation fault. 0x0804837e in test ()

セグメント例外が起きた箇所の 関数名がわかる

(40)

著者リスト

40

1. 安積 卓也(情報システム学科)

2. 大森 隆行(情報システム学科)

参照

関連したドキュメント

1) “Prior Consultation with Customs”: This process is not mandatory, however, any operator who wants to be an applicant can contact regional Customs to get the necessary

“〇~□までの数字を表示する”というプログラムを組み、micro:bit

社会調査論 調査企画演習 調査統計演習 フィールドワーク演習 統計解析演習A~C 社会統計学Ⅰ 社会統計学Ⅱ 社会統計学Ⅲ.

「AI 活用データサイエンス実践演習」 「AI

卒論の 使用言語 選考要件. 志望者への

国際地域理解入門B 国際学入門 日本経済基礎 Japanese Economy 基礎演習A 基礎演習B 国際移民論 研究演習Ⅰ 研究演習Ⅱ 卒業論文

授業は行っていません。このため、井口担当の 3 年生の研究演習は、2022 年度春学期に 2 コマ行います。また、井口担当の 4 年生の研究演習は、 2023 年秋学期に 2

使用言語 日本語 選考要件. 登録届を提出するまでに個別面談を受けてください。留学中で直接面談 できない場合は Skype か