6.ポインタ
6.1.ポインタとは
プログラムで使用されるデータは、全てメモリに保持されます。C言語で作成されたプログラムも同様に、変数が保持するデータは全てメモリで管理されます。通常プログラマはメモリのどこに変数のデータが管理されているか意識しなくて良いようになっていますが、データが格納されているメモリアドレスを操作する仕組みも提供されています。それを「ポインタ」と呼びます。
ポインタは他にあるデータが保持されているメモリ上のアドレスを管理します。プログラマはポインタが示すアドレスを操作することもできますし、そのアドレスに格納されているデータを操作することもできます。アドレスの操作は、他のデータの破壊にも繋がる可能性がありますので、慎重に扱う必要があります。
以下のサンプルプログラムは、キーボードから入力された文字をそのまま表示します。ポインタを用いています。
#include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]){ char *str; str=(char *)malloc(sizeof(char)*100); fgets(str,100,stdin); puts(str); free(str); return(0); }
6.2.mallocとfree
ポインタの宣言は
データ型 *ポインタ名;
の形式で行います。5行目では、char型のポインタstrが宣言されています。この宣言により、char型のデータ領域を指し示すポインタを使用できるようになりますが、ポインタそのものはデータを格納する領域を持ちません。既存の変数が持つデータ領域のアドレスを受け取ることにより、データ領域を確保できます。以下はその例です。「&変数名」は変数のデータ領域のアドレスを示します。
int a=10; int *b=&a;
ここではもう1つの方法である、「malloc」という関数を用いて(7行目)データ領域を確保する方法を使用しています。mallocは引数として確保したい領域のサイズ(単位はバイト)を指定します。ここではchar型の変数が100個格納できるサイズ、つまり100バイトを引数として与えています。
mallocはメモリ上に引数で指定されたサイズの領域を確保すると、その先頭アドレスを返します。返り値の型は「void *」 という汎用ポインタ(どのような型のデータでも指し示すことのできるポインタ)になっていますので、サンプルの場合はchar型のポインタにキャストしてやる必要があります。キャストとは型変換のことです。
10行目で使用されている「free」は、ポインタが指し示しているデータ領域を開放する関数です。変数はスコープ(変数名が有効なプログラム上の範囲)を抜けると確保された領域を開放しますが、mallocで確保されたポインタのデータ領域は開放されません。そこでfree関数を用いて、明示的に領域を開放してやる必要があります。
なお、mallocとfreeを使用するには2行目の宣言が必要になります。
(実習課題)
以下のプログラムを作成しなさい。
- 2個の文字列を格納できるポインタ配列(char *str[2])を作成する。
- キーボードから2つの文字列を読み取り、ポインタ配列に格納する。
- 入力される文字列は最大256文字とする。
- 最後に格納された文字列をコンソールに出力する。
6.3.配列とポインタ
配列は同じ変数名で操作される同じタイプのデータを集めたものですが、データ構造的にはポインタと同じく、そのデータ領域の先頭アドレスを指し示すものです。したがって配列名を用いて、そのアドレスをポインタに代入することができます。しかしポインタとは異なって、宣言と同時にデータを格納する領域が確保されます。また指し示しているアドレスを動的に変更することはできません。つまり逆はできないということです。以下は配列の値をディスプレイに出力するプログラムです。
#include <stdio.h> int main(int argc, char *argv[]){ char str[]="yojigen"; char *str2; str2=str; puts(str); puts(str2); return(0); }
7行目で配列strの先頭アドレスをポインタstr2に代入しています。8・9行目でそれぞれを出力していますが、 どちらも同じ「yojigen」を出力します。
(実習課題)
以下のプログラムを作成しなさい。
- 「yojigen taro」という文字列が格納されている配列を作成する。
- 配列のアドレスをポインタに渡す。
- 格納された文字列を1行1文字づつ表示する。
- 表示には配列ではなく、ポインタを使用すること。
- (ヒント)ポインタに対して演算を適用する。(「char *str; str++;」などを実行する)
- (ヒント)1文字の表示にはputcharを使用する。