FreeBASIC マニュアルのトップに戻る

FreeBASIC ポインタ、データ型、メモリ

目次→教本→いっしょに学ぼうPointers, Data Types and Memory←オリジナル・サイト

ポインタ、データ型、メモリ 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

記事 ポインタへの序論 をお読みの方は、ポインタが、記憶域のアドレスを収納していることを知っています。
あなたは、これらの記憶域で、間接参照演算子 * を使って、データを操ることができます。単一のデータ項目で、ポインタを使うことは、問題ありません。しかし、複数のデータ項目を一緒に格納して、ポインタを使ってそれらを操る必要があるときは、どうするのでしょうか?
データがメモリにどのように格納されるかを理解していないと、それは少し扱いにくいかもしれません。

コンピュータの単一の記憶域は、1バイトの長さです。
ANSI 文字の1文字を保持できる大きさです。
(ユニコード文字と対照です。ユニコード文字は、ワイド・キャラクターであり、2バイトです。 私たちはこの記事でユニコード文字について議論しません。)
しかしながら、すべてのデータ型は、幅が1バイトではありません。
ここに、それぞれのデータ型の長さを、バイトで表示する、簡単なプログラムがあります。

Dim a As Byte
Dim b As Short
Dim c As Integer
Dim d As LongInt
Dim au As UByte
Dim bu As UShort
Dim cu As UInteger
Dim du As ULongInt
Dim e As Single
Dim f As Double
Dim g As Integer Ptr
Dim h As Byte Ptr
Dim s1 As String * 10 'fixed string
Dim s2 As String      'variable length string
Dim s3 As ZString Ptr 'zstring

s1 = "Hello World!"
s2 = "Hello World from FreeBasic!"
s3 = Allocate ( Len( s2 ) + 1 )
*s3 = s2

Print "Byte: ";len (a)
Print "Short: ";len (b)
Print "Integer: ";len (c)
Print "Longint: ";len (d)
Print "UByte: ";len (au)
Print "UShort: ";len (bu)
Print "UInteger: ";len (cu)
Print "ULongint: ";len (du)
Print "Single: ";len (e)
Print "Double: ";len (f)
Print "Integer Pointer: ";len (g)
Print "Byte Pointer: ";len (h)
Print "Fixed String: ";len (s1)
Print "Variable String: ";len (s2)
Print "ZString: ";len (*s3)

Deallocate s3

Sleep


出力は以下の通りです。(32bit システムで):

Byte:   1
Short:   2
Integer:   4
LongInt:   8
UByte:   1
UShort:   2
UInteger:   4
ULongInt:   8
Single:   4
Double:   8
Integer Pointer:   4
Byte Pointer:   4
Fixed String:   10
Variable String:   27
ZString:   27


ポインターの長さは、常に、32bit システムでは4バイト、64bit システムでは8バイトの長さで、整数と同じことに注意してください。ポインターは、データではなくメモリー・アドレスを含んでいるため、データとは無関係なのです。

さまざまなデータ型の長さを見ると、10個の整数に十分な領域を allocate すると、40/80バイトのメモリ(32/64bit システムで)が必要になることがわかります。
各整数は、4/8 バイト(32/64ビットシステムで)です。
では、どのようにメモリ・バッファから、各整数値にアクセスするのですか?
答えは、ポインタの数学です。 以下のプログラムを見てください。

Dim aptr As Integer Ptr

'2つの整数のために十分なスペースを割り当てます
aptr = Allocate(Len(Integer) * 2)
'最初の整数をロードする
*aptr = 1
Print "Int #1:", "address: "; aptr, "value: "; *aptr
'ポインタを、次の整数の場所に動かします
'aptr + 1
'2番目の整数をロードする
*(aptr + 1) = 2
Print "Int #2:", "address: "; aptr + 1, "value: "; *(aptr + 1)

Deallocate aptr
Sleep


このプログラムで、2つの変数を定義します。整数整数 ポインタ, aptr です。
Aptr は、2つの整数を収納する、メモリ・バッファをポイントします。
allocate 関数は、我々が必要とするバッファーのサイズを要求します。8/16バイト(32/64bit システムで)のメモリーを確保するために、 整数 のサイズに2を掛けます。整数のスペースは、4/8バイト(32/64bit システムで)です。

割当てを行った後に、aptr は、メモリ・バッファの、最初のバイトのアドレスを収納します。
最初の整数を格納するのは、単に間接参照演算子を使って、値に 1 を設定する問題です。
値を表示するために、私たちは再び、*aptr を使用します。

ここで質問です:
コンパイラーは、値1が、4/8バイト(32/64bit システムで)を必要としていて、1 か 2バイトではないことを、どうして知っているのでしょう?
私たちは、aptr を integer ptr として宣言したからです。
コンパイラは、整数が4/8バイト(32/64ビットシステムで)であることを知っているため、メモリの4バイトに、データをロードします。
これは、値を表示するときに、何か奇妙な数ではなく、1を得る理由です。


2番目の値を、バッファにロードするのに、下を使います。
*(aptr + 1) = 2


一見すると少し奇妙に見えるかもしれません。
Aptr は、メモリ・バッファの最初のバイトを指します。
整数は、4/8バイト長(32/64bit システム)なので、次の整数バイトの位置に到達するには、アドレス(aptrの値)に4/8を追加する必要があります。
コンパイラは、このポインタで使われているデータのサイズが、Integer または4/8バイト(32/64bit システム)であることを知っています。
そこで、2番目の要素にアクセスするために、ポインタに1を加えて *(aptr + 1) とするのです。

間接参照演算子 * が + より高い優先順位を持つため、add 演算の前後に、括弧が必要です。
括弧で、最初に加算操作を実行してから、間接参照演算子 を適用します。

直接 aptr を増加させなかったことに注目してください。
もしそうすると、aptr はもはやメモリ・バッファの開始点を指さなくなります。そして、バッファを「割り当て解除」したとき、プログラムはクラッシュするでしょう。メモリ・バッファの外側にメモリを deallocate するからです。
ポインタを直接増加させる必要がある場合は、元の割り当てで使われたポインタではなく、一時的なポインタ変数を作成して、増加させます。

メモリ・バッファとポインタは、メモリのデータを格納して、操る、強力な方法です。
しかし、バッファに格納されているデータの型に従って、正しくデータにアクセスしていることを確実にするために、注意して下さい。。

いっしょに学ぼう に戻る

最終、sancho3 によるレビュー(2018年2月7日)

←リンク元に戻る プログラム開発関連に戻る

ページ歴史:2019-07-04 00:32:43
日本語翻訳:WATANABE Makoto、原文著作者:WikiRick(Rick Clark aka rdc)

ホームページのトップに戻る

表示-非営利-継承