...

malloc

by user

on
Category: Documents
15

views

Report

Comments

Description

Transcript

malloc
C言語 ポインタ
H108102 濱口 賢人
H108137 山崎 貴英
H108139 山下 佳隆
1
ポインタとは
2
ポインタって何?
• 変数がメモリ上のどこ(何番地)にあるの
かという情報がアドレス
• そのアドレスを格納するための変数が
ポインタ
3
実体とアドレス
宣言
実体
アドレス
int x;
x
&x
ポインタ int* x;
変数
int *x;
*x
x
ふつうの
変数
よくわかるC言語 P.79より
4
#include <stdio.h>
int main(void)
{
int a = 100;
int* p = &a;
double b = 0.25f;
double* q = &b;
printf(“pのアドレスは%x、実体の値は%d\n”, p, *p);
printf(“qのアドレスは%x、実体の値は%f\n”, q, *q);
return 0;
}
5
メモリ
※1マス = 1バイト
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
番地
6
変数の宣言
int a = 100;
int型 : 4バイト
a
1
2
3
4
5
6
7
8
9
100
10
11
12
13
14
15
16
番地
変数は値を代入するもの
7
ポインタの宣言
p
int* p = &a;
p
1
2
a
9 番地
3
4
5
6
7
8
9
a
100
100
10
11
12
13
14
15
16
番地
ポインタは番地を格納するもの
8
変数の宣言
double b = 0.25f;
double型 : 8バイト
b
1
2
3
4
5
6
7
0.25
8
9
10
11
12
13
14
15
16
番地
9
変数の宣言
q
double* q = &b;
q
1
2
b
8 番地
3
4
5
b
0.25
6
7
0.25
8
9
10
11
12
13
14
15
16
番地
ポインタの大きさは型に依存しない
10
動的なメモリの確保
11
malloc関数
キャスト(型変換)
sizeof演算子 sizeof(データ型)
void*型をint*型に変換
型の大きさを求める
int* p = (int *) malloc (sizeof(int));
malloc関数 void *malloc(size_t size)
sizeバイトのメモリを確保
戻り値はvoid*型
12
realloc関数
p = (int *) realloc (p, sizeof(int)*2);
• 一度確保した領域を再確保する
その場合、元の領域の内容がコピーされる
• 第一引数: void*
• あらかじめ確保した領域を指すポインタ
• 第二引数: size_t
• 確保する領域の大きさ
13
calloc関数
int* p = (int *) calloc (3, sizeof(int));
• sizeバイトの領域をn個割り当てる
確保された領域はゼロで初期化される
• 第一引数: size_t (n)
• 確保する個数
• 第二引数: size_t (size)
• 確保する領域の大きさ
14
どうしてキャストするの?
void* p = malloc (sizeof(int));
• voidポインタは指し示すことは出来るが
実体に対して値の代入が出来ない
(何型の変数を指しているか分からないため)
*p = 100; ×
• 目的の型のポインタにキャストして使
おう
15
free関数
free(p);
• mallocで確保された領域は、プログラム
が終了しても解放されないことがある
• メモリ上に管理者不在の領域が出来て
しまう
• 確保と逆の順で開放しよう
16
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* p = (int *)malloc(sizeof(int)*3);
*p = 2010;
*(p+1) = 10;
*(p+2) = 7;
printf(“%4d/%2d/%2d¥n”, *p, *(p+1), *(p+2));
free(p);
p=NULL;
return 0;
}
17
malloc
int *p = (int *) malloc (sizeof(int)*3);
p
10
20
15
20
25
30
35
40
45
番地
intの3倍 → 12バイトが確保された
18
malloc
*p = 2010;
p
10
20
2010
15
20
25
30
35
40
45
番地
pはint*型 → 4バイトを使って代入
19
malloc
p+1 = 24 番地
*(p+1) = 10;
p
10
20
2010
15
20
10
25
30
35
40
45
番地
pはint*型 → 4バイト先を見る
20
malloc
p+2 = 28 番地
*(p+2) = 7;
p
10
20
2010
15
20
10
7
25
30
35
40
45
番地
21
malloc
free(p);
p
10
20
2010
15
20
10
7
25
30
35
40
45
番地
不要になったメモリを解放
22
malloc
p
p=NULL;
×
p
20
NULL
10
15
20
25
30
35
40
45
番地
使わなくなったらNULLを代入
23
どうしてNULLを代入するの?
• メモリの二重解放を防ぐため
• 発見するのが難しいバグになりがち
• うっかりミスをなくすための記述
24
#include <stdio.h>
実行結果
int main(void) {
int *p1 = (int*)malloc(sizeof(int));
*p1 = 100;
printf("p1のアドレスは%xです¥n", p1);
100080が解放されました
free(p1);
p2のアドレスは100080です
printf("%xが解放されました¥n",p1);
100080が解放されました
int *p2 = (int*)malloc(sizeof(int));
printf("p2のアドレスは%xです¥n", p2);
free(p1); // 二重解放
printf("%xが解放されました¥n",p1);
printf("p2の値は…%d¥n", *p2);
free(p2);
return 0;
p1のアドレスは100080です
p2の値は…100
間接的にp2が
開放されている
p1
p2
}
25
100080番地
?
どうしてNULLを代入するの?
• 解放された100080番地は
他のスレッドに確保されてしまうかも
• p2を開放してる訳ではないため、
バグに気づきにくい
• ポインタにNULLを代入しておけば
このようなバグを回避可能
26
#include <stdio.h>
改善例
int main(void) {
int *p1 = (int*)malloc(sizeof(int));
*p1 = 100;
printf("p1のアドレスは%xです¥n", p1);
free(p1);
printf("%xが解放されました¥n",p1);
p1=NULL;
実行結果
p1のアドレスは100080です
100080が解放されました
p2のアドレスは100080です
int *p2 = (int*)malloc(sizeof(int));
printf("p2のアドレスは%xです¥n", p2);
free(p1); // ここで二重開放は起こらない
printf("%xが解放されました¥n",p1);
printf("p2の値は…%d¥n", *p2);
free(p2); p2=NULL;
return 0;
}
0が解放されました
p2の値は…100
free関数にNULL(0)を
渡しても何も起こらない
27
配列とポインタ
28
静的確保と動的確保の違いは?
• 静的確保
• 宣言の時点でメモリを確保し、プログラム
終了と同時に解放される
例) int a[10];
• 動的確保
• プログラムの途中でメモリを確保し、
free関数で任意のタイミングで解放できる
例) int *a = (int *)malloc(sizeof(int)*10);
29
配列とポインタの関係
• ポインタと配列は実は同じもの
• 配列aがあるとき、aはa[0]のポインタ
• 配列は連続した領域を型で区切る
• 添字によってポインタを進めている
30
int a[5];
a[0]
10
15
20
a[1]
a[2]
25
30
a[3]
a[4]
35
40
45
番地
a
int* p = (int *)malloc(sizeof(int)*5);
*p
10
15
20
25
30
35
40
45
番地
p
31
動的確保のメリット
• メモリの最大量を固定する必要が
無い
• 必要な量だけメモリを確保する
ため、メモリの無駄遣いを防ぐ
32
構造体とポインタ
33
構造体とは
• 複数のデータ型をひとまとめにしたもの
• 構造体の要素のことをメンバという
• メンバにはドット演算子を使ってアクセ
スする
• student.id = 109001;
34
構造体変数の宣言
struct student {
int id;
char name[10];
};
struct student s;
s
s.id s.name
10
15
20
25
30
35
40
45
番地
メンバとなる変数がそれぞれ確保される
35
メンバの参照
• ドット演算子
• student.name
• 構造体のメンバを参照
• アロー演算子
• student->name
• ポインタから構造体のメンバを参照
• (*student).nameと同義
36
構造体とポインタ
struct student {
int id;
char name[10];
};
p
10
s
s.id s.name
24
15
s
p
20
25
30
35
40
45
番地
s.id, (*p).id, p->idは同じものを指す
37
課題
38
課題1
• strchr関数を作ってみよう
•
探す対象の文字列 (charの配列) と
探す文字(char)を引数として受け取る
•
文字が見つかったらその文字のポインタを、
見つからなかったらNULLを返す
39
注意とヒント
• 関数内で配列を使ってはダメ
• 代わりにポインタを使おう
• 文字列の終わりは’¥0’
40
課題2
• 学生を表す構造体を作り、成績管理ソフ
トを作成せよ
• 構造体には以下のメンバを持たせること
• 名前(charの配列)
• 学籍番号(charの配列)
• GPA(float)
41
構造体例
typedef struct student {
char
name[20];
char
number[10];
float
gpa;
} STUDENT;
42
条件1
• 管理は動的配列とすること。
• 静的配列は×
• 10人分の入力を受け付ける
• 入力が終わったら、入力した情報を
表示する
43
条件2
• 条件1の表示が終わった後に、検索機
能をつける
• 名前、学籍番号を入力し、該当する
学生情報を出力する
44
課題3
• 課題2のプログラムを、入力する人数
の制限をなくすよう改良しよう
• 名前に特定の文字列が入力されたら、
その時点で入力を終了する
• 特定文字列は自由に決めてください
45
ヒント
• reallocを使うと楽
• 最初に10人分の領域を確保し、
足りなくなったら20人分の領域を
reallocで再確保、と出来る
46
ラシゼミ恒例課題
• 何か作ってみよう(自由課題)
• 以下のものを全て使うこと
• 構造体を指すポインタ
• ポインタを引数として受け取る関数
• テキストファイルかコメント文で
どんなプログラムか簡単に説明を付けて
• 無責任ってレベルじゃねーぞ!
47
評価方法
• 課題1, 2, 3の完成度で判断
• 自由課題は加点(課題が終わってから)
48
提出について
• 課題ごとに別々のファイルに保存
• .cファイルをメールに添付して提出
• 次回のレクチャまでに
• 宛先: [email protected]
• 絶対になくすなよ!削除するなよ!
49
勉強におすすめ
• Cのドリル (Workbook in Programming)
• C言語ポインタ完全制覇
瀬戸 遥 (著)
(標準プログラマーズライブラリ)
前橋 和弥 (著)
• Cの絵本 C言語が好きになる9つの扉
(株)アンク (著)
• よくわかるC言語
—イメージと例題で理解する
長谷川 聡 (著)
50
Fly UP