質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • C

    3965questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3746questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

文字列とポインタについてです。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 608

strike1217

score 563

以前、int型のポインタについて、質問しました。
今回はchar型のほうです。
1,

char *buf;
scanf("%s", buf);


これがダメな理由を教えてください。NULLポインタで初期化してもsegmentation faultでした。
Linuxだと、上記のやり方でも、エラーはでませんが、windowsだと強制的に終了します。

char buffer[1024];
char *buf = buffer2;
scanf("%s", buf);


こちらは問題ありませんでした。
なので、

char *buf = "you will make me happy";
scanf("%s", buf);


とやってみました。 これもダメでした・・・・

2,

char *buf = "123";
buf = "456";
*buf = 'Z';
これは問題がありません。ですが・・・
*buf = "456";
とやるとエラーです。


なぜです?? *buf = "456"の方が正しくみえるのですが・・・
buf と *bufの違いがまだよくわかっていません。

3,

char str[8];
char *ptr = str;
scanf("%s", &ptr);


これはどういうことですか??
実際にやってみて、printf("%s", ptr);とやるとエラーになるんですが・・・

4,

char s[] = "ABC";
s = "DEF";


これはエラーですね。
なんで、ダメなんですか??
配列の値を上書きするには、他に方法がありますか??

ちょっといろいろ混乱していて、わかりません。
教えてください。

[追記]
int *w, a;
w = &a
printf("%d", *w);
int 型はこうできます。

char *buf = "jfkdoaur";
printf("%s", *buf);これはエラーでした。
printf("%s", buf);
char型の場合はprintf("%s", *buf);ではダメなようです・・・
何が違うんですか??

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

1(前半) 使用可能な領域のアドレスをポインタにセットしていないから。
未初期化のポインタや、ヌルポインタという利用不可能な領域を指すアドレスをセットしたポインタは、使用可能な領域のアドレスをセットしておらず、正しく実行されない。

1(後半) リテラル文字列(二重引用符で囲んだ文字列)は、その内容が格納された読み取り専用領域のアドレスを指す。そのため環境によっては正しく実行されない。

2 どちらにも問題がある。
*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。

3 配列strの「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず(printf関数はヌル文字にあたるまで読み込み続ける)、利用不可能な領域にアクセスしてしまい、異常終了する。

4(前半) C言語には、配列をまるごと別の配列にコピーする命令は用意されていないからです。配列の名前を書くと、そのアドレスを意味するので、質問者さんのコードは

1 = 2;


と無理矢理代入しているようなものになってしまうのです。
面倒でも、

char s[] = "ABC";
s[0] = 'D';
s[1] = 'E';
s[2] = 'F';
s[3] = '¥0';


のように、1要素(文字)ずつコピーする必要があります。
(strcpyという関数を使用すればこの面倒は解消されます。)

4(後半) char型の場合はprintf("%s", *buf);ではダメなようです・・・
ということですが、まさにそれが答えです。
printfの書式設定で、sは「引数のポインタの指す先のアドレス」にある文字列の表示を意味します。
*bufはポインタではなく、char型の変数なので、printf関数が利用不可能な領域にアクセスしてしまい、異常終了します。
1文字表示させたいときには、printf("%c", *buf);
文字列を表示させたいときには、printf("%s", buf);
というように使い分ける必要があります。

3(追記)

char str[8];
char *ptr = str;
scanf("%s", &ptr);


最終行が問題です。これはscanf("%s", ptr);とする必要があります。
例えば、scanf関数で数値を1つint型の変数iに読み込みたいとしたとき、なぜ

scanf("%d", &i);


というように、&を使う必要があるかを説明します。
C言語では、関数の引数は元の変数や値の「コピー」というルールになってます。
コピーの方をいくら操作しても、元の変数には何の影響もありません。
そのため、

scanf("%d", i); /* 本当はダメよ */


というように書いたとしても、元の変数は操作できません。
なので、元の変数の「アドレス」を関数に渡して、そのアドレスの先を操作することで、変数を操作しているのです。
では、文字列を読み込むときはどうでしょうか。
ptrは元々ポインタ、すなわちアドレスですよね。
ptrの指す先の領域を操作すれば、配列の中身を変更できます。
そして、ptrという「ポインタ変数」を操作する必要はありません。操作するのはその「中身」です。
なので、%sという文字列読み込みの書式設定の場合だけ例外で、&ptrではなくptrを渡すというルールになっているのです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/14 16:57

    ありがとうございます。

    キャンセル

  • 2017/01/14 16:59

    行き違いで加筆しました。追記分はこれからさらに加筆します。

    キャンセル

  • 2017/01/14 17:08

    とても、わかりやすいです。

    キャンセル

  • 2017/01/14 17:10

    できるだけ正確に書こうとしたため、かえってわかりにくいところがなかったか心配していますが、内容でまだわかりにくいところはありますか?

    キャンセル

  • 2017/01/14 17:17

    3番ですね。
    char *p;
    scanf("%s", &p);

    ポインタのアドレスをscanfに指定するとどうなるかが、まだよくわかりません

    キャンセル

  • 2017/01/14 17:39

    2番については、再度質問します。

    キャンセル

  • 2017/01/14 17:40

    ありがとうございました

    キャンセル

+1

ポインタは:宣言されただけでは有効なメモリ番地を指し示しているとは限りません。

配列:宣言するだけで有効なメモリ領域を確保し、配列名と先頭番地を指し示すポインタを兼ねます。
→ただし、これは固定のポインタ変数であり、他のアドレスを代入し直すことができません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/14 16:58

    ありがとうございます

    キャンセル

+1

こんにちは。

最初の方だけ、ちろっと回答してみます。

char *buf;

これは、char* buf;と書くと分かりやすいです。char*変数を1つ定義してます。
見ての通り初期化してませんので、不定値のままです。
bufはchar型へのポインタですから、どこか分からない謎の場所を指してます。

scanf("%s", buf);

は、その「謎の場所」へ文字列を読み込みますので、普通は落ちます。
linuxで落ちなかったのはたまたまかも知れません。

char *buf = "you will make me happy";
scanf("%s", buf);

この場合、bufは"you will make me happy"という文字列が記録された先頭メモリを指してます。
そして、"you will make me happy"は定数ですから、最近のPCでは書き換え不可と指定されたメモリ上に記録されます。(この辺はMMUの機能です。x86系CPUはそのような機能をもつMMUを内蔵してます。)
書き換え不可ですから、そこにscanf()で読み込もうとすると、書き換え不可例外が発生し落ちます。

C++でビルドした場合、"you will make me happy"はchar const*型です。それをchar*へ代入しようとした時点でコンパイラによっては警告、もしくは、エラーになると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/14 16:58

    ありがとうございます。
    いままで、初期化されていないポインタを使っていたので、やめますね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    3965questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3746questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。