文字列を表すための配列とポインタ
配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、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;」
と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。
No.7
- 回答日時:
「コード上は同じように扱えるが別のもの」であることを理解してないとこうなります。
私も同じことをやった時期がありました。
char a[256];
は「aという名前のchar配列(要素数256)」であるのに対し
char *b;
は「bという名前のcharポインタ」です。
ポインタは、その先に示すものが正しく存在しないと機能しません。
この場合はaとは異なるchar配列を定義するか、あるいはmalloc()等の動的メモリ確保を利用するかしてbの参照先を用意する必要があります。
No.6
- 回答日時:
char a[256]; → 256バイトのメモリが確保される
char *b; → メモリは確保されない(メモリの番地を入れておくぶんは確保されます)
bは単にメモリの番地を入れておく変数で、char *b;と宣言してもメモリ自体は確保されません。なので、他の回答者が回答されているようにmalloc関数等でメモリを確保してから、そのメモリの先頭番地をbに入れてください。
scanf("%s", b);は、bで示されている番地のメモリに標準入力(キーボード)から入力された値を入れます。なので、その入力した値を入れるメモリ領域が必要なのです。
char *b;
のあとには、bへの何らかの代入操作が必要なようですね、自分でもいろいろポインタの初期化について調べてみました。言葉で説明すると、抽象的でどうも私には分かりにくいです。ありがとうございました。
No.5
- 回答日時:
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)でメモリを解放する必要があります。
>コンピュータアーキテクチャ、stack、heap等を勉強してみるとこういう問題がわかってくると思いますよ。
>あと、mallocを使った場合は、free(b)でメモリを解放する必要があります。
そういう勉強をしたいものです。それから、free(b)についてのご指摘も、ありがとうございました。
No.4
- 回答日時:
あ, すみません, #3 の「たまたま配列をあたかも (定数) ポインタのように使える場合がある」は間違いです. 正しくは
たまたま配列指示子をあたかも (定数) ポインタのように使える場合がある
です. 「配列指示子」はわかりにくいので (多少不正確ではあるが)
たまたま配列名をあたかも (定数) ポインタのように使える場合がある
と思ってもいい.
いずれにしても, 本質的に配列とポインタとは違うものです.
No.1ベストアンサー
- 回答日時:
「初期化されていないローカル変数'b'が使用されます」
b にアドレスを代入してあげましょう。
#include <stdlib.h>
b = (char*)malloc(256);
この回答への補足
ありがとうございます。
もう少し詳しく教えていただけませんでしょうか。すなわち、
char *b;
b = (char *)malloc(256);
と二行に分ければよいのか、
char *b = (char *)malloc(256);
と一行にまとめてよいのか(済みません、よく分かっていません)、よろしくお願いします。
それから、このように文字列を使うときは、ポインタより配列を使う方がよいのでしょうか。よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# str[j++]の意味 2 2022/08/30 16:20
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# 【C言語】全角文字の配列を、全角のまま1文字ずつ出力する方法 4 2023/05/09 15:08
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
文字列内の数字削除
-
C言語のintとcharの違いってな...
-
文字列str内の全ての数字を...
-
C言語で文字列をかえす正しい書...
-
SetWindowTextについて。
-
char*を初期化したいのですが
-
構造体が戻り値の関数について...
-
strcat関数を自作したいです
-
CStringからchar*への型変換に...
-
C言語を用いた環境変数の作成/...
-
C言語でポインターで詰まってい...
-
C言語にて構造体のメンバがNULL...
-
char型にint型の数値を代入する。
-
new charとnew char[N]の違いは?
-
char 文字列型 の表現範囲が-12...
-
C言語において、以下の条件で...
-
p = (char **)*p の意味
-
文字の代入とコピーについて
-
ポインタを使用 [数字列を数値...
-
文字列の途中から途中までを抽出
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
CStringからchar*への型変換に...
-
C言語にて構造体のメンバがNULL...
-
小数点入りの文字列をfloat型に...
-
C言語のプログラムについてです
-
strcat関数を自作したいです
-
fstream型オブジェクトを関数の...
-
new charとnew char[N]の違いは?
-
DWORDとcharの変換
-
文字列の途中から途中までを抽出
-
char 文字列型 の表現範囲が-12...
-
const char* s1とただのchar s1...
-
wsprintf( ポインタ , "%d" , "...
-
c言語でポインタ変数を用いた配...
-
char型にint型の数値を代入する。
-
C言語で文字列をかえす正しい書...
-
C++17で、unsigned char * 配列...
-
共用体について
-
エクセルのMID関数は、C言語では?
おすすめ情報