[前へ]   [目次へ]   [次へ]

ポインタ(3)(C/C++)


今回も、引き続き実践的に使えるポインタの用法、入門編です。

今回は char 型の配列を受け取って文字列の長さ(文字列が何バイトあるか)を
調べて返す関数を作ってみましょう。

なお、今回作るものは strlen という名前の標準関数と同じ機能となります。
標準関数というと何か複雑で特別なもののような気がするかもしれませんが、
結構、中身が単純なものもあります。

標準関数と同じものを作っても面白みは無いかもしれません。
しかしながら、標準関数が中で何をしているかを知っていることはデバッグ時に役に立ちますので、
どういうことをしているのかという点は覚えておくといいでしょう。


さて、そろそろ始めます。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
#include <stdio.h>

int StringLength(char *str){//(1)
   /******************************
   文字列のバイト数を数えて返す。
   
   戻り値:strのバイト数
   
   str:[入力]バイト数を数える対象の文字列
   ******************************/
   
int i;
   
for(i=0;str[i]!='\0';i++);//(2)
   
return i;
}

int main(void){
   
char str1[11]="abcde";
   
char str2[11]="あいうえお";
   
char str3[11]="1\n23\n456";
   
   printf(
"%sの長さ:%d\n\n",str1,StringLength(str1));//(3)
   
printf("%sの長さ:%d\n\n",str2,StringLength(str2));
   printf(
"%sの長さ:%d\n\n",str3,StringLength(str3));
   
   
//終了待ち
   
getchar();
   
return 0;
実行結果:
abcdeの長さ:5

あいうえおの長さ:10

1
23
456の長さ:8


今回の内容は今までの内容をイロイロ使っています。
分からない部分があったら前に戻って確認するようにしてください。

(1)3行目からは、文字列のバイト数を数える関数 StringLength の定義です。
引数型は今回は char* となっています。

(2)12行は、文字列の終端を探すループです。
「文字列は配列を使って表現する」( 第19回参照 )
「文字列はナル文字( '\0' )が現れるまでの範囲とする」( 第19回参照 )
「 [ ] 配列添え字参照演算子が本当に要求するのは配列の絶対ID」( 第57回参照 )
というルールを思い出してください。

文字列は常に配列に格納されていること、
そして str がその文字列を格納した配列への絶対IDを格納していることにより、
str に対して [ ] 配列添字参照演算子を使用することができます。
そして、ナル文字ではない文字の場合、続行するようにループを組むことで
全ての文字に対して処理を行うようにすることができます。

(3)21〜23行は、それぞれの文字列変数とその長さを表示しています。
文字列の長さの取得には先に定義した StringLength 関数を使っています。


さて、今回も実行を追跡していきたいと思います。

16行、 main 関数から始まり、ローカル変数の作成と初期化まで終わった20行目です。
今までは、リストが巨大化するのが嫌だったのでまとめていた配列変数の実体ですが、
今回はその辺の詳細が必要なので巨大リスト覚悟で全てのバラ実体も含めて進めます。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
mainブロック 確保位置ID:0x0013FF5C

というわけで、(3)21行目です。

A      B C                    D      E            F G    F' B'
printf ( "%sの長さ:%d\n\n" , str1 , StringLength ( str1 )  )


通し記号種別
Aint(*)(const char*,...)0x00401530関数(printf)
B演算子( () )(その他、優先16、結合→)
Cconst char[15]"%sの長さ:%d\n\n"文字列定数
Dchar[11]"abcde"変数(str1)
Eint(*)(char*)0x00401020関数(StringLength,line 3)
F演算子( () )(その他、優先16、結合→)
Gchar[11]"abcde"変数(str1)
F'演算子Fの終点
B'演算子Bの終点
優先順位および結合規則から演算子B(関数呼び出し、目標 関数A、引数C〜F)からの処理ですが、
E〜F'の範囲が複式なのでそちらから解決します。

というわけで演算子F(関数呼び出し、目標 関数E、引数G)が実行されます。
引数Gの型は char[11] ですが、暗黙変換により char* 型へと変換されて代入されます。
そして、実行座標が呼び出した関数の起点である3行目へと移動されます。

続いてローカル変数を作成して11行目終了時点です。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
0x0013FF08char*0x0013FF5C(main::str1)StringLength(str,line 3)
0x0013FEFCint不定(未初期化)StringLength(i,line 11)
mainブロック 確保位置ID:0x0013FF5C
StringLength引数 確保位置ID:0x0013FF08
StringLengthブロック 確保位置ID:0x0013FEFC


続いて(2)12行の for ループです。
このループは「真の時実行するステートメント」に何も書いていません。
このような書き方をすると、初期化式が実行された後、
継続条件の判定と続行式が交互に行われるようになります。
(単に「真の時〜」の部分は何もしないだけです)

まず、 i に0が代入され、初回の継続条件判定です。

A   B C B' D  E
str [ i ]  != '\0'


通し記号種別
Achar*0x0013FF5C変数(str)(参照先:main::str1)
B演算子( [] )(その他、優先16、結合→)
Cint0変数(i)
B'演算子Bの終点
D演算子(!=)(論理、優先9、結合→)
Echar0('\0')定数
優先順位から、演算子B(配列添字参照、左辺 変数A、座標 変数C)からです。
これまでの通り、この演算子は0x0013FF5C( str の格納値)+1( char 型のサイズ)*0( i の格納値)を計算し、
結果として0x0013FF5Cへの char 型参照を作成します。

A       B  C
vtemp1  != '\0'


通し記号種別
Achar&97('a')一時変数(参照先:main::str1[0](0x0013FF5C))
B演算子(!=)(論理、優先9、結合→)
Cchar0('\0')定数
次は演算子B(以外、左辺 一時変数A、右辺 定数C)で、97は0以外を判定します。
これは正しいので真が返されます。

継続条件が真になったので続行式により i が1増えます。
そして再び継続条件判定です。

A   B C B' D  E
str [ i ]  != '\0'


通し記号種別
Achar*0x0013FF5C変数(str)(参照先:main::str1)
B演算子( [] )(その他、優先16、結合→)
Cint1変数(i)
B'演算子Bの終点
D演算子(!=)(論理、優先9、結合→)
Echar0('\0')定数
優先順位から、演算子B(配列添字参照、左辺 変数A、座標 変数C)からです。
これまでの通り、この演算子は0x0013FF5C( str の格納値)+1( char 型のサイズ)*1( i の格納値)を計算し、
結果として0x0013FF5Dへの char 型参照を作成します。

A       B  C
vtemp1  != '\0'


通し記号種別
Achar&98('b')一時変数(参照先:main::str1[1](0x0013FF5D))
B演算子(!=)(論理、優先9、結合→)
Cchar0('\0')定数
次は演算子B(以外、左辺 一時変数A、右辺 定数C)で、98は0以外を判定します。
これは正しいので真が返されます。

この後、 main::str1[2](0x0013FF5E) 、 main::str1[3](0x0013FF5F) 、 main::str1[4](0x0013FF60) も判定され、
同様に真となります。

そして i が5になった継続条件判定です。

A   B C B' D  E
str [ i ]  != '\0'


通し記号種別
Achar*0x0013FF5C変数(str)(参照先:main::str1)
B演算子( [] )(その他、優先16、結合→)
Cint5変数(i)
B'演算子Bの終点
D演算子(!=)(論理、優先9、結合→)
Echar0('\0')定数
優先順位から、演算子B(配列添字参照、左辺 変数A、座標 変数C)からです。
これまでの通り、この演算子は0x0013FF5C( str の格納値)+1( char 型のサイズ)*5( i の格納値)を計算し、
結果として0x0013FF61への char 型参照を作成します。

A       B  C
vtemp1  != '\0'


通し記号種別
Achar&0('\0')一時変数(参照先:main::str1[5](0x0013FF61))
B演算子(!=)(論理、優先9、結合→)
Cchar0('\0')定数
次は演算子B(以外、左辺 一時変数A、右辺 定数C)で、0は0以外を判定します。
これは正しくないので偽が返されます。
これにより、ループが終了します。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
0x0013FF08char*0x0013FF5C(main::str1)StringLength(str,line 3)
0x0013FEFCint5StringLength(i,line 11)
mainブロック 確保位置ID:0x0013FF5C
StringLength引数 確保位置ID:0x0013FF08
StringLengthブロック 確保位置ID:0x0013FEFC


そしてこの時の i の値である5が呼び出し元に返されることになります。
同時に、 StringLength のローカル変数が破棄されます。


そして呼び出し元に戻ってきました。

A      B C                    D      E       B'
printf ( "%sの長さ:%d\n\n" , str1 , vtemp1  )


通し記号種別
Aint(*)(const char*,...)0x00401530関数(printf)
B演算子( () )(その他、優先16、結合→)
Cconst char[15]"%sの長さ:%d\n\n"文字列定数
Dchar[11]"abcde"変数(str1)
Eint5一時変数
B'演算子Bの終点
これで「 abcdeの長さ:5 」が出力されました。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
mainブロック 確保位置ID:0x0013FF5C

次は22行目、 printf("%sの長さ:%d\n\n",str2,StringLength(str2)) です。

A      B C                    D      E            F G    F' B'
printf ( "%sの長さ:%d\n\n" , str2 , StringLength ( str2 )  )


通し記号種別
Aint(*)(const char*,...)0x00401530関数(printf)
B演算子( () )(その他、優先16、結合→)
Cconst char[15]"%sの長さ:%d\n\n"文字列定数
Dchar[11]"あいうえお"変数(str2)
Eint(*)(char*)0x00401020関数(StringLength,line 3)
F演算子( () )(その他、優先16、結合→)
Gchar[11]"あいうえお"変数(str2)
F'演算子Fの終点
B'演算子Bの終点
使用している変数が str1 から str2 に変わっただけで、
その他の部分に違いはありません。
なので、21行目と基本的には同じ流れで進んでいきます。

というわけで演算子F(関数呼び出し、目標 関数E、引数G)が実行されます。
引数Gの型は char[11] ですが、暗黙変換により char* 型へと変換されて代入されます。
そして、実行座標が呼び出した関数の起点である3行目へと移動されます。

続いてローカル変数を作成して11行目終了時点です。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
0x0013FF08char*0x0013FF68(main::str2)StringLength(str,line 3)
0x0013FEFCint不定(未初期化)StringLength(i,line 11)
mainブロック 確保位置ID:0x0013FF5C
StringLength引数 確保位置ID:0x0013FF08
StringLengthブロック 確保位置ID:0x0013FEFC


初回との違いは0x0013FF08( str )の実体が保持している値です。
これ以外の部分は同じ状況になっているので、
この部分の違いが、この先の処理の内容へ関わっています。

続いて(2)12行の for ループです。
まず、 i に0が代入され、初回の継続条件判定です。

A   B C B' D  E
str [ i ]  != '\0'


通し記号種別
Achar*0x0013FF68変数(str)(参照先:main::str2)
B演算子( [] )(その他、優先16、結合→)
Cint0変数(i)
B'演算子Bの終点
D演算子(!=)(論理、優先9、結合→)
Echar0('\0')定数
優先順位から、演算子B(配列添字参照、左辺 変数A、座標 変数C)からです。
今度は0x0013FF68( str の格納値)+1( char 型のサイズ)*0( i の格納値)を計算し、
結果として0x0013FF68への char 型参照を作成します。

A      B  C
vtemp1 != '\0'


通し記号種別
Achar&-126一時変数(参照先:main::str2[0](0x0013FF68))
B演算子(!=)(論理、優先9、結合→)
Cchar0('\0')定数
次は演算子B(以外、左辺 一時変数A、右辺 定数C)で、-126は0以外を判定します。
これは正しいので真が返されます。

この後、 main::str1[1](0x0013FF69) 〜 main::str1[9](0x0013FF71) までも判定され、
同様に真となります。

そして i が10になった継続条件判定です。

A   B C B' D  E
str [ i ]  != '\0'


通し記号種別
Achar*0x0013FF68変数(str)(参照先:main::str2)
B演算子( [] )(その他、優先16、結合→)
Cint10変数(i)
B'演算子Bの終点
D演算子(!=)(論理、優先9、結合→)
Echar0('\0')定数
優先順位から、演算子B(配列添字参照、左辺 変数A、座標 変数C)からです。
これまでの通り、この演算子は0x0013FF68( str の格納値)+1( char 型のサイズ)*10( i の格納値)を計算し、
結果として0x0013FF72への char 型参照を作成します。

A       B  C
vtemp1  != '\0'


通し記号種別
Achar&0('\0')一時変数(参照先:main::str2[10](0x0013FF72))
B演算子(!=)(論理、優先9、結合→)
Cchar0('\0')定数
次は演算子B(以外、左辺 一時変数A、右辺 定数C)で、0は0以外を判定します。
これは正しくないので偽が返されます。
これにより、ループが終了します。

この時点までを実行した時の状況の一例
実体ID(絶対)実体の型保持値所属
0x0013FF5Cchar[11]"abcde"main(str1,line 17)
0x0013FF5Cchar97('a')main(str1[0],line 17)
0x0013FF5Dchar98('b')main(str1[1],line 17)
0x0013FF5Echar99('c')main(str1[2],line 17)
0x0013FF5Fchar100('d')main(str1[3],line 17)
0x0013FF60char101('e')main(str1[4],line 17)
0x0013FF61char0('\0')main(str1[5],line 17)
0x0013FF62char0('\0')main(str1[6],line 17)
0x0013FF63char0('\0')main(str1[7],line 17)
0x0013FF64char0('\0')main(str1[8],line 17)
0x0013FF65char0('\0')main(str1[9],line 17)
0x0013FF66char0('\0')main(str1[10],line 17)
0x0013FF68char[11]"あいうえお"main(str2,line 18)
0x0013FF68char-126main(str2[0],line 18)
0x0013FF69char-96main(str2[1],line 18)
0x0013FF6Achar-126main(str2[2],line 18)
0x0013FF6Bchar-94main(str2[3],line 18)
0x0013FF6Cchar-126main(str2[4],line 18)
0x0013FF6Dchar-92main(str2[5],line 18)
0x0013FF6Echar-126main(str2[6],line 18)
0x0013FF6Fchar-90main(str2[7],line 18)
0x0013FF70char-126main(str2[8],line 18)
0x0013FF71char-88main(str2[9],line 18)
0x0013FF72char0('\0')main(str2[10],line 18)
0x0013FF74char[11]"1\n23\n456"main(str3,line 19)
0x0013FF74char49('1')main(str3[0],line 19)
0x0013FF75char10('\n')main(str3[1],line 19)
0x0013FF76char50('2')main(str3[2],line 19)
0x0013FF77char51('3')main(str3[3],line 19)
0x0013FF78char10('\n')main(str3[4],line 19)
0x0013FF79char52('4')main(str3[5],line 19)
0x0013FF7Achar53('5')main(str3[6],line 19)
0x0013FF7Bchar54('6')main(str3[7],line 19)
0x0013FF7Cchar0('\0')main(str3[8],line 19)
0x0013FF7Dchar0('\0')main(str3[9],line 19)
0x0013FF7Echar0('\0')main(str3[10],line 19)
0x0013FF08char*0x0013FF68(main::str2)StringLength(str,line 3)
0x0013FEFCint10StringLength(i,line 11)
mainブロック 確保位置ID:0x0013FF5C
StringLength引数 確保位置ID:0x0013FF08
StringLengthブロック 確保位置ID:0x0013FEFC


そしてこの時の i の値である10が呼び出し元に返されることになります。
同時に、 StringLength のローカル変数が破棄されます。


そして呼び出し元に戻ってきました。

A      B C                    D      E       B'
printf ( "%sの長さ:%d\n\n" , str2 , vtemp2  )


通し記号種別
Aint(*)(const char*,...)0x00401530関数(printf)
B演算子( () )(その他、優先16、結合→)
Cconst char[15]"%sの長さ:%d\n\n"文字列定数
Dchar[11]"あいうえお"変数(str2)
Eint10一時変数
B'演算子Bの終点
これで「 あいうえおの長さ:10 」が出力されました。

3回目も同じような手順で「
1
23
456の長さ:8
」が出力されます。

このように、ポインタを受け取って処理をするように作成した関数は、
呼び出し元が任意に渡した変数に対して処理を行うことができます。

これは利用方法によっては非常に強力な使い勝手を得ることができます。
しかしながら、強力なものは慎重に使わなければならないのがこの世の常です。

たとえば、刃物等を正しく使わないと怪我をするように、
ポインタも正しく使わないと凶悪にバグります。

次回からはポインタに関するバグ追跡の予定です。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17