第3回:ポインタと配列


C言語では,配列ポインタに密接な関係があります.

まず,先週のおさらいから.


ポインタ変数

データのメモリアドレスを指し示す(ポイントする)ための変数

int *p;
ポインタ変数の宣言.型を指定し,変数名の前に*をつける
p = &a;
pにはint型変数aのアドレスが入る.ポインタ変数にアドレスを入れるには,対象となる変数の前に&をつける
b = *p;
ポインタ変数に格納されているアドレスに格納されているを取り出すには,ポインタ変数の前に*をつける

配列とポインタの関係

配列の名前は,じつは,配列の最初の要素を指すポインタです.たとえば,

int a[4];

と定義した場合,変数aは要素a[0]へのポインタです.

他の要素を呼び出すには,ポインタに1づつ加えていきます.ポインタ変数に対しては整数の加算と減算が可能です.変数の方によるメモリー上の大きさの違いは自動的に計算されます.

例で見てみると,

配列 ポインタ
#include <stdio.h>

void main()
{
    char src[20] = "Thank you.";
    int i;

    i = 0;

    printf("文字列=");
    while(src[i] != 0x00){
        printf("%c", src[i]);
        i++;
    }
}
#include <stdio.h>

void main()
{
    char src[20] = "Thank you.";
    char *p;

    p = src;

    printf("文字列=");
    while(*p != 0x00){
        printf("%c", *p);
        p++;
    }
}

何をやっているプログラムか理解できますか?


ここで,Thank you.の3文字目の"a"を表示したい場合はどうしたらよいか考えてみよう.

printf("%c", *p + 2);

で正しいでしょうか.じつは,これは間違いです.*p + 2という演算は,ポインタpの指している所にある値に2を加えるということです.正しくは,

printf("%c", *(p + 2));

となります.


今日の演習

入力されたアルファベットの小文字の文字列をabc順に並べ替えるプログラムを,ポインタを使って書き直そう.

#include <stdio.h>

void main()
{
    char s[256], t;
    int n, i, j;

    //文字列の入力
    printf("単語を入力してください\n");
    scanf("%s", s);
    printf("入力された文字列は%sです.\n", s);

    // 文字数を数える
    for(i=0; s[i] != 0x00; i++);
    printf("文字数は,%d文字です.\n", i);

    n = i;

    // 並び替え
    for(i=0; i < n-1; i++){
        for(j=i+1; j < n; j++){
            if(s[i] > s[j]){
                t = s[i];
                s[i] = s[j];
                s[j] = t;
            }
        }
    }

    printf("結果 : %s\n", s);
}

メモリの確保

これまで使ってきた配列の定義方法では,配列の大きさが,プログラムの作成時にすでにわかっている必要がありました(静的なメモリ確保).ポインタを使うと,はじめに配列の先頭アドレスだけ決めておき,大きさはプログラムの実行時に決めることができます(動的なメモリ確保).ココでは,ポインタを用いたメモリの動的確保方法を練習しましょう.

上のプログラムを,動的なメモリ確保に書き換えると...

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

void main()
{
    char *s, t;
    int n, i, j;

    s = (char *)malloc(sizeof(char)*256);        //ここで,はじめてメモリを確保する

    //文字列の入力
    printf("単語を入力してください\n");
    scanf("%s", s);
    printf("入力された文字列は%sです.\n", s);

    // 文字数を数える
    for(i=0; s[i] != 0x00; i++);
    printf("文字数は,%d文字です.\n", i);

    n = i;

    // 並び替え
    for(i=0; i < n-1; i++){
        for(j=i+1; j < n; j++){
            if(s[i] > s[j]){
                t = s[i];
                s[i] = s[j];
                s[j] = t;
            }
        }
    }

    printf("結果 : %s\n", s);
    free(s);                        //動的に確保したメモリは,必ず解放する
}

動的に確保したメモリは,使い終わったら,解放する必要があります.最後のfreeを忘れると,プログラムが終了してもメモリが確保されたままになるので,だんだんコンピュータの動きがおかしくなります.(メモリーリーク


おまけ

自宅のWindowsPCで,大学で使っているものとほとんど同じCコンパイラを使うことができます.ボーランド社のホームページから,Borland C++ Compiler 5.5をダウンロードし,インストールするだけです.

Borland C++ Compiler 5.5 ダウンロードページへ