学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース

C++プログラミング入門その27 ポインタの応用

<<前  [TOP]  次>>


Visual Studioで新規プロジェクトを作り、以下のcppファイルを作成して下さい。


PointerTest6.cpp 直

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void  main(){

		char *s, buf[512];
		std::cout << "文字列を入力してください" << std::endl;
		std::cin >> buf;
		s = (char *)malloc( strlen(buf) + 1 );
		strcpy_s(s, strlen(buf) + 1, buf);
		std::cout << s << std::endl;
}



少し大規模なプログラムにおいては扱うデータが不定量になる場合が多いです。
別の言い方をすれば、あらかじめどれだけのメモリを必要とするか解らないと言うこともできます。
そこで、必要なメモリを必要なときに必要な分だけ用意することが問題になってきます。
例えば、

char buf[512];

などとして、一行が512文字までであると仮定して宣言します。
問題は、次々とユーザーが入力した文字列を失わずに保持することで、そのためには、buf[]で格納されたデータを別の場所にコピーして保存しなければなりません。
しかし、buf[512]に用意したのと同じように、512の大きさの配列を別に用意するのは、メモリの無駄遣いになります。
実際、ユーザーは一行に1文字しか入力しないかもしれないからです。
従って、ユーザーが入力しただけの文字数分のメモリを用意できれば良いのです。
その方法を次に説明します。


必要なときに必要なだけメモリを確保する方法として、C言語では標準関数でmalloc()が用意されています。
malloc()を使う場合は、プログラムの先頭で、#includeが必要です。
malloc()は確保したメモリのアドレスを返します。

#include<stdlib.h>
・・・・
    char *s;
    s = malloc(20);

この例では、20byteの大きさのメモリを確保し、確保してメモリの先頭アドレスをポインタsに格納しています。
このように、確保したメモリはそのままでは行方不明になってしまうので、この場所を覚えておくためにポインタを使います。


malloc()はメモリの大きさを具体的に示す必要がありますが、例えば、float型が何byteかということはシステムによって違う場合があります。
したがって、プログラム中でこうした大きさについて知ることができなければなりません。
このために用意されている演算子がsizeofです。


このsizeofを使うと、使用しているOSなどに依存しないプログラムが書けるとともに、構造体などのメモリにしめるサイズが不明な型の大きさも取得できます。
従って、malloc()とともに用いる場合は通常次のように使います。

/* char 20個のメモリ */

char *s;
 s = malloc( sizeof(char) * 20 );

 /* struct Point 10個分のメモリ */

struct Point {
    float x;
    float y;
 };
 struct Point *p;

 p = malloc( sizeod(struct Point) * 10 );



C言語では自動的な型の変換というものがあります。
例えば、次のプログラムでは、整数3は、代入時に自動的に実数3.0に変換されています。

float x;
x = 3;

このように型を別の型に自動的に変換する機能は便利ですが、ときとしてバグの原因にもなります。
そこで、C言語では明示的に型を変換するための単項演算子が用意されており、一般にこの機能をキャストと呼んでいます。


値や変数の前に(型)を置くことによって、希望の型に変換できます。

例
     int y = 3;
    float x;
    x = (float)y;

この例では、整数変数yに入っている値3を実数にキャストしていますが、y自体は変化するわけではない点に注意してください。


メモリの割り当てはmalloc()で行いますが、必要がないメモリをいつまでも放って置いては使えるメモリが少なくなっていきます。
必要がなくなった時点で使ったメモリをシステムに返却する必要があります。
これを行う関数がfree()です。
free()はvoid型ですので、何も結果は返しません。
使い方は次のようにします。

/* char 20個分のメモリの確保と開放 */

char *s;
 s = (char *)malloc(sizeof(char) *20 );
・・・・
free(s);

ここで注意しなければならないのは、一度free()してしまった領域を参照したり、利用したりしてはいけないという点です。
malloc()でアドレスを返すとき、実際はこの例のようにキャストを行います。
そうすれば、std::coutなどで出力するとき、アドレスではなく文字列での出力が可能になります。
これは、malloc()を使用するときの基本となりますので覚えておいてください。


malloc()をするには、そのメモリサイズを決める必要がありましたが、文字列では実際の文字列の長さを数える必要があります。
このための関数がstrlen()です。
strlen()は引数に文字列へのポインタをとり、¥0までの文字数を計算し、結果として返します。
ただし、¥0自体は勘定しませんので、malloc()で利用する場合は一つ多めにしておかなければなりません。

char buf[512];
char *s;
int n;

std::cin >> buf;
n = strlen(buf) +1;
malloc(sizeof(char) * n);
・・・・

上の例では、標準入力から読み込んだ文字列の長さ+¥0をnに代入し、char型の大きさをかけた分のメモリを確保しています。
C言語では、charは1byteであると決まっていますので、下記のようにしてもかまいません。

char buf[512];
char *s;

std::cin >> buf;
(char *)malloc(strlen(buf) + 1);

こうして確保されたメモリ領域に、buf []に入っている文字列を移します。

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

void main() {

    char *s, buf[512];
    std::cin >> buf;

    s = (char *)malloc( strlen(buf) +1);
    strcpy(s, buf);
    std::cout << s << std::endl;
}



標準関数 strcpy()について説明します。
この関数は、文字列をコピーする関数です。
ファイルの先頭に、#include を追加しておかなければなりません。

        #define _CRT_SECURE_NO_WARNINGS
        #include <string.h>

     char str1[50];
    char str2[50];
    ・・・・
    strcpy( str1, "yamada" );
    strcpy( str2, str1 );

この例では、配列str[]に文字列"yamada"がコピーされます。
さらに次の行で、str1からstr2へのコピーも行っていますが、str1には、その前のコピーで、"yamada"がコピーされているので、結局、str2にも"yamada"がコピーされます。
ただし、strcpy()は、文字数などは数えないので、コピーされる配列は充分な大きさを自分で注意して確保しなければなりません。
現在、strcpy()は非推奨になっていますので、ビルド時にエラーが出ます。
そのエラーを出ないようにするには、次の行をソースファイルの先頭に記述なければなりません。

#define _CRT_SECURE_NO_WARNINGS

こうすることで、非推奨のメッセージが出ることがなくなります。


現在strcpy()の代わりに推奨されているのは「strcpy_s()」です。
このstrcpy_s()関数を用いて例を書き換えると、以下のようになります。

        #include <string.h>

     char str1[50];
    char str2[50];
    ・・・・
    strcpy_s( str1, 7, "yamada" );
    strcpy_s( str2, 7, str1 );

2つ目の引数で文字列の長さを指定し、安全にメモリを確保します。


実行結果です。



<<前  [TOP]  次>>