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

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

ただいまの
回答率

89.20%

C言語 ポインタ変数 scanf_s 第二引数へ指定する

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 559

kazuyakazuya

score 150

こちらの内容を見ていて理解できないところが
あったので教えてください。
イメージ説明
下記リンク先のコード

char *gook[10]; 

void go(int i) {
scanf_s("%s",gook[i],4);
}

int main(void){
...
go(0);
...
go(1);

}

こちらの内容を見ていると
scanf_sにポインタ変数を指定しているように見えるのですが
おかしくないですか?

ポインタ変数・・・アドレスを格納するための変数    のはず


もし、以下のような内容なら理解できますが・・・

char gook[10]; 

void go(int i) {
scanf_s("%s",gook[i],4); //文字列を格納する場所(変数)のアドレスを指定・・・多分
}

int main(void){
...
go(0);
...
go(1);

}


ですが
ポインタ変数の場合
そのままの意味で 文字列を格納するための変数ではなく
アドレスを格納するための変数なのですよね?

標準出力で打った文字列が格納されている場所(アドレス)をしている
ということなのでしょうか?
 
分からないので参考になるリンクまたは説明をお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • kazuyakazuya

    2019/09/05 14:37

    後で追記します!

    キャンセル

  • cateye

    2019/09/05 14:53 編集

    scanf()の仕様がポインタを基にその先に変数の格納域が有るのを、前提で動いている事を理解してなかったのでは? (呼び元がデータを受け取る方法が分かってなかったのではないか・・・)

    キャンセル

  • kazuyakazuya

    2019/09/05 16:42 編集

    scanf関数の引数の意味 ポインタの意味については理解していました。

    ポインタ変数はアドレスを記憶する変数。
    つまりポインタ変数のなかにはアドレスが入る。

    この間違ったコードを正しい前提で見ていました。
    char *gook[10];
    scanf_s("%s",gook[2],4);
    すると率直にとらえて


    scanf関数の第二引数には格納さきの アドレス が入る。
    だけど、ポインタ変数って
    アドレスを格納する変数なのだから
    格納する変数をデータ格納さきアドレスとして指定するのは
    おかしいぞ?ということで質問しました。

    もし、scanfの引数にポインタ変数を指定する場合
    中身がなければいけないという
    ことに気づいていれば
    早く理解ができたかもしれません・・・。

    キャンセル

回答 5

checkベストアンサー

+1

scanf_s関数の仕様を正しく理解してください。

この関数は標準入力に入力された文字列を第一引数に従って解釈し、第二引数以降で指定されるメモリアドレスへ格納します。そのため、scanf_sで第二引数以降で指定するパラメタはすべてポインタでなければなりません。

また、%sが指定された場合は指定されたメモリアドレスを起点に複数のバイトにわたってデータを格納します。指定するポインタは適切に確保されたメモリアドレスでなければなりません。

char gook[10]; 

void go(int i) {
    scanf_s("%s",gook[i],4);  //文字列を格納する場所(変数)のアドレスを指定・・・多分
}


はポインタを指定していないのでアウトです。gook[i]はただのchar型変数です。sizeof(gook[i])とした場合、結果は1です
仮に事前にgook[i] = 'B'と設定されいた場合、メモリアドレス0x00000042を起点に格納するだけでほとんどのプラットフォームではエラーになります。

No.208603 はポインタを指定しているがその値がNULL(0x00000000)だったという問題です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/04 21:58

    ありがとうございます。
    第二引数にとにかくアドレスを指定するという部分に関しては理解していると思います。

    キャンセル

+1

その部分だけ見ればおかしくありません。

少し不正確ですが、簡単に言うと C 言語の文字列とは char 配列のことです。文字列を特定するにはその配列の先頭アドレスを使います。アドレスなのでポインタを使います。

詳しくは C 言語の文字列について調べてください。

C 言語と C++ や C# を混同する人がいますが、これらは別の言語です。情報必ず C 言語のものであることを確かめてください。

おそらくそこを間違えています。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/04 21:58

    ありがとうございます。

    キャンセル

+1

ポインタって何? 「アドレスを格納するための変数」...間違いではないです。でも、いきなり「アドレス」が出てくるのはどうでしょう。
(なお、ポインタは変数である、というのはちょっと抵抗あるのですが、かのK&Rでそういう表記をしているので仕方なくそれに従います)

高級言語としての抽象度の高いスコープでは、「どこかにある(変数等の)データ領域を指すための変数」であるということで理解すべきかと思います。

そして、「どこかにあるデータを指す」ための具象的な手段は、以前の回答で示したように変数の実体がメモリの一区画ということなのでその場所「アドレス」を示すことによる、ということです。
(https://teratail.com/questions/208103#reply-307216 " rel="nofollow" target="_blank">以前の質問で、メモリーの話をしましたので、変数とメモリーそしてアドレスの関係はご理解いただいているものと思います)

さて。Cで関数を呼び出すとき、その引数は全て「値渡し」です。値渡しというのは、関数を呼び出す側でカッコの中に記述されたのが変数なら変数の値、式ならその式の結果を、関数の定義側の仮引数に「値として」設定します。結果として、ご存知のように、関数の中でいくら引数として与えられた変数をいじろうとも、関数を呼び出した側には全く影響がありません(もちろん、C言語のことですから間違った方法でいじるととんでもないことが起こるかも知れませんが、それは今は考えません)。
でも、scanf()あるいはscanf_s()で例えば
int a;
scanf("%d",&a);
とすると、aに値が設定されて関数から戻ってきます...何故? もちろん、aに&がついているから。&ってなんでしたっけ。アドレス演算子。アドレス演算子って何をする?  オペランド(演算対象)の変数のアドレスを求める。アドレスを値として持つものってなんだったけ...はい、ポインタです。ポインタつまり変数の在り処を関数に値として渡すと、関数は変数の在り処がわかるので、変数の中身を操作出来るのです。

つまり、関数内で、呼び出し元の変数の中身を操作するとき、必ず引数としてポインタが与えられる必要があるのです。前のbzero()なんかも同じ話だったわけですし、scanf()でももちろんそう。

char gook[10]; 

void go(int i) {
  scanf_s("%s",gook[i],4); //文字列を格納する場所(変数)のアドレスを指定・・・していません
}


でscanf_s()に与えられているのはgook[i]。これはchar型の変数です。これで関数を呼び出すと、char型の値がscanf_s()に渡されますが...gook[i]が例えば128だったとして、それを貰ったscanf_s()としては、'128'を知ってもgook[i]を変化させる術にはならないのです。

(なお、C言語ではそもそも値の型チェックがおざなりでバグの元となりがちなのですが、 scanfは汎用性を実現するためにほとんど引数のチェックが行われず、本当にとんでもない呼び出しでもエラーにも警告にもならずに粛々と破滅的な動作をしたりします。)


「ポインタの配列に代入」で問題になっていたのはなんだったか...

確かRubyでもempty?ってありますよね。そういうことです。ポインタの配列は宣言しました。でも、その配列の要素であるそれぞれのポインタはどこを指しているのでしょう...変数の宣言場所によって期待値はちょっと変わりますが、いずれにせよ意味のあるオブジェクトを設定していないので駄目、というのがその質問の骨子です。


配列とポインタの関係

Cは、いろいろな手間を「プログラマの責任」で片付けることで処理系の負担を減らし、かつ人間の方が頭を絞ることで効率の良いプログラムを組めるようにしている言語です。そのポリシーの一環として、配列の扱いがとんでもないこと(?)になっています。
配列って、その要素になる変数が並んでいるものです。なら、先頭要素の在り処(ポインタ)だけわかれば、2番め、3番めにもアクセス出来ますね。じゃあそういうことに決めましょう。配列を扱うときは、先頭の要素へのポインタを扱うものとします。要素数? 別途管理して下さい...そういうことです。

文法的なところで言えば、配列を宣言し、その配列が単独で記述されたとき、コンパイラはそれを「配列の先頭要素へのポインタと解釈する」というCの規則があるのです。(例外はちょっとあって、それこそ&演算子を作用させるときとかはイロイロあるんですけれど、今は棚上げしておきます)

そのため、

char gook[10]; 

void go( void ) {
  scanf_s("%s",gook,4); //文字列を格納する場所(変数)のアドレスを指定している
}


というプログラム(片)は正しくて、gookに標準入力から文字列を取り込むことが出来ます。
ちなみに、配列の要素 gook[i]に「文字」を取り込むなら&を使って

char gook[10]; 

void go(int i) {
  scanf_s("%c",&gook[i],4); //文字を格納する場所(変数)のアドレスを指定する
}


となります。gookもポインタ、&gook[i]もポインタであることは言うまでもありません。


ちょっと周辺まで書きすぎてボケちゃったかな...

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/05 16:43

    ありがとうございます。

    キャンセル

0

BAが出ていますが、ちょまどさんのページにポインタで渡す場合の解説が有ります。
C言語における値渡しと参照渡し
確認してみて下さい。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/05 16:44

    ありがとうございます。

    キャンセル

-4

なにをいいたいのかわからないですが、そのコードはダメです
なので考えても無駄です

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/04 18:16

    リンク先は、そもそもコードがおかしいというものなので、それでなにをしたいんですか?(二回目

    キャンセル

  • 2019/09/04 18:34

    そのおかしい?コードを見て
    私も疑問をもったので質問をしただけです。

    なにをしたいのか?
    >何かをしたくて質問しているわけではございません。

    キャンセル

  • 2019/09/04 18:45

    なら、そのコードはダメです
    で納得できませんか?

    キャンセル

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

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