SlideShare a Scribd company logo
1 of 175
C言語ポインタ講座
@kakira9618
2017/11/12
この資料について
 この資料は、@kakira9618が所属している
サークルでの講座『C言語ポインタ講座』
で使用していた資料を、一部修正・加筆し
て、一般公開したものです。
 質問、指摘などは@kakira9618まで。
– https://twitter.com/kakira9618
2
この講座の対象
3
1 ポインタの基本的な使い方を知っている
ポインタ変数の宣言の仕方と使い方
ポインタを使ったプログラムが一応書ける
2 動作原理、記法がよく分かっていない
ポインタ変数が派生型である理由を説明できない
配列の要素へのアクセスの原理を説明できない
int (*p)[3]; って何? という人
3 良い使い方がわからない
で、どういうときに使うと良いの?という人
ポインタのポイント
これらを把握すればポインタは理解できる!
4
1 原理
ポインタがどのようにしてメモリ上の情報を
読んでいるかを理解する。
2 記法
ポインタの記法を整理する。
3 使い方
ポインタを使うと効率よく書ける場面を把握。
お約束
 この資料では、以下の環境を仮定します
– sizeof(int) = 4
– sizeof(short int) = 2
– sizeof(float) = 4
– sizeof(double) = 8
– sizeof(ポインタ型) = 4
– 1byte = 8bit
– C言語の規約はANSI C
– float型・double型の表現方法は IEEE754
– 文字コードはASCII
– とくに指示がない限りバイトオーダーは
リトルエンディアン
5
注意
 この資料中に掲載しているプログラムは
ポインタの文法や原理、使い方の解説をす
るために掲載しているものです。
 そのため、実務のプログラミングでそのま
ま使うと怒られるようなコード、もしくは
他の方法を使ったほうが良いようなコード
等が入っていたりしますがご了承ください。
6
目次
7
記法
使い方
原理
ポインタの指す”幅”を意識する
ポインタはただ場所を保存するだけじゃない!
8
質問です
9
Q. C言語におけるポインタ変数とは?
質問です
10
Q. C言語におけるポインタ変数とは?
アドレスを保存する変数!
確かにその通り。
だけど、理解するにはもう一歩。
アドレスとポインタ変数の違い
アドレス
 ポインタ変数の値
 メモリ上の位置を示す
番号のこと
– 0x12345678とか
ポインタ変数
 アドレスを格納する変数
– 格納するアドレスを自由に
変更できる
11
int *p = &intValue ;
アドレスポインタ変数
さらに質問
12
Q. &演算子(1項演算子)で計算されるものは?
さらに質問
13
Q. 式中の&演算子(1項演算子)で計算されるものは?
その変数のアドレス!
その変数のアドレス、ですね。
だけど、理解するにはもう一歩。
う~ん... 論理積かな?
&演算子
14
 &を変数の前につけると、
が得られる
変数の先頭アドレス
図解
 int value;
 &value
15
value
value
ここのアドレスが得られる
= 1byte
参照
 参照するときは、ポインタ変数の前に*を
つけます。
 これで、pの記憶していたアドレスに書い
てある内容を取り出すわけですが・・・
16
int *p = &intValue;
printf(“%d”, *p);
重要な考察
 int *p = &intValue; では、pがintValueの
先頭アドレスで初期化される。
 *pで、pのアドレスの内容を取り出す
値を取り出すとき、
どこから取り出せば良いのかは分かる。
どこまで取り出せばよいのかは??
17
図解
 int *p = &value;
 *p
18
valuep
p
どこまで読めば良いの??= 1byte
p
変数pに のアドレスが入っていることを意味注意: =
重要な考察
19
&のときに「valueの」という
情報も保存してるのでは?
→まちがい。pはアドレスしか保存していません。
ポインタ自身の型から推測?
→せいかい!
重要な考察
 int *p; としたとき、
 *pとすると、pに記憶されているアドレス
から、int型分だけ読み込む
20
pは int型への ポインタ変数
図解
 int *p = &value;
 *p
21
valuep
p int型分
「int型分」はpの宣言「int *p」から。
= 1byte
ポインタ演算
 p++; や、p--; とするとポインタに保存さ
れているアドレスが1単位動く
 アドレスがいつも1byte動くわけではない
 ポインタ変数の宣言から、参照元の型を
見て、その型の大きさを1単位とする。
22
図解
 int型へのポインタpの場合:
23
p int型分
p int型分
p++; int型分だけずれる
= 1byte
図解
 short int型へのポインタpの場合:
24
p short int
型分
p
p++;
short int型分だけずれる
short int
型分
= 1byte
ここまでのまとめ
 ポインタはアドレスを保存する変数
 値を参照するときに、自身の型から参照すべ
き幅を計算
 ポインタ演算(++, --など)をするときも、
自身の型から増やすべき値を計算。
 アドレスにも型があり、同じように計算する。
25
ポインタやアドレスの指す先には
”幅”があるイメージ
メモリへの情報格納方法
同じビット列でも格納方法・型が違えば違う値!
26
データの格納順(バイトオーダー)
 情報をどういう順番で格納していくか
 大きく分けて2つ
27
1 ビックエンディアン
上位バイトを上位バイト、
下位バイトを下位バイトに格納
2 リトルエンディアン
上位バイトを下位バイト、
下位バイトを上位バイトに格納
このような格納順をバイトオーダーという
素直
ひねくれ
ビックエンディアン
 0x12345678(0xは16進数を表す)を
ビックエンディアンで格納するとき:
28
0 x 1 2 3 4 5 6 7 8
0x12 0x34 0x56 0x78
上位 下位
格納
ソース上
メモリ上
= 1byte
ビックエンディアン
 0x12345678(0xは16進数を表す)を
ビックエンディアンで取り出すとき:
29
0 x 1 2 3 4 5 6 7 8
0x12 0x34 0x56 0x78
上位 下位
取出
ソース上
メモリ上
= 1byte
リトルエンディアン
 0x12345678(0xは16進数を表す)を
リトルエンディアンで格納するとき:
30
0 x 1 2 3 4 5 6 7 8
0x78 0x56 0x34 0x12
上位 下位
格納
ソース上
メモリ上
= 1byte
リトルエンディアン
 0x12345678(0xは16進数を表す)を
リトルエンディアンで取り出すとき:
31
0 x 1 2 3 4 5 6 7 8
0x78 0x56 0x34 0x12
上位 下位
取出
ソース上
メモリ上
= 1byte
float(double)型の格納方法
 IEEE 754の規格に基づく。
 32bitを3つの領域に分ける
– 符号部分(1bit):+なら0, -なら1
– 指数部分(8bit) :基数部分を2の何乗するか
– 基数部分(23bit) :基となる数字の並び
 (値) = (符号) * 1.(基数) * 2
32
(指数-127)
符号
1bit
指数
8bit
基数
23bit
float (double)型の格納方法
33
0 x C 0 F 8 0 0 0 0
=1bit
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
※簡単化のため、バイトオーダーは
ビックエンディアンとする
続きは全て0→
float (double)型の格納方法
34
0 x C 0 F 8 0 0 0 0
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
符
号
指数 基数
=1bit
float (double)型の格納方法
35
0 x C 0 F 8 0 0 0 0
=1bit
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
符
号
指数
(129)
基数
符号が1なので「-1」
指数は129 – 127 = 2
基数は1.11110000000000000…
⇒-1 * 2 * 1.1111 = -111.11 = -7.752
型と数値
36
0 x C 0 F 8 0 0 0 0
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
 このビット列をunsigned int型だと思うと
– ビックエンディアンなら
• 0xC0F80000 = 3237478400という整数
– リトルエンディアンなら
• 0x0000F8C0 = 63680という整数
=1bit
型と数値
 このビット列をint型だと思うと
– ビックエンディアンなら
• 0xC0F80000 = -1057488896 という整数
– リトルエンディアンなら
• 0x0000F8C0 = 63680という整数
37
0 x C 0 F 8 0 0 0 0
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
=1bit
型と数値
 このビット列をfloat型だと思うと
– ビックエンディアンなら
• 0xC0F80000 = -7.75という数値
– リトルエンディアンなら
• 0x0000F8C0 = 0.0という数値
38
0 x C 0 F 8 0 0 0 0
0xC 0x0 0xF 0x8 0x0
1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
=1bit
型と数値
 0xC0F80000が格納されている領域の
先頭アドレスがポインタに代入されている
39
unsigned int a = 0xC0F80000;
unsigned int *p1 = &a;
int *p2 = (int *)&a;
float *p3 = (float *)&a;
※ &aの左の(int *)などはキャストと呼ばれる。
キャストにより型の変換をすることができる。
アドレスに対してキャストを行った場合、
アドレスの値は変わらないが、アドレスの型のみが変わる。
型と数値
 0xC0F80000が格納されている領域の
先頭アドレスがポインタに代入されている
 このとき、保持しているポインタの型に
よって、読みだした結果が異なる!
40
unsigned int a = 0xC0F80000;
unsigned int *p1 = &a;
int *p2 = (int *)&a;
float *p3 = (float *)&a;
// 3237478400, -1057488896, -7.750000
printf(“%u, %d, %fn”, *p1, *p2, *p3);
型
 つまり、C言語における型は
を表す
 アドレスのみを保存するポインタ変数は、
指し示す先の型の情報が無いとメモリに
アクセスできない!
41
メモリ上のデータの格納方式
メモリ上のデータの読込方式
普通の変数と配列の(メモリ上の)違い
普通の変数
 別個に変数を定義
– int a, b, c;
 各変数が連続した領域に
置かれるとは限らない
配列
 配列で定義
– int a[3];
 各要素は連続した領域に
必ず置かれる。
42
図解
43
 int a, b, c;
a c b
 int a[3];
a[0] a[1] a[2]
必ず連続
連続とは限らない
= 1byte
ここまでのまとめ
 ビット列が同じでも、格納方法や型が違えば違う値!
44
0 x C 0 F 8 0 0 0 0
3237478400
63680 -7.75
-1057488896
0.0
ここまでのまとめ
 配列は連続した領域に置かれる
45
a[0] a[1] a[2]
必ず連続
int a[3];
= 1byte
配列のアクセスの原理を理解する
連続した領域+ポインタ=ランダムアクセス
46
覚えるべき文法(1)
 配列名だけを書いたとき、
– sizeofや&の対象ならば、配列全体を意味
– それ以外ならば、配列の先頭要素のアドレス
47
int a[5] = {1, 2, 3, 4, 5};
printf(“%un”, sizeof(a));
someFunction(&a);
int (*p)[5] = &a;
int *p1 = a;
int *p2 = a + 1;
someFunction(a);
printf(“%pn”, a + 1)
配列全体 配列の先頭要素へのアドレス
覚えるべき文法(2)
 配列名(sizeofや&の対象の場合を除く)を書いたと
きに得られるアドレスの型は、(配列要素の型)へ
のポインタ型。
48
int a[4]; なら、aの型は、int *
float a[2]; なら、aの型は、float *
char a[6]; なら、aの型は、char *
覚えるべき文法(3)
 配列の糖衣構文(シンタックスシュガー)
49
array[i] = *(array + i)
 この2つの表記は完全に同じ意味
 配列の宣言の時の[]は別物。
– この[]は、配列を使うときの[]。
配列アクセスを理解
50
 int a[3] = {1, 2, 3};
a[0] a[1]
必ず連続
1 2
a[2]
3
= 1byte
配列アクセスを理解
 a[2]
51
a[0] a[1]
必ず連続
1 2
a[2]
3
= 1byte
配列アクセスを理解
 *(a + 2)
52
a[0] a[1]
必ず連続
1 2
a[2]
3
= 1byte
配列アクセスを理解
 *(a + 2)
53
a[0] a[1]
必ず連続
1 2
int *
幅はint
a int
a[2]
3
= 1byte
配列アクセスを理解
 *(a + 2)
54
a[0] a[1]
1 2
int *
幅はint
a + 2
a[2]
3
int
+2すると、
sizeof(int) * 2 = 8 byte分進む
8byte
= 1byte
配列アクセスを理解
 *(a + 2)
55
a[0] a[1]
1 2
a + 2
a[2]
3
int
この領域をint型で
読み取り
⇒3が読みだされる
= 1byte
ポインタを使っても同じ!
 int a[3] = {1, 2, 3};
 int *p = a; //ポインタ変数にアドレス代入
 printf(“%dn”, p[2]);
56
a[0] a[1]
1 2
p + 2
a[2]
3
int*(p + 2)=
= 1byte
動的配列
(実行時に要素数を指定できる配列)
 #include <stdlib.h>をして使える、malloc
– memory allocation (メモリ確保)
 malloc(確保したいバイト数);
– とすると、連続した確保したいバイト数分の
領域が確保される。
– 返り値は、確保した領域の先頭アドレス
(指している型の情報無し。つまりvoid *)
– 仕方がないので返り値はキャストして使う
57
動的配列(図解)
58
 malloc(8);
とりあえず8byte分だけ確保
返り値(アドレス)
= 1byte
動的配列(図解)
59
 int *p = (int *)malloc(8);
返り値をpへ
p
p[0] p[1]
配列の記法で
領域を扱える
= 1byte
動的配列(図解)
60
 short int *p = (short int *)malloc(8);
返り値をpへ
p
p[0] p[1]
配列の記法で
領域を扱える
p[2] p[3]
= 1byte
動的配列
 環境によってintやshort intなどの型の大き
さは変わる
 引数には sizeof(型)*欲しい要素数を入れる
61
int *p = (int *)malloc(sizeof(int) * 2);
呪文(?)の完成!
配列の配列
 二次元配列の正体は、配列の配列
– つまり、配列の要素として配列を含んでいる
 char a[2][3]; のとき、aはchar型の配列(要
素数3)を要素とする、要素数2の配列。
 aのアドレスの型は、 char型の配列(要素
数3)へのポインタ型
62
配列の配列(図解)
 char a[2][3] = {{1,2,3}, {4,5,6}};
63
a
1 2 3 4 5 6
 a[1]
a+1
1 2 3 4 5 6
=*(a + 1)
*(a + 1)…char [3](配列)
= 1byte
配列の配列(図解)
64
 *(a+1)はchar [3](配列)だが、次に+2という演算が控えているため
先頭要素へのアドレスに読み替えられる
a+1
1 2 3 4 5 6
*(a + 1)…char [3](配列)
*(a + 1)…char * (先頭要素へのポインタ型)
*(a+1)
1 2 3 4 5 6
= 1byte
配列の配列(図解)
65
 a[1][2]
*(a+1)…char *
1 2 3 4 5 6
*(a+1)+2…char *
 a[1][2] = *(*(a + 1) + 2)
⇒6が読みだされる
= 1byte
配列へのポインタ
 途中で登場した、「char型の配列」へのポ
インタの定義がこちら。
 間違えても、char *p[5]; と勘違いしてはい
けない。
– こちらは、char *が5つ格納されている配列 66
char (*名前)[配列の要素数];
(例)
char a[5]; を指すポインタは、char (*p)[5];
char (*p)[5] = a;
ここまでのまとめ
 配列の要素は、連続した領域に置かれる
 配列名は、(基本的に)先頭要素へのアドレ
ス
– このアドレスの型は、配列の要素の型へのポイン
タ型
 このアドレスをポインタ演算したり、ポイン
タ変数に入れたりして配列っぽく使用。
– このとき、*(array + i) = array[i]である。
 二次元配列は、配列の配列であり、ポインタ
演算の規則をうまく使って要素にアクセスし
ている。
67
理解度チェック
 バイトオーダーはリトルエンディアンとします。
次のア~カの行で表示される数値は?(次ページに補足有)
68
int arr[] = {0x01234567, 0x89abcdef, 0xc0f80000};
int *p1 = arr;
char *p2 = (char *)arr;
float *p3 = (float *)arr;
printf(“%un”, sizeof(arr));
printf(“%un”, sizeof(p2));
printf(“%xn”, p1[1]);
printf(“%xn”, p2[1]);
printf(“%3.2fn”, p3[2]);
printf(“%xn”, *(int *)(p2 + 2));
/* ア */
/* イ */
/* ウ */
/* エ */
/* オ */
/* カ */
理解度チェック(補足)
 バイトオーダーはリトルエンディアンとします。
次のア~カの行で表示される数値は?
69
int arr[] = {0x01234567, 0x89abcdef, 0xc0f80000};
int *p1 = arr;
char *p2 = (char *)arr;
float *p3 = (float *)arr;
printf(“%un”, sizeof(arr));
printf(“%un”, sizeof(p2));
printf(“%xn”, p1[1]);
printf(“%xn”, p2[1]);
printf(“%3.2fn”, p3[2]);
printf(“%xn”, *(int *)(p2 + 2));
/* ア */
/* イ */
/* ウ */
/* エ */
/* オ */
/* カ */
0xで始まる値は16進数を表します
sizeof演算子…演算対象のメモリ上での大きさをバイト単位で計算します
%u…符号なし整数10進数として出力します
%x…16進数として出力します
%3.2f…全体で3桁、小数部分は2桁になるように小数点表示します
お約束(再掲)
 この資料では、以下の環境を仮定します
– sizeof(int) = 4
– sizeof(short int) = 2
– sizeof(float) = 4
– sizeof(double) = 8
– sizeof(ポインタ型) = 4
– 1byte = 8bit
– C言語の規約はANSI C
– float型・double型の表現方法は IEEE754
– 文字コードはASCII
– とくに指示がない限りバイトオーダーは
リトルエンディアン
70
理解度チェック(ヒント)
 迷ったらメモリの図を書こう!
71
0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x?? 0x??
arr[0] arr[1] arr[2] = 1byte
 バイトオーダーに注意。
 arrだけでなく、p1, p2, p3もメモリ上に確保
される
理解度チェック(答え)
 ア: 12
 イ: 4
 ウ: 0x89abcdef
 エ: 0x45
 オ: -7.75
 カ: 0xcdef0123
72
理解度チェック(解説:前提)
 int arr[] = {0x01234567, 0x89abcdef,
0xc0f80000};
 のメモリ上の姿を書くと……
73
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2]
 要素はメモリ上で必ず連続して配置
 各要素ごとにリトルエンディアンで格納
= 1byte
理解度チェック(解説:ア)
 printf(“%un”, sizeof(arr));
74
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
 sizeof(配列)は配列全体の大きさをバイト単位で返す
 arrは全体で12byteの配列
arr (12byte)
理解度チェック(解説:イ①)
 char *p2 = (char *)arr;
75
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p2
※このarrは先頭要素arr[0]のアドレスとなる。型はint *
 arrはint *となるが、(char *)とキャストしているので、
問題なくポインタ変数p2にarr[0]のアドレスが入る
理解度チェック(解説:イ②)
 printf(“%un”, sizeof(p2));
76
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p2(ポインタ変数)の領域(4byte)を返す
4byte
p2
理解度チェック(解説:ウ①)
 int *p1 = arr;
77
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p1
理解度チェック(解説:ウ②)
 p1[1] は *(p1 + 1)
78
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p1+1
この領域をintで読み取る
 読み出すときもバイトオーダを意識する
– 読み出すと 0x89abcdef となる
理解度チェック(解説:エ)
 p2[1]は *(p2 + 1)
79
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p2+1
 読み出すと、0x45。
 バイトオーダーによって結果が変わる!
– (ビックエンディアンの場合……0x23)
この領域をcharで読み取る
理解度チェック(解説:オ①)
 float *p3 = (float *)arr;
80
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p3
理解度チェック(解説:オ②)
 p3[2] は *(p3 + 2)
81
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p3+2
この領域をfloatで読み取る
 バイトオーダーを考えて読むと0xc0f80000
理解度チェック(解説:オ③)
82
 0xc0f80000は2進数で……
1100 0000 1111 1000 0000 0000 0000 0000
0xc 0x0 0xf 0x8 0x0 0x0 0x0 0x0
 IEEE754で読むと
1 10000001 11110000000000000000000
上位1ビット目…符号はマイナス
上位2-9ビット目…指数は129-127=2
その他…データは2進数で1.11110000……
-1 * (1.1111) * 2^(129-127) = -111.11 = -7.75
2進数 2進数
理解度チェック(解説:カ①)
 *(int *)(p2 + 2)
83
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
p2+2
 p2+2は0x23の領域を指す
理解度チェック(解説:カ②)
 *(int *)(p2 + 2)
84
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
(int *)(p2+2)
 int *にキャストしたことで、指す領域が広がる
理解度チェック(解説:カ③)
 *(int *)(p2 + 2)
85
0x67 0x45 0x23 0x01 0xef 0xcd 0xab 0x89 0x00 0x00 0xf8 0xc0
arr[0] arr[1] arr[2] = 1byte
(int *)(p2+2)
 バイトオーダーに気をつけて読み取ると
0xcdef0123となる。
この領域をintで読み取る
関数の引数にポインタを渡す
間接的なアクセス方法
86
関数にポインタを渡す
 ここでは原理のみ。表記の問題等は後で
87
void someFunc(int *p) {
printf(“%dn”, *p);
}
int main(void) {
int value = 3;
int *pValue = &value;
someFunc(pValue);
return 0;
}
何が起こっているのか?
メモリマップ
 メモリは、使用用途によって領域が分かれている。
 静的領域…プログラムの開始から終了まで読書可
 定数領域…絶対に書き換えない。プログラムの開始
から終了まで使える。読込のみ可。
 スタック領域… 関数ごとの領域。その関数が実行中
の間使える。読書可。
 ヒープ領域…mallocなどで使用。解放するまで読書可
88
メモリマップ(図解)
89
int global = 3;
void func2() {
printf(“Hellon”);
}
void func1(int a) {
int b = 1;
func2();
printf(“%d,%dn”, a , b);
}
int main(void) {
func1(1);
}
global 静的
“Hellon”
“%d,%dn”
定数
a
b
スタック(func2)
スタック(func1)
スタック(main)
メモリ
メモリマップ(図解)
90
global 静的
“Hellon”
“%d,%dn”
定数
a
b
スタック(func2)
スタック(func1)
スタック(main)
メモリ
ずっと使える。
書き換え可
ずっと使える。
書き換え不可
関数が始まってから
終わるまで使える。
書き換え可
関数に値を渡す
 関数に値を渡すと、その値は渡した先に
コピーされる
– ポインタの値だろうがコピーされます。
91
void someFunc(int *p) {
printf(“%dn”, *p);
}
int main(void) {
int value = 3;
int *pValue = &value;
someFunc(pValue);
return 0;
}
value;
pValue;
p(pValueの値を
コピー)
スタック( main )
スタック( someFunc )
関数に値を渡す
 渡したものがポインタだと、関数外の領域
にアクセスできるようになる。
92
void someFunc(int *p) {
printf(“%dn”, *p);
}
int main(void) {
int value = 3;
int *pValue = &value;
someFunc(pValue);
return 0;
}
value;
pValue;
p(pValueの値を
コピー)
ア
ク
セ
ス
スタック( main )
スタック( someFunc )
イメージ
 webにアップロードした写真のURLを友達
に教える
– URL自身はコピーされている
– 写真はコピーされない
– 友達も写真にアクセスできる。
93
http://xxx.com/yyy.jpg
http://xxx.com/yyy.jpg
アクセス アクセス
ダメな参照
 呼び出し元と呼び出し先の関数で値をやり
取りする際の注意
 呼び出し先関数内の領域を指すポインタを
呼び出し元で使ってはいけない!!
– 呼び出し元で使うときには、呼び出し先の関
数の実行は終わっている
– メモリマップ的にアウト。
– どうなるかわからない(動作未定義)
94
ダメな参照(例)
95
int *someFunc() {
int value = 3;
return &value;
}
int main(void) {
int *p = someFunc();
printf(“%dn”, *p);
return 0;
}
main
someFunc
p
value
main
someFunc
p
value
使えないアドレス
ダメな参照(イメージ)
96
 webにアップロードした写真のURLを友達
に教える
 何故か教えた瞬間にうp主が写真を削除
①http://xxx.com/yyy.jpg
http://xxx.com/yyy.jpg
②削除 ③アクセス
できない
404 NotFound
良い参照
 関数内で作った値へのポインタを返したいときは、
その領域を動的確保します。
 動的確保された領域は、ヒープ領域に入るため、
明示的に開放しない限りメモリ上に残ります。
97
int *someFunc() {
int *p = (int *)malloc(sizeof(int));
*p = 3;
return p;
}
int main(void) {
int *p = someFunc();
printf(“%dn”, *p);
free(p);
return 0;
}
※mallocした領域は、
使い終わったら必ずfreeしましょう。
関数にポインタを渡すメリット
98
1 コピーコスト削減
アドレスしかコピーしないので、
コピーする量・時間が減る
2 データの一貫性保持
データを更新すればその変更が向こうにも伝わる
3 複数の値を返す関数
複数のアドレスを渡しておけば、
複数の値を返す関数のようなものを作れる。
ここまでのまとめ
 関数にポインタを渡すことができる
– 渡された値はポインタであろうとコピーされる
– 呼び出し先から呼び出し元の変数を参照できる
 呼び出し元から呼び出し先の変数の参照を
するときは注意。
– 動的確保した領域へのポインタを返せばOK
 コピーコスト削減、データの一貫性を保つ、
複数の値を返せるなどの利点がある。
99
文字列
文字の配列
100
文字と文字列
文字
 通常、‘A’や’b’とかをchar
型変数に格納。
– 実際に格納されるのは文字
に対するアスキーコード
(数値)
 1文字のみ表す
文字列
 「文字」が配列になった
もの
– char str[3] = {‘a’, ‘b’, ‘0’};
 文字配列の最後に番兵と
して’0’を入れる
– 文字列の終端が分かる
101
文字列(図解)
102
 char str[3] = {‘a’, ‘b’, ‘0’};
str
‘a’ ‘b’ ‘0’
 printf(“%s”, str);
str
‘a’ ‘b’ ‘0’
strから’0’のアドレスまで表示
“ab”
= 1byte
文字列(図解)
103
 char str[3] = {‘a’, ‘b’, ‘0’};
 printf(“%s”, str); p = str
‘a’ ‘b’ ‘0’
char *p = str;
while(*p != ‘0’) {
printf(“%c”, *p);
p++;
}
p
‘a’ ‘b’ ‘0’
p
‘a’ ‘b’ ‘0’
p++
p++
‘a’
‘b’
終了
= 1byte
文字列とポインタ
 配列の先頭をポインタに格納すれば、
ポインタで文字列を扱うこともできる
104
char str[3] = {‘a’, ‘b’, ‘0’};
char *str_p = str;
printf(“%s”, str_p);
str_p = str
‘a’ ‘b’ ‘0’
str_pは指している場所を
自由に場所を変更できる
strの場所の変更は不可能
(strはコンパイル時定数)⇔= 1byte
ややこしい表記
105
char str[3] = {‘a’, ‘b’, ‘0’};
char str[] = {‘a’, ‘b’, ‘0’};
char str[] = “ab”;
文字列のために
用意された文法
(シンタックス
シュガー)
配列のルール
ややこしい表記
106
char str[] = “ab”;
char *str = “ab”;
図解
 char str[] = “ab”;
 char *str = “ab”;
107
ローカル‘a’ ‘b’ ‘0’
str(コンパイル時定数)
定数‘a’ ‘b’ ‘0’
str
ローカル
= 1byte
char *の配列とcharの2次元配列
char *の配列
 char *a[] = {“ab”, “cde”};
 スタックに各要素(ポインタ)
– ポインタの指す場所は変更可能
 定数域にデータ
– ポインタの指すデータは変更不可能
 領域を無駄なく利用
char の二次元配列
 char a[2][4] = {“ab”, “cde”};
 スタックにデータ
– データは書き換え可能
– aはスタック領域の配列
{“ab”, “cde”}の先頭を指すア
ドレス定数
 無駄な領域が発生
108
目次方式 表方式
図解
 char *a[] = {“ab”, “cde”};
109
定数‘a’ ‘b’ ‘0’
a[0]
ローカル
a[1]
‘c’ ‘d’ ‘e’ ‘0’
a…char *へのポインタ
※a[0], a[1]はchar *
= 1byte
図解
 char a[2][4] = {“ab”, “cde”};
110
ローカル‘a’ ‘b’ ‘0’ ‘c’ ‘d’ ‘e’ ‘0’
a…char [4]へのポインタ
※a[0], a[1]はchar [4](配列)だが、
次の演算がsizeof, &以外の場合、
char *(先頭要素へのポインタ)になる
= 1byte
char *の配列とcharの2次元配列(共通点)
 共通点は、どちらもa[i]がchar *となること。
– しかもそのポインタは文字列の先頭を指す
– 両方とも、文字列の配列として利用できる
 さらに、a[i][j]と書くと、i個目の文字列のj
番目の文字を表せる
111
使い方はほぼ同じだが、メモリの構造は違う!
ここまでのまとめ
 文字列はchar の配列である。
 文字列の最後に番兵として’0’を置く
 char str[] = {‘a’, ‘b’, ‘0’} は char str[] = “ab”;
と同じ意味
– これもシンタックスシュガー
– 文字列のために用意された文法
 char str[][hoge];とchar *str[]は同じように使う
ことができるが、メモリの構造は異なる
112
構造体へのポインタ
基本がわかっていれば怖くないけど、応用例が多い
113
構造体
 いろいろな型を並べて新しい型を作れる
114
typedef struct {
char name[10];
int age;
} person;
 person型はchar[10]とintを並べた型
構造体
 構造体を使う
115
typedef struct {
char name[10];
int age;
} person;
…
person john = {“John”, 21};
printf(“%s %dn”, john.name, john.age);
 構造体の中の名前でアクセスできる
メモリ上の構造体
 構造体の宣言は、メモリ上のレイアウトを決めている
116
typedef struct {
char name[10];
int age;
} person;
name age
0 10index
= 1byte
メモリ上の構造体
 メンバ変数とindex(相対位置)を紐づけている
117
typedef struct {
char name[10]; //開始indexは0
int age; //開始indexは10
} person;
name age
0 10index
= 1byte
アライメント
 構造体は配列とは違い、必ずしもその中身が連続
するとは限らない
 OS・CPUが扱いやすい単位に揃えられてデータの
レイアウトが決まることがある
 扱いやすい単位をアライメントという。
 charのアライメントは1byte、intのアライメントは
4byteなど。(環境依存)
118
name age
0 12index 4の倍数
データがどのようにアラインされても、
メンバ変数でアクセスすれば問題ない
= 1byte
構造体へのsizeof
 レイアウトの結果定まった、構造体全体のサイズ
を返す。
– 正確には、この構造体を配列に入れて並べたときの
隣り合う2要素間のアドレスの差をbyteで返す。
 アライメントの関係で、sizeof(構造体)がsizeof(メ
ンバ変数)の総和と等しくなるとは限らない
119
0 10index
sizeof(person) = 14
= 1byte
構造体へのsizeof
120
sizeof(person) = 16
0 12index
 レイアウトの結果定まった、構造体全体のサイズ
を返す。
– 正確には、この構造体を配列に入れて並べたときの
隣り合う2要素間のアドレスの差をbyteで返す。
 アライメントの関係で、sizeof(構造体)がsizeof(メ
ンバ変数)の総和と等しくなるとは限らない
= 1byte
構造体へのポインタ
 構造体へのポインタを定義して使う
 person *p = &john;
 printf(“%s %dn”, p->name, p->age);
 ポインタからメンバ変数にアクセスする時
は.ではなく->を使う。
121
a->b = (*a).b
これもシンタックスシュガー
構造体を関数に渡す
 構造体はデータの塊。これを関数に渡すと
データがコピーされる。
 巨大な構造体だとコピーするのに
時間とメモリ領域が消費される。
 ポインタを渡せば、一瞬でデータを渡せる。
 ただし、データを書き換えると
その変更は呼び出し元に伝わる。
122
構造体を関数に渡す
123
John
person *p = &john;
p
呼び出し元関数
func関数
120
= 1byte
構造体を関数に渡す
124
John
person *p = &john;
p
呼び出し元関数
func関数
func(p);
↑ 4バイトだけコピー
120
p
= 1byte
構造体を関数に渡す
125
John
person *p = &john;
p
呼び出し元関数
func関数
func(p);
p->age = 14;
12 書き換え
0
ageの
indexは12
p
= 1byte
構造体へのポインタまとめ
 複数の型を融合して新しい型を定義できる
 構造体の宣言はメモリ上のレイアウトを決
めている
 メンバ変数がメモリ上の相対位置を記憶
 アライメントに注意。
 巨大な構造体でも、ポインタを経由して他
の関数に素早く渡すことができる。
126
関数ポインタ
とにかく記法が難しい。使い方は難しくない。
関数を持ち運べる便利な変数!
127
まずは関数ポインタ
128
 関数名も実はアドレス
 アドレスの型として実際に使うときの情報
つまり、「引数の型・順番」「返り値の型」
が分かれば良い。
char func(char *p, int n);
返り値の型と
引数の型・順番が同じ
なら同じ型
関数ポインタ
 関数を格納するためのポインタpfuncの宣言
 関数を持ち運べる便利な変数と考えると良い
129
char (*pfunc)(char *, int);
 何が変わったのか?
– かっこを左にもつけた
• ポインタであるということを示すため
– 引数の名前は削除
• 型が重要だから
関数ポインタの使い方
130
char func1(char *p, int n) {
return p[n];
}
char func2(char *p, int n) {
return *p + n;
}
int main(void) {
char (*pfunc)(char *, int);
pfunc = func1;
//pfunc = func2;
printf(“%c”, pfunc(“aaa”, 1));
}
どっちも型
が等しい
関数ポインタ
pfuncの宣言
どちらのアドレ
スでも代入可
呼び出しは
いつも通り
関数ポインタの配列
131
char (*pfunc[3])(char *, int);
 関数を格納するためのポインタ配列の宣言
 何が変わったのか
– 変数名の右に配列を表す[]がついた
関数ポインタの使い方
132
char func1(char *p, int n) {
return p[n];
}
char func2(char *p, int n) {
return *p + n;
}
int main(void) {
char (*pfunc[2])(char *, int);
pfunc[0] = pfunc1;
pfunc[1] = pfunc2;
printf(“%c”, pfunc[0](“aaa”, 1));
}
どっちも型
が等しい
関数ポインタの
配列pfuncの宣言
どちらのアドレ
スでも代入可
関数ポインタを引数に取る
 関数ポインタは関数の引数にもできます
– すごく記述が複雑になるが、落ち着いてみれ
ばOK
 関数の引数として関数を与えられる
– 関数内から、与えられた関数を呼べる
– コールバック関数
133
int func(int n, char (*pfunc)(char *, int)) {
…
}
関数ポインタを返り値にする
134
char (*func(int n))(char *, int) {
…
}
 返り値なのに、左右から挟み込む新発想!
– C言語の規格なので仕方ない。
 後で処理してほしい関数などを返せる
目次
135
記法
使い方
原理
表記は同じだけど意味が違う
混同しやすいので注意
136
*
 *は3つの意味を持つ。
137
1 ポインタの宣言の*
int *p; など、「自分はポインタである」ことを
示すための*。関数の引数の*もこっちの意味。
2 ポインタ参照の*
ポインタ(またはアドレス)の前につける*。
そのアドレスの値を参照する。
3 掛け算の*
2 * 3とか。
[]
 []も3種類。
138
1 配列の定義の[]
配列を定義するときに使う[]。
配列の要素数を表す。
2 配列の要素の参照の[]
配列の要素を参照するときに使う[]。
*(array + i) = array[i]と言い換えられる。
3 関数の仮引数の[]
これは、関数の引数にポインタ渡しするとき
見た目だけでも配列にするための[]。後述。
“”
 “”は2種類。
139
1 文字列リテラルの””
定数領域に格納される文字のデータを表す””
ほとんどの””はこちらに分類される。
型としては、char []となる。
2 charの配列を初期化するための””
char str[] = {‘a’, ‘b’, ‘0’}; と書くのが面倒なので
char str[] = “ab”; と書けるようにした。
上の””とは関係はない。
配列名
140
1 配列の先頭要素へのポインタ
ほとんどの配列名はこちらに分類される。
type型の配列の場合、配列名を書くとtype *型となる
2 配列全体
sizeof(配列)または、&配列で使われたとき。
前者は配列全体の大きさ(byte)、
後者は配列全体に対するポインタを計算する。
 配列名は2種類
表記は違うけど意味が同じ
こっちも混同しやすいので注意
141
関数の引数
 関数引数の宣言
142
void func(int *p) {
}
void func(int p[]) {
}
関数の引数
 どうして?
 ⇒関数に渡すときに、元が配列であるという情報
はどのみち消える。呼び出し元が配列であったこ
とを明示したい!
143
void func(int *p) {
…p[i]…
}
void func(int p[]) {
…p[i]…
}
 実際に意味を考えるときは、ポインタ記法
に戻して考える。
 Q. sizeof(p)は? ⇒ 4
関数の引数
 関数引数の宣言
144
void func(int **p) {
}
void func(int *p[]) {
}
Q. sizeof(p)は?
⇒ 4
関数の引数
 関数引数の宣言
145
void func(int (*p)[3]) {
}
void func(int p[][3]) {
}
Q. sizeof(p)は?
⇒ 4
配列のルール
146
a[i]
*(a + i)
もちろん、
参照時の[]
(式の中の[])
文字の配列
147
char str[3] = {‘a’, ‘b’, ‘0’};
char str[] = {‘a’, ‘b’, ‘0’};
char str[] = “ab”;
文字列のた
めに用意さ
れた文法
配列のルール
const
 int i = 1; // 普通の変数
 const int ic = 1; // 書換不可能
 const int *p1 = &ic; // p1は書換可能。p1
の指す先は書換不可能
 int * const p2 = &i; // p2は書換不可能。p2
の指す先は書換可能
 const int * const p3 = &ic; // p3もp3の指
す先も書換不可能
148
複雑な記法
英訳→和訳
149
複雑な記法
 char (*p)[3];
 char (*func)(char *, int);
 char (*func(int n))(char *, int) {
 …
 複雑な記法が多い。
 どうにかして解読できないか?
150
まず英訳
151
1 中心の名前を見つける
変数や変数の名前。
真ん中にあることが多い。
見つかったら(名前) is をつける。
2 )に突き当たるまで右に読む
この時、[にあたったら array[要素数] of をつける
(にあたったらfunction(引数リスト) returning
をつける。
3 突き当たった)に対応する(まで戻る
このとき*にあたったらpointer toをつける
終わったら②へ
char (*p)[3]
152
1 中心の名前を見つける
p
p is
char (*p)[3];
なう
char (*p)[3]
153
2 )に突き当たるまで右に読む
すでに突き当たっている
char (*p)[3];
p is
なう
char (*p)[3]
154
3 突き当たった)に対応する(まで戻る
戻るときに、*に当たるので、
pointer to をつける
char (*p)[3];
p is pointer to
なう
char (*p)[3]
155
2 )に突き当たるまで右に読む
[が見える。array[3] of をつける
char (*p)[3];
p is pointer to array[3] of
なう
char (*p)[3]
156
3 突き当たった)に対応する(まで戻る
一番最後に)がいると思って、
まだ読んでいないところまで左に戻ると
char.
char (*p)[3];
p is pointer to array[3] of char
p はchar[3]配列へのポインタ
なう
char (*(*p)())[5];
157
1 中心の名前を見つける
p
p is
char (*(*p)())[5];
なう
char (*(*p)())[5];
158
p is
char (*(*p)())[5];
なう
2 )に突き当たるまで右に読む
すでに突き当たっている
char (*(*p)())[5];
159
p is pointer to
char (*(*p)())[5];
なう
3 突き当たった)に対応する(まで戻る
戻るときに、*に当たるので、
pointer to をつける
char (*(*p)())[5];
160
p is pointer to function(void) returning
char (*(*p)())[5];
なう
2 )に突き当たるまで右に読む
途中で(に出会う。
function(void) returningをつけて次へ
char (*(*p)())[5];
161
p is pointer to function(void) returning
char (*(*p)())[5];
なう
2 )に突き当たるまで右に読む
突き当たった
char (*(*p)())[5];
162
p is pointer to function(void) returning
pointer to
char (*(*p)())[5];
なう
3 突き当たった)に対応する(まで戻る
戻るときに、*に当たるので、
pointer to をつける
char (*(*p)())[5];
163
p is pointer to function(void) returning
pointer to array[5] of
char (*(*p)())[5];
なう
2 )に突き当たるまで右に読む
[が見える。array[5] of をつける
char (*(*p)())[5];
164
p is pointer to function(void) returning
pointer to array[5] of char.
char (*(*p)())[5];
なう
3 突き当たった)に対応する(まで戻る
一番最後に)がいると思って、
まだ読んでいないところまで左に戻ると
char.
char (*(*p)())[5];
165
p is pointer to function(void) returning
pointer to array[5] of char.
char (*(*p)())[5];
p は「char[5]配列へのポインタ」
を返す関数へのポインタ
目次
166
記法
使い方
原理
ポインタの使い方(1)
 代表的な使い方
167
1 関数間で構造体を渡す
データの塊を渡す。
ポインタを通してデータにアクセス
2 構造体をつなげる
構造体が他の構造体を知ることが
できる。リスト構造とかもこれ
3 文字列を扱う
先頭アドレスだけで文字列を表す
ポインタの使い方(2)
 その他の使い方
168
1 動的配列
動的に確保した領域の先頭を指すポインタ
C++では配列だけではなく、
オブジェクトも動的にとれる
2 コールバック処理の実現
関数内の一部処理を外部に決めてもらう
3 メモリをいじる
char *を使えば1バイトずつ読み書き可能
関数間で構造体を渡す
 構造体(データの塊)を渡すには、アドレ
スだけ渡せば十分なことが多い。
169
typedef struct {
char datatype;
int data[10000];
} Bigdata;
void dataProc(Bigdata *p) {
p->data[hogehoge]……
}
int main(void) {
Bigdata p; ……
dataProc(&p);
return 0;
}
main
dataProc
10000*sizeof(int)+1 byte
4 byte
コピーの時間と容量を削減
= 1byte
…
構造体をつなげる
 リスト構造など。定義中の構造体へのポイン
タを、その構造体のメンバ変数に追加する。
170
struct node_{
int value;
struct node_ *p;
};
typedef struct node_ node;
value p
value p
value p
要素同士のつながりをpで表現
要素の追加・削除の計算量が
(配列と比べて)少ない
= 1byte
文字列を扱う
 文字列は文字の配列(の終端に’0’が付加さ
れたもの)
 文字列の先頭文字へのアドレスを捕まえてお
けば、文字列全体を持っていることになる
171
void func(char *p) {
(pを使った処理)
}
int main(void) {
char str[5] = “test”;
char *p = “hello”;
func(str);
func(p);
…
}
‘t’ ‘e’ ‘s’ ‘t’
‘h’ ‘e’ ‘l’ ‘l’
‘0’
‘o’ ‘0’
p
func
main
定数
= 1byte
動的配列
 呼び出し元で配列の大きさを決定できる
 型宣言・キャストの仕方によってその領域を使う
ときの型を決められる
172
int *p = (int *)malloc(sizeof(int) * 2);
p
p[0] p[1]
char (*p)[3] = (char (*)[3])malloc(sizeof(char) * 6);
p
p[0] p[1]
p[0][0] p[0][1] p[0][2] p[1][0] p[1][1] p[1][2]
char [2][3]の2次元配列を動的確保したい場合:
int [2] の配列を動的確保したい場合:
= 1byte
コールバック処理の実現
 処理の一部を呼び出し側に決定させる
 qsort関数など(要素の大小の定義は外部で定義する)
 イベント駆動プログラミングにも最適
173
typedef struct {
int w, h;
} Rect;
int comp_by_area(const void *a, const void *b) {
return (Rect *)a->w * (Rect *)a->h – (Rect *)b->w * (Rect *)b->h;
}
int main(void) {
Rect data[] = {{3, 5}, {4, 4}, {2, 7}};
qsort(data, sizeof(data)/sizeof(data[0]), sizeof(Rect), comp_by_area);
// data[] = {{2, 7}, {3, 5}, {4, 4}};
……
}
aの指すオブジェクトがbの指すものより
大きければ正
等しければ0
そうでなければ負の値
を返すような関数を定義
qsortの定義によると定義
すべき関数の型はint
(const void *a, const void
*b)である。これは任意の
型のオブジェクトに対応で
きるようにするため。
大小関係を定義した関数である
comp_by_areaを使ってソート。
大小関係の比較はcomp_by_areaで、
比較順などの最適化はqsortで行う。
メモリをいじる
 char *は1byte単位でのメモリ操作が可能
 組み込み等のプログラミングでは良く出てくる
174
char *p = (char *)0x12345678; // 整数をアドレスに変換
*p = 0xff;
…
 OSなどの実行環境によってアクセスでき
る領域が限られることがあるので注意
参考文献
 『 C言語ポインタ完全制覇』,前橋 和弥, 技
術評論社, 2001
 『プログラミング言語C 第2版 ANSI規格準
拠』, B.W. カーニハン (著), D.M. リッチー
(著), 石田 晴久 (翻訳), 共立出版, 1989
 ポインタ虎の巻
http://www.nurs.or.jp/~sug/soft/tora/
175

More Related Content

What's hot

ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門Eita Sugimoto
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門Kimikazu Kato
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexprGenya Murakami
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
 
カスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてカスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてalwei
 
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjpcocodrips
 
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)Hiro H.
 
ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門k h
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~Takuya Akiba
 
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~Takuya Akiba
 
競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略K Moneto
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだGenya Murakami
 

What's hot (20)

ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
はじめての「R」
はじめての「R」はじめての「R」
はじめての「R」
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 
C言語超入門
C言語超入門C言語超入門
C言語超入門
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
カスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてカスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについて
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp
強くなるためのプログラミング -プログラミングに関する様々なコンテストとそのはじめ方-#pyconjp
 
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
 
グレブナー基底を食べよう
グレブナー基底を食べようグレブナー基底を食べよう
グレブナー基底を食べよう
 
ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
 
グラフネットワーク〜フロー&カット〜
グラフネットワーク〜フロー&カット〜グラフネットワーク〜フロー&カット〜
グラフネットワーク〜フロー&カット〜
 
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
 
競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
 

Similar to C言語ポインタ講座 (Lecture of Pointer in C)

解説#1 C言語ポインタとアドレス
解説#1 C言語ポインタとアドレス解説#1 C言語ポインタとアドレス
解説#1 C言語ポインタとアドレスRuo Ando
 
Javaセキュアコーディングセミナー東京第2回講義
Javaセキュアコーディングセミナー東京第2回講義Javaセキュアコーディングセミナー東京第2回講義
Javaセキュアコーディングセミナー東京第2回講義JPCERT Coordination Center
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Yuto Takei
 
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】Proktmr
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介MITSUNARI Shigeo
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由kikairoya
 
C++11概要 ライブラリ編
C++11概要 ライブラリ編C++11概要 ライブラリ編
C++11概要 ライブラリ編egtra
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
 
El text.tokuron a(2019).watanabe190613
El text.tokuron a(2019).watanabe190613El text.tokuron a(2019).watanabe190613
El text.tokuron a(2019).watanabe190613RCCSRENKEI
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354Taku Miyakawa
 
Learning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.GeomtryLearning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.GeomtryAkira Takahashi
 
NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門Shiqiao Du
 
とあるFlashの自動生成
とあるFlashの自動生成とあるFlashの自動生成
とあるFlashの自動生成Akineko Shimizu
 

Similar to C言語ポインタ講座 (Lecture of Pointer in C) (20)

解説#1 C言語ポインタとアドレス
解説#1 C言語ポインタとアドレス解説#1 C言語ポインタとアドレス
解説#1 C言語ポインタとアドレス
 
Javaセキュアコーディングセミナー東京第2回講義
Javaセキュアコーディングセミナー東京第2回講義Javaセキュアコーディングセミナー東京第2回講義
Javaセキュアコーディングセミナー東京第2回講義
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
 
C++11のつかいかた
C++11のつかいかたC++11のつかいかた
C++11のつかいかた
 
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
 
cp-11. ポインタ
cp-11. ポインタcp-11. ポインタ
cp-11. ポインタ
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
Haskell Lecture 2
Haskell Lecture 2Haskell Lecture 2
Haskell Lecture 2
 
C++11概要 ライブラリ編
C++11概要 ライブラリ編C++11概要 ライブラリ編
C++11概要 ライブラリ編
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
 
C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
 
El text.tokuron a(2019).watanabe190613
El text.tokuron a(2019).watanabe190613El text.tokuron a(2019).watanabe190613
El text.tokuron a(2019).watanabe190613
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354
 
Learning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.GeomtryLearning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.Geomtry
 
NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門
 
とあるFlashの自動生成
とあるFlashの自動生成とあるFlashの自動生成
とあるFlashの自動生成
 

C言語ポインタ講座 (Lecture of Pointer in C)