アプリ版:「スタンプのみでお礼する」機能のリリースについて

文字列を表すための配列とポインタ
 配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、Visual Studio 2010 コマンドプロンプトです。

#include <stdio.h>

void main(void)
{
char a[256];
char *b;

printf("文字列を入力してください。\n");
printf("例「abcde」\n\n");

printf("配列型文字列を使います。\n");
scanf("%s", a);
printf("文字列は%sです。\n\n", a);

printf("ポインタ型文字列を使います。\n");
scanf("%s", b);
printf("文字列は%sです。\n", b);
}

 すると、まずコンパイル時に、
「warning C4700: 初期化されていないローカル変数'b'が使用されます」
と表示されました。そして、実行すると、「配列型文字列」の方は問題ないのですが、「ポインタ型文字列」の方の実行後に、
「x.exeは動作を停止しました。

問題が発生したため、プログラムが正しく動作しなくなりま
した。プログラムは閉じられ、解決策がある場合は
Windowsから通知されます。」
と表示され、エラーとして終了してしまいます。
「char *b;」
と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。

A 回答 (7件)

「コード上は同じように扱えるが別のもの」であることを理解してないとこうなります。


私も同じことをやった時期がありました。

char a[256];

は「aという名前のchar配列(要素数256)」であるのに対し

char *b;

は「bという名前のcharポインタ」です。

ポインタは、その先に示すものが正しく存在しないと機能しません。
この場合はaとは異なるchar配列を定義するか、あるいはmalloc()等の動的メモリ確保を利用するかしてbの参照先を用意する必要があります。
    • good
    • 0
この回答へのお礼

 ありがとうございます。

お礼日時:2010/06/01 00:10

char a[256]; → 256バイトのメモリが確保される


char *b; → メモリは確保されない(メモリの番地を入れておくぶんは確保されます)

bは単にメモリの番地を入れておく変数で、char *b;と宣言してもメモリ自体は確保されません。なので、他の回答者が回答されているようにmalloc関数等でメモリを確保してから、そのメモリの先頭番地をbに入れてください。

scanf("%s", b);は、bで示されている番地のメモリに標準入力(キーボード)から入力された値を入れます。なので、その入力した値を入れるメモリ領域が必要なのです。
    • good
    • 0
この回答へのお礼

char *b;
のあとには、bへの何らかの代入操作が必要なようですね、自分でもいろいろポインタの初期化について調べてみました。言葉で説明すると、抽象的でどうも私には分かりにくいです。ありがとうございました。

お礼日時:2010/06/01 00:09

char a[256];


char *b;

printf等で出力した場合、aはa[256]の先頭アドレスを出力します。
一方、bはcharデータのアドレスを格納する変数です。

質問にあるプログラムで、scanfでbの指すアドレスに文字列を格納するにはまずbにメモリ領域の先頭アドレスを代入する必要があります。例えば、a[256](stackにある配列)に文字列を格納したいなら、
b=a; 
scanf("%s", b);
とすればよいと思います。

また、動的メモリ領域(heap)に格納したいなら、他の回答にもあるようにmallocまたはcallocを使ってまずメモリ領域を確保してからscanfを使えばいいと思います。

つまり、bが確保されているメモリ領域(stackでもheapどちらでも)を指していればコンパイラもOSも文句はいいません。質問にあるプログラムではbは初期化されていないので、scanf("%s", b);でランタイムエラーが発生します。

コンピュータアーキテクチャ、stack、heap等を勉強してみるとこういう問題がわかってくると思いますよ。
あと、mallocを使った場合は、free(b)でメモリを解放する必要があります。
    • good
    • 0
この回答へのお礼

>コンピュータアーキテクチャ、stack、heap等を勉強してみるとこういう問題がわかってくると思いますよ。
>あと、mallocを使った場合は、free(b)でメモリを解放する必要があります。

 そういう勉強をしたいものです。それから、free(b)についてのご指摘も、ありがとうございました。

お礼日時:2010/05/31 23:56

あ, すみません, #3 の「たまたま配列をあたかも (定数) ポインタのように使える場合がある」は間違いです. 正しくは


たまたま配列指示子をあたかも (定数) ポインタのように使える場合がある
です. 「配列指示子」はわかりにくいので (多少不正確ではあるが)
たまたま配列名をあたかも (定数) ポインタのように使える場合がある
と思ってもいい.
いずれにしても, 本質的に配列とポインタとは違うものです.
    • good
    • 0
この回答へのお礼

 ありがとうございます。

お礼日時:2010/05/31 23:54

「配列とポインタは同様に扱えるもの」という思い込みは捨ててください.


配列とポインタは全く別物です. 「たまたま配列をあたかも (定数) ポインタのように使える場合がある」だけ.
    • good
    • 0
この回答へのお礼

 はい。分かりました。

お礼日時:2010/05/31 23:51

>二行に分ければよいのか、


>一行にまとめてよいのか

【2行に分けねばならない場合】
char *b;
/* 何かの文(1個以上) */
b = malloc(256);

【1行でよい場合】
char *b = malloc(256);

【2行でよい場合(定義の直後に代入)】
char *b;
b = malloc(256);


他の型の変数の場合と、何ら変わりません。
    • good
    • 0
この回答へのお礼

 ありがとうございます。よく分かりました。

お礼日時:2010/05/31 23:47

「初期化されていないローカル変数'b'が使用されます」


b にアドレスを代入してあげましょう。
#include <stdlib.h>
b = (char*)malloc(256);

この回答への補足

 ありがとうございます。
 もう少し詳しく教えていただけませんでしょうか。すなわち、
char *b;
b = (char *)malloc(256);
と二行に分ければよいのか、
char *b = (char *)malloc(256);
と一行にまとめてよいのか(済みません、よく分かっていません)、よろしくお願いします。
 それから、このように文字列を使うときは、ポインタより配列を使う方がよいのでしょうか。よろしくお願いします。

補足日時:2010/05/30 18:03
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!