SlideShare a Scribd company logo
ポインタと配列と文字列

  HN:MARISHI



   牛乳おいしいよ>
やること
●   ポインタ
●   ポインタと配列
●   文字列
ポインタとは
●   メモリのアドレスを
    メモリのアドレス     アドレス         メモリの内容
                 0x00000000
    格納する変数       0x00000001
                 0x00000002
                 0x00000003
●   バグの温床        0x00000004
                 0x00000005
                 0x00000006
●   でもこれがないと     0x00000007

    C言語ははじまらない   0x00000008
                 0x00000009
                 0x0000000A
                 0x0000000B
                 0x0000000C
                 0x0000000D
                 0x0000000E
ポインタ・・・の前に
                          アドレス         メモリの内容
                          0x00000000
                          0x00000001 12
int hoge = 12;            0x00000002 (hoge)
char piyo = 'a';          0x00000003
double fuga = 0.123456;   0x00000004
                          0x00000005
                          0x00000006 'a'(piyo)
                          0x00000007 0.123456
32ビット環境では                 0x00000008 (fuga)
int型は4バイト                 0x00000009

char型は1バイト                0x0000000A
                          0x0000000B
double型は8バイト              0x0000000C
                          0x0000000D
                          0x0000000E
ポインタ関連の文法
                       アドレス         メモリの内容
                       0x00000000
                       0x00000001 12
                       0x00000002 (hoge)
int hoge = 12;         0x00000003
                       0x00000004
printf(“%p”,&hoge);   0x00000005
                       0x00000006
//結果:0x00000001        0x00000007
                       0x00000008
                       0x00000009
変数のアドレスを得る             0x0000000A
                       0x0000000B
&変数名                   0x0000000C
                       0x0000000D
                       0x0000000E
ポインタ関連の文法
                 アドレス         メモリの内容
                 0x00000000
int hoge = 12;   0x00000001 12
int *phoge;      0x00000002 (hoge)
                 0x00000003
                 0x00000004
phoge = &hoge;   0x00000005
                 0x00000006 0x00000001
                 0x00000007

ポインタの定義          0x00000008
                 0x00000009
型の名前 *変数の名前;     0x0000000A
                 0x0000000B
/*32ビット環境では      0x0000000C

ポインタは4バイト*/      0x0000000D
                 0x0000000E
ポインタ関連の文法
                         アドレス         メモリの内容
                         0x00000000

int hoge = 12;           0x00000001 12
                         0x00000002 (hoge)
int *phoge;              0x00000003
                         0x00000004
phoge = &hoge;           0x00000005
                         0x00000006 0x00000001
                         0x00000007
printf(“%d” , *phoge);   0x00000008
                         0x00000009
ポインタを通して間接的に             0x0000000A
                         0x0000000B
変数を見る                    0x0000000C
*変数名                     0x0000000D
                         0x0000000E
ダブルポインタの動作
                             アドレス         メモリの内容
int hoge = 22;
                             0x00000000 22
int *phoge;
                             0x00000001 (hoge)
int **pphoge;
                             0x00000002
phoge = &hoge;               0x00000003
pphoge = &phoge;             0x00000004 0x00000000
                             0x00000005 (phoge)
printf("%pn" , phoge );     0x00000006
printf("%pn" , *pphoge );   0x00000007
//結果:0x00000000              0x00000008 0x00000004
                             0x00000009 (pphoge)
printf("%pn" , &phoge );    0x0000000A
printf("%pn" , pphoge );    0x0000000B
//結果:0x00000004              0x0000000C
                             0x0000000D
printf(“%dn”,**pphoge);     0x0000000E
//結果:22
ポインタの例:スワップ
swap1(int a , int b)     int hoge = 5;
{                        int piyo = 10;
  int tmp = b;
  b = a;                 swap1(hoge,piyo);
  a = tmp;               //結果?
}
                         swap2(&hoge,&piyo);
swap2(int *a , int *b)   //結果?
{
  int tmp = *b;
  *b = a;
  *a = tmp;
}
スワップ
swap1(int a , int b)      アドレス         メモリの内容
{                         0x00000000 5

  int tmp = b;            0x00000001 (hoge)
                          0x00000002
  b = a;
                          0x00000003
  a = tmp;                0x00000004 10
}                         0x00000005 (piyo)
...                       0x00000006
                          0x00000007
int hoge = 5;             0x00000008

int piyo = 10;//←今ココ      0x00000009
                          0x0000000A
                          0x0000000B
swap1(hoge,piyo);         0x0000000C
printf(                   0x0000000D
“%d,%d”,hoge,piyo);       0x0000000E
                          0x0000000F
スワップ
swap1(int a , int b)//←今ココ   アドレス         メモリの内容
{                            0x00000000 5
  int tmp = b;               0x00000001 (hoge)
  b = a;                     0x00000002
  a = tmp;                   0x00000003
}                            0x00000004 10
                             0x00000005 (piyo)
...                          0x00000006
                             0x00000007
int hoge = 5;                0x00000008 5
int piyo = 10;               0x00000009 (a)
                             0x0000000A
swap1(hoge,piyo);//←ココの      0x0000000B
printf(“%d,%d”,hoge,piyo);
                             0x0000000C 10
                             0x0000000D (b)
                             0x0000000E
                             0x0000000F
スワップ
swap1(int a , int b)         アドレス         メモリの内容
{                            0x00000000 5
  int tmp = b;               0x00000001 (hoge)
  b = a;                     0x00000002
  a = tmp;//←今ココ             0x00000003
}                            0x00000004 10
                             0x00000005 (piyo)
...                          0x00000006
                             0x00000007
                             0x00000008 10
int hoge = 5;
                             0x00000009 (a)
int piyo = 10;
                             0x0000000A

swap1(hoge,piyo);//←ココの      0x0000000B
printf(“%d,%d”,hoge,piyo);   0x0000000C 5
                             0x0000000D (b)
                             0x0000000E
                             0x0000000F
スワップ
swap1(int a , int b)      アドレス         メモリの内容
{                         0x00000000 5
  int tmp = b;            0x00000001 (hoge)
  b = a;                  0x00000002
                          0x00000003
  a = tmp;
                          0x00000004 10
}
                          0x00000005 (piyo)
...                       0x00000006
                          0x00000007
int hoge = 5;             0x00000008
int piyo = 10;            0x00000009
                          0x0000000A
swap1(hoge,piyo);         0x0000000B
printf(                   0x0000000C
“%d,%d”,hoge,piyo);       0x0000000D
//↑今ココ                    0x0000000E
                          0x0000000F
スワップ
swap2(int *a , int *b)   アドレス         メモリの内容
{                        0x00000000 5

  int tmp = *b;          0x00000001 (hoge)
                         0x00000002
  *b = *a;
                         0x00000003
  *a = tmp;              0x00000004 10
}                        0x00000005 (piyo)
...                      0x00000006
                         0x00000007
int hoge = 5;            0x00000008

int piyo = 10;//←今ココ     0x00000009
                         0x0000000A
                         0x0000000B
swap1(&hoge,&piyo);      0x0000000C
printf(                  0x0000000D
“%d,%d”,hoge,piyo);      0x0000000E
                         0x0000000F
スワップ
swap2(int *a , int *b)//←今ココ   アドレス         メモリの内容
{                              0x00000000 5
  int tmp = *b;                0x00000001 (hoge)

  *b = *a;                     0x00000002
                               0x00000003
  *a = tmp;
                               0x00000004 10
}
                               0x00000005 (piyo)
...                            0x00000006
                               0x00000007
int hoge = 5;                  0x00000008 0x00000000
int piyo = 10;                 0x00000009 (a)
                               0x0000000A
swap1(&hoge,&piyo);//←ココ       0x0000000B
の                              0x0000000C 0x00000004
printf(“%d,%d”,hoge,piyo);     0x0000000D (b)
                               0x0000000E
                               0x0000000F
スワップ
swap2(int *a , int *b)       アドレス         メモリの内容
{                            0x00000000 10
                             0x00000001 (hoge)
  int tmp = *b;
                             0x00000002
  *b = *a;
                             0x00000003
  *a = tmp;//←今ココ            0x00000004 5
}                            0x00000005 (piyo)
...                          0x00000006
                             0x00000007
int hoge = 5;                0x00000008 0x00000000
                             0x00000009 (a)
int piyo = 10;
                             0x0000000A
                             0x0000000B
swap1(&hoge,&piyo);//←ココ     0x0000000C 0x00000004
の                            0x0000000D (b)
printf(“%d,%d”,hoge,piyo);   0x0000000E
                             0x0000000F
スワップ
swap2(int *a , int *b)       アドレス         メモリの内容
{                            0x00000000 10

  int tmp = *b;              0x00000001 (hoge)
                             0x00000002
  *b = *a;
                             0x00000003
  *a = tmp;                  0x00000004 5
}                            0x00000005 (piyo)
...                          0x00000006
                             0x00000007
int hoge = 5;                0x00000008

int piyo = 10;               0x00000009
                             0x0000000A
                             0x0000000B
swap1(&hoge,&piyo);          0x0000000C
printf(“%d,%d”,hoge,piyo);   0x0000000D
//↑今ココ                       0x0000000E
                             0x0000000F
ポインタを使うタイミング
●   動的メモリの管理
●   複数の構造体などから同じデータを参照したい時
●   関数の引数に構造体を利用する時
●   関数の戻り値が2つ以上欲しい時

    etc
動的メモリの確保
int num;
scanf(“%dn”,&num);
int *ary = (int*)malloc( sizeof(int) * n );
複数の「何か」から同じデータを参照
アドレスさえあれば、同じデータを簡単に共有できる。
     int apple_num;//0x00334455


0x00334455            0x00334455

 MARISHI                  kano
複数の「何か」から同じデータを参照
  乱用すると、意図しない値の操作が行われた時に、
  どのプログラムが間違ってるか分かり辛い
      int apple_num;//0x00334455
誰だ5個も食いやがった奴は!

                                0x00334455
0x00334455       0x00334455   *apple_num -= 5
  MARISHI           kano           xALTx




                                       ククク・・・
関数の引数に構造体を使うとき
typedef struct Human
{
   int age;
   int height;
   int weight;
} Human;

//構造体をまるごとコピーして重い。
void print_human(Human h)
{
  printf(“%dn”,sizeof(h) ); //結果:16(環境依存
}

//アドレスのみコピー
void print_human_size_p( Human *ph)
{
  printf(“%dn”,sizeof(ph) ); //結果:4(環境依存
}
関数の戻り値が複数欲しい時
void yanagisawa_info(int *age , int *weight)
{
    *age = 22;
    * weight = …//ヒミツ
}
やること
●   ポインタ
●   ポインタと配列
●   文字列
ポインタと配列
●   ポインタと配列は深い関係ある
●   配列で困ったときはポインタを思い出すと
    納得行くことがあったり無かったり無かったり
●   そして配列死ねよと思う(?)
ポインタと配列の衝撃の事実
●   配列へのアクセスにはポインタも利用できる

    int i;
    int ary[3] = {7,5,3};
    int *p = ary;

    for(i = 0 ; i < 3 ; ++i){
      printf(“%dn” , ary[i] ); //出力結果は
      printf(“%dn” , *(p+i) ); //一緒
    }
配列の先頭
                        アドレス         メモリの内容
int ary[3] = {7,5,3};   0x00000000 7

int *p = ary;           0x00000001
                        0x00000002
                        0x00000003

配列の先頭だけ記述               0x00000004 5
                        0x00000005
↓                       0x00000006
配列の先頭ポインタ               0x00000007
                        0x00000008 3
                        0x00000009
                        0x0000000A
                        0x0000000B
                        0x0000000C 0x00000000
                        0x0000000D
                        0x0000000E
                        0x0000000F
ポインタに整数を足すと
                        アドレス         メモリの内容
int ary[3] = {7,5,3};   0x00000000 7
int *p = ary;
                        0x00000001
                        0x00000002
printf(“%p”,ary);       0x00000003
printf(“%p”,&ary[0]);
                        0x00000004 5
printf(“%p”,p);
//一緒                    0x00000005
                        0x00000006
printf(“%p”,&ary[2]);   0x00000007
printf(“%p”,p+2);       0x00000008 3
//一緒                    0x00000009
                        0x0000000A
++p;                    0x0000000B
printf(“%p”,&ary[1]);
printf(“%p”,p);         0x0000000C 0x00000000
//一緒                    0x0000000D
                        0x0000000E
                        0x0000000F
配列を関数の引数にする
//配列の先頭のポインタが渡される!
void func( int a[])
{
  printf("%pn", a );//出力:0x000000ff
  a[2] = 0;
}

///

int ary[] = {1,2,3};
printf("%p", ary );//出力:0x000000ff
func(ary);
//ポインタを渡したので、関数の書き換えが反映される
printf("%dn",ary[2]);//出力:0
配列を関数の引数にする(応用)
//配列の先頭のポインタを渡すので、これでもいい
void func2(int *a)
{
  *(a+2) = 0;
  //a[2] = 0;//1次元の場合、これでもよい。
}

///
int ary[] = {1,2,3};
func(ary);
printf("%dn",ary[2]);//0
2次元配列について
//一番左の要素数は省略可
void func(int ary[][3])
{
  ary[1][1] = 2;
}


int main()
{
   int ary[][3] = { {0,1,2},
                    {3,4,5} };
   func(ary);
}
2次元配列についての罠
void func(int ary[][3])
{
  ary[1][1] = 2;
}

//ポインタでも扱いは同様と思ってると
void func(int *ary)
{
  ary[1][1] = 2;//エラー!
}
2次元配列についての罠
                                       アドレス           メモリの内容
●   要素数がある程度分からないと                     0x00000000
    要素の参照に困る                           0x00000001 'a' ( [0][0] )
                                       0x00000002 'b' ( [0][1] )
    char hoge[][3] = {{'a','b','c'},   0x00000003 'c' ( [0][2] )
                     {'d','e','f'}};   0x00000004 'd' ( [1][0] )
                                       0x00000005 'e' ( [1][2] )
    //配列の最初を参照すればOK                    0x00000006 'f' ( [1][3] )
    hoge[0][0] = 'e';                  0x00000007
                                       0x00000008
    //配列の最初から3バイト先を                    0x00000009
    //参照しなくてはいけない                      0x0000000A
    hoge[1][0] = 'f';                  0x0000000B
                                       0x0000000C
    先ほどのポインタは、何バイト先を                   0x0000000D
    読み込めばいいか分からなかった。                   0x0000000E
    よってエラー
やること
●   ポインタ
●   ポインタと配列
●   文字列
文字列
●   文字列はchar型の配列として扱うことができる
●   文字列の最後にはNULL文字がある。

    char str1[5] = "abcd";
    char str2[5] = {'a','b','c','d','0'};

    printf("%sn",str1);
    printf("%sn",str2);
                a      b     c      d        0
文字列
●   文字列はchar型の配列として扱うことができる
●   文字列の最後にはNULL文字がある

    char str1[5] = "abcd";
    char str2[5] = {'a','b','c','d','0'};
    int i;
    for(i=0;i<5;++i){
       printf("%c",str1[i]); //一緒
       printf("%c",str2[i]); //一緒
    }
    //char型、文字列として出力する時、
    //ヌル文字は出力されない
文字列
●   文字列の最後にはNULL文字があるので・・・

    char str1[5] = "abcd";
    char str1[2] = '0';

    printf("%sn",str1);
    //出力:ab

              a     b      0   d   0
今日の確認+α
char str1[5] = "abcd";
char str2[] = "abcd";
char *str3 = "abcd";

どう違うか?
今日の確認+α
char str1[5] = "abcd";
char str2[] = "abcd";

どちらも同じ。char型の配列、要素数5




          a    b     c   d   0
今日の確認+α
char *str3 = "abcd";

メモリ上の何処かに{a,b,c,d,0}の配列が作られる

その配列の先頭のアドレスがstr3に格納

{a,b,c,d,0}の書き換えなどの操作は動作未定義
今日の確認+α+β
void func1( char str1[5] ){ ... };

void func2( char str2[] ){...};

void func3( char *str3 ){...};

どう違うか?
今日の確認+α+β
void func1( char str1[5] ){ ... };
void func2( char str2[] ){...};
void func3( char *str3 ){...};

アドレスを受け取るのはどれも同じ。
要素数の指定(一番上)は
二次元以上の配列に必要となる。

例: void func4( int ary2[][5] ){...};
   void func5( int ary3[][3][5]){...};

一番左の要素数は省略可。
最後に
●   ポインタと配列の深い関係についてやったけど、
    「ポインタと配列は一緒」とか訳のわからない
    事をいう大人にはならないように

●   printf("%cn" , "abcde"[3] );

    きもちわるいぃぃぃぃぃいいいい

More Related Content

PPTX
PHP でバイナリ変換プログラミング
PDF
Javaセキュアコーディングセミナー東京第2回講義
PDF
Haskell Lecture 2
PDF
C言語講習会3
PDF
解説#1 C言語ポインタとアドレス
PDF
Popcntによるハミング距離計算
PDF
C++ ポインタ ブートキャンプ
PDF
やさしく知りたいC言語
PHP でバイナリ変換プログラミング
Javaセキュアコーディングセミナー東京第2回講義
Haskell Lecture 2
C言語講習会3
解説#1 C言語ポインタとアドレス
Popcntによるハミング距離計算
C++ ポインタ ブートキャンプ
やさしく知りたいC言語

Viewers also liked (9)

PDF
Moodle - Intro
PPT
Verde mais verde
PPSX
Defesa Campanha Central de Transplante
PPT
Kunskapsbaren 2011 Stockholm - Scala och andra nya språk i JVM:en
PPT
Jornadas navidenas
PPT
TODO EN LA RED
PPT
Presentación once
PPTX
El tenis
PPT
Viatge a roma
Moodle - Intro
Verde mais verde
Defesa Campanha Central de Transplante
Kunskapsbaren 2011 Stockholm - Scala och andra nya språk i JVM:en
Jornadas navidenas
TODO EN LA RED
Presentación once
El tenis
Viatge a roma
Ad

Tora pointer3

  • 2. やること ● ポインタ ● ポインタと配列 ● 文字列
  • 3. ポインタとは ● メモリのアドレスを メモリのアドレス アドレス メモリの内容 0x00000000 格納する変数 0x00000001 0x00000002 0x00000003 ● バグの温床 0x00000004 0x00000005 0x00000006 ● でもこれがないと 0x00000007 C言語ははじまらない 0x00000008 0x00000009 0x0000000A 0x0000000B 0x0000000C 0x0000000D 0x0000000E
  • 4. ポインタ・・・の前に アドレス メモリの内容 0x00000000 0x00000001 12 int hoge = 12; 0x00000002 (hoge) char piyo = 'a'; 0x00000003 double fuga = 0.123456; 0x00000004 0x00000005 0x00000006 'a'(piyo) 0x00000007 0.123456 32ビット環境では 0x00000008 (fuga) int型は4バイト 0x00000009 char型は1バイト 0x0000000A 0x0000000B double型は8バイト 0x0000000C 0x0000000D 0x0000000E
  • 5. ポインタ関連の文法 アドレス メモリの内容 0x00000000 0x00000001 12 0x00000002 (hoge) int hoge = 12; 0x00000003 0x00000004 printf(“%p”,&hoge); 0x00000005 0x00000006 //結果:0x00000001 0x00000007 0x00000008 0x00000009 変数のアドレスを得る 0x0000000A 0x0000000B &変数名 0x0000000C 0x0000000D 0x0000000E
  • 6. ポインタ関連の文法 アドレス メモリの内容 0x00000000 int hoge = 12; 0x00000001 12 int *phoge; 0x00000002 (hoge) 0x00000003 0x00000004 phoge = &hoge; 0x00000005 0x00000006 0x00000001 0x00000007 ポインタの定義 0x00000008 0x00000009 型の名前 *変数の名前; 0x0000000A 0x0000000B /*32ビット環境では 0x0000000C ポインタは4バイト*/ 0x0000000D 0x0000000E
  • 7. ポインタ関連の文法 アドレス メモリの内容 0x00000000 int hoge = 12; 0x00000001 12 0x00000002 (hoge) int *phoge; 0x00000003 0x00000004 phoge = &hoge; 0x00000005 0x00000006 0x00000001 0x00000007 printf(“%d” , *phoge); 0x00000008 0x00000009 ポインタを通して間接的に 0x0000000A 0x0000000B 変数を見る 0x0000000C *変数名 0x0000000D 0x0000000E
  • 8. ダブルポインタの動作 アドレス メモリの内容 int hoge = 22; 0x00000000 22 int *phoge; 0x00000001 (hoge) int **pphoge; 0x00000002 phoge = &hoge; 0x00000003 pphoge = &phoge; 0x00000004 0x00000000 0x00000005 (phoge) printf("%pn" , phoge ); 0x00000006 printf("%pn" , *pphoge ); 0x00000007 //結果:0x00000000 0x00000008 0x00000004 0x00000009 (pphoge) printf("%pn" , &phoge ); 0x0000000A printf("%pn" , pphoge ); 0x0000000B //結果:0x00000004 0x0000000C 0x0000000D printf(“%dn”,**pphoge); 0x0000000E //結果:22
  • 9. ポインタの例:スワップ swap1(int a , int b) int hoge = 5; { int piyo = 10; int tmp = b; b = a; swap1(hoge,piyo); a = tmp; //結果? } swap2(&hoge,&piyo); swap2(int *a , int *b) //結果? { int tmp = *b; *b = a; *a = tmp; }
  • 10. スワップ swap1(int a , int b) アドレス メモリの内容 { 0x00000000 5 int tmp = b; 0x00000001 (hoge) 0x00000002 b = a; 0x00000003 a = tmp; 0x00000004 10 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 int piyo = 10;//←今ココ 0x00000009 0x0000000A 0x0000000B swap1(hoge,piyo); 0x0000000C printf( 0x0000000D “%d,%d”,hoge,piyo); 0x0000000E 0x0000000F
  • 11. スワップ swap1(int a , int b)//←今ココ アドレス メモリの内容 { 0x00000000 5 int tmp = b; 0x00000001 (hoge) b = a; 0x00000002 a = tmp; 0x00000003 } 0x00000004 10 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 5 int piyo = 10; 0x00000009 (a) 0x0000000A swap1(hoge,piyo);//←ココの 0x0000000B printf(“%d,%d”,hoge,piyo); 0x0000000C 10 0x0000000D (b) 0x0000000E 0x0000000F
  • 12. スワップ swap1(int a , int b) アドレス メモリの内容 { 0x00000000 5 int tmp = b; 0x00000001 (hoge) b = a; 0x00000002 a = tmp;//←今ココ 0x00000003 } 0x00000004 10 0x00000005 (piyo) ... 0x00000006 0x00000007 0x00000008 10 int hoge = 5; 0x00000009 (a) int piyo = 10; 0x0000000A swap1(hoge,piyo);//←ココの 0x0000000B printf(“%d,%d”,hoge,piyo); 0x0000000C 5 0x0000000D (b) 0x0000000E 0x0000000F
  • 13. スワップ swap1(int a , int b) アドレス メモリの内容 { 0x00000000 5 int tmp = b; 0x00000001 (hoge) b = a; 0x00000002 0x00000003 a = tmp; 0x00000004 10 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 int piyo = 10; 0x00000009 0x0000000A swap1(hoge,piyo); 0x0000000B printf( 0x0000000C “%d,%d”,hoge,piyo); 0x0000000D //↑今ココ 0x0000000E 0x0000000F
  • 14. スワップ swap2(int *a , int *b) アドレス メモリの内容 { 0x00000000 5 int tmp = *b; 0x00000001 (hoge) 0x00000002 *b = *a; 0x00000003 *a = tmp; 0x00000004 10 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 int piyo = 10;//←今ココ 0x00000009 0x0000000A 0x0000000B swap1(&hoge,&piyo); 0x0000000C printf( 0x0000000D “%d,%d”,hoge,piyo); 0x0000000E 0x0000000F
  • 15. スワップ swap2(int *a , int *b)//←今ココ アドレス メモリの内容 { 0x00000000 5 int tmp = *b; 0x00000001 (hoge) *b = *a; 0x00000002 0x00000003 *a = tmp; 0x00000004 10 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 0x00000000 int piyo = 10; 0x00000009 (a) 0x0000000A swap1(&hoge,&piyo);//←ココ 0x0000000B の 0x0000000C 0x00000004 printf(“%d,%d”,hoge,piyo); 0x0000000D (b) 0x0000000E 0x0000000F
  • 16. スワップ swap2(int *a , int *b) アドレス メモリの内容 { 0x00000000 10 0x00000001 (hoge) int tmp = *b; 0x00000002 *b = *a; 0x00000003 *a = tmp;//←今ココ 0x00000004 5 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 0x00000000 0x00000009 (a) int piyo = 10; 0x0000000A 0x0000000B swap1(&hoge,&piyo);//←ココ 0x0000000C 0x00000004 の 0x0000000D (b) printf(“%d,%d”,hoge,piyo); 0x0000000E 0x0000000F
  • 17. スワップ swap2(int *a , int *b) アドレス メモリの内容 { 0x00000000 10 int tmp = *b; 0x00000001 (hoge) 0x00000002 *b = *a; 0x00000003 *a = tmp; 0x00000004 5 } 0x00000005 (piyo) ... 0x00000006 0x00000007 int hoge = 5; 0x00000008 int piyo = 10; 0x00000009 0x0000000A 0x0000000B swap1(&hoge,&piyo); 0x0000000C printf(“%d,%d”,hoge,piyo); 0x0000000D //↑今ココ 0x0000000E 0x0000000F
  • 18. ポインタを使うタイミング ● 動的メモリの管理 ● 複数の構造体などから同じデータを参照したい時 ● 関数の引数に構造体を利用する時 ● 関数の戻り値が2つ以上欲しい時 etc
  • 21. 複数の「何か」から同じデータを参照 乱用すると、意図しない値の操作が行われた時に、 どのプログラムが間違ってるか分かり辛い int apple_num;//0x00334455 誰だ5個も食いやがった奴は! 0x00334455 0x00334455 0x00334455 *apple_num -= 5 MARISHI kano xALTx ククク・・・
  • 22. 関数の引数に構造体を使うとき typedef struct Human { int age; int height; int weight; } Human; //構造体をまるごとコピーして重い。 void print_human(Human h) { printf(“%dn”,sizeof(h) ); //結果:16(環境依存 } //アドレスのみコピー void print_human_size_p( Human *ph) { printf(“%dn”,sizeof(ph) ); //結果:4(環境依存 }
  • 23. 関数の戻り値が複数欲しい時 void yanagisawa_info(int *age , int *weight) { *age = 22; * weight = …//ヒミツ }
  • 24. やること ● ポインタ ● ポインタと配列 ● 文字列
  • 25. ポインタと配列 ● ポインタと配列は深い関係ある ● 配列で困ったときはポインタを思い出すと 納得行くことがあったり無かったり無かったり ● そして配列死ねよと思う(?)
  • 26. ポインタと配列の衝撃の事実 ● 配列へのアクセスにはポインタも利用できる int i; int ary[3] = {7,5,3}; int *p = ary; for(i = 0 ; i < 3 ; ++i){ printf(“%dn” , ary[i] ); //出力結果は printf(“%dn” , *(p+i) ); //一緒 }
  • 27. 配列の先頭 アドレス メモリの内容 int ary[3] = {7,5,3}; 0x00000000 7 int *p = ary; 0x00000001 0x00000002 0x00000003 配列の先頭だけ記述 0x00000004 5 0x00000005 ↓ 0x00000006 配列の先頭ポインタ 0x00000007 0x00000008 3 0x00000009 0x0000000A 0x0000000B 0x0000000C 0x00000000 0x0000000D 0x0000000E 0x0000000F
  • 28. ポインタに整数を足すと アドレス メモリの内容 int ary[3] = {7,5,3}; 0x00000000 7 int *p = ary; 0x00000001 0x00000002 printf(“%p”,ary); 0x00000003 printf(“%p”,&ary[0]); 0x00000004 5 printf(“%p”,p); //一緒 0x00000005 0x00000006 printf(“%p”,&ary[2]); 0x00000007 printf(“%p”,p+2); 0x00000008 3 //一緒 0x00000009 0x0000000A ++p; 0x0000000B printf(“%p”,&ary[1]); printf(“%p”,p); 0x0000000C 0x00000000 //一緒 0x0000000D 0x0000000E 0x0000000F
  • 29. 配列を関数の引数にする //配列の先頭のポインタが渡される! void func( int a[]) { printf("%pn", a );//出力:0x000000ff a[2] = 0; } /// int ary[] = {1,2,3}; printf("%p", ary );//出力:0x000000ff func(ary); //ポインタを渡したので、関数の書き換えが反映される printf("%dn",ary[2]);//出力:0
  • 30. 配列を関数の引数にする(応用) //配列の先頭のポインタを渡すので、これでもいい void func2(int *a) { *(a+2) = 0; //a[2] = 0;//1次元の場合、これでもよい。 } /// int ary[] = {1,2,3}; func(ary); printf("%dn",ary[2]);//0
  • 31. 2次元配列について //一番左の要素数は省略可 void func(int ary[][3]) { ary[1][1] = 2; } int main() { int ary[][3] = { {0,1,2}, {3,4,5} }; func(ary); }
  • 32. 2次元配列についての罠 void func(int ary[][3]) { ary[1][1] = 2; } //ポインタでも扱いは同様と思ってると void func(int *ary) { ary[1][1] = 2;//エラー! }
  • 33. 2次元配列についての罠 アドレス メモリの内容 ● 要素数がある程度分からないと 0x00000000 要素の参照に困る 0x00000001 'a' ( [0][0] ) 0x00000002 'b' ( [0][1] ) char hoge[][3] = {{'a','b','c'}, 0x00000003 'c' ( [0][2] ) {'d','e','f'}}; 0x00000004 'd' ( [1][0] ) 0x00000005 'e' ( [1][2] ) //配列の最初を参照すればOK 0x00000006 'f' ( [1][3] ) hoge[0][0] = 'e'; 0x00000007 0x00000008 //配列の最初から3バイト先を 0x00000009 //参照しなくてはいけない 0x0000000A hoge[1][0] = 'f'; 0x0000000B 0x0000000C 先ほどのポインタは、何バイト先を 0x0000000D 読み込めばいいか分からなかった。 0x0000000E よってエラー
  • 34. やること ● ポインタ ● ポインタと配列 ● 文字列
  • 35. 文字列 ● 文字列はchar型の配列として扱うことができる ● 文字列の最後にはNULL文字がある。 char str1[5] = "abcd"; char str2[5] = {'a','b','c','d','0'}; printf("%sn",str1); printf("%sn",str2); a b c d 0
  • 36. 文字列 ● 文字列はchar型の配列として扱うことができる ● 文字列の最後にはNULL文字がある char str1[5] = "abcd"; char str2[5] = {'a','b','c','d','0'}; int i; for(i=0;i<5;++i){ printf("%c",str1[i]); //一緒 printf("%c",str2[i]); //一緒 } //char型、文字列として出力する時、 //ヌル文字は出力されない
  • 37. 文字列 ● 文字列の最後にはNULL文字があるので・・・ char str1[5] = "abcd"; char str1[2] = '0'; printf("%sn",str1); //出力:ab a b 0 d 0
  • 38. 今日の確認+α char str1[5] = "abcd"; char str2[] = "abcd"; char *str3 = "abcd"; どう違うか?
  • 39. 今日の確認+α char str1[5] = "abcd"; char str2[] = "abcd"; どちらも同じ。char型の配列、要素数5 a b c d 0
  • 40. 今日の確認+α char *str3 = "abcd"; メモリ上の何処かに{a,b,c,d,0}の配列が作られる その配列の先頭のアドレスがstr3に格納 {a,b,c,d,0}の書き換えなどの操作は動作未定義
  • 41. 今日の確認+α+β void func1( char str1[5] ){ ... }; void func2( char str2[] ){...}; void func3( char *str3 ){...}; どう違うか?
  • 42. 今日の確認+α+β void func1( char str1[5] ){ ... }; void func2( char str2[] ){...}; void func3( char *str3 ){...}; アドレスを受け取るのはどれも同じ。 要素数の指定(一番上)は 二次元以上の配列に必要となる。 例: void func4( int ary2[][5] ){...}; void func5( int ary3[][3][5]){...}; 一番左の要素数は省略可。
  • 43. 最後に ● ポインタと配列の深い関係についてやったけど、 「ポインタと配列は一緒」とか訳のわからない 事をいう大人にはならないように ● printf("%cn" , "abcde"[3] ); きもちわるいぃぃぃぃぃいいいい