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

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

C++プログラミング入門その27 ポインタの応用(2020年4月更新)

<<前  [TOP]  次>>


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


【PointerTest6.cpp】

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


int  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>

int 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つ目の引数で文字列の長さを指定して安全にメモリを確保します。


実行結果です。


PointerTest6.cpp実行結果
PointerTest6.cpp実行結果


<<前  [TOP]  次>>