- ベストアンサー
ポインタ変数が引数に宣言されている関数の使い方。
以前、キュープログラムで”BYTE dequeue(BYTE *x)”というのを作成した際に、この作り方で質問させていただきい、この関数だと、 BYTE dequeue(BYTE *x) { if(Head==Tail){ if(QueueState != QSTATE_FULL){ return QSTATE_EMPTY; } } *x=QBuf[Head]; Head=(Head+1)%MAX_BUF_NUM; return QSTATE_VALID; } この関数だと、QueueState = dequeue(&UartSendBuf[i]);というように使用すれば、配列変数のUartSendBuf[i]でiの数値で指定した配列番号のメモリ番地にdequeueしたい値を入れることができ、なおかつ、キュープログラムがちゃんと動作したかのステータス値を戻り値として出力できるということを教わり、戻り値が複数出力できるような関数が作れるので大変便利だなぁと思ったのですが、 ちょっと疑問があるのですが、 QueueState = dequeue(UartSendBuf[i]); というように&を付けずにこのプログラムを動かした場合、どのような動きをプログラムはしてしまうのでしょうか?
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
>i = 8; >QueueState = dequeue(UartSendBuf[i]); >というようにしてこの関数を使ったとしても、以前の関数の動作と全く同じということになるということでしょうか? コンパイルでエラーが起こるかどうかはそのコンパイラや書き方に依存するのでそこは軽く ANSI C準拠で書いて対応コンパイラならエラーが出るでしょうし K&R だっけ?でかいたらエラーは出ません 関数コール側の書き方が間違っているというのは変わりありません ( & を付けない以上ポインタを渡してません プログラムとしては期待する結果を得られません) 改造とかかれてますが >x[0]=QBuf[Head]; のことでしょうか? そのコードであれば *x=QBuf[Head]; と書いているのと同じですので結果は変わりません 例えがよくありませんが 住所と其処に住んでいる居住者の関係をイメージしてください UartSendBuf[i] と書いた場合はUartSendBuf[i]に入っている数値(居住者)を意味します &UartSendBuf[i]と書いた場合は住所を意味します それぞれ意味合いはぜんぜん違います (まずその違いを理解してください) もう少しポインタを学習された方がよいのではないかと思います 再度同じようなこと書きますが 配列変数の場合配列の要素書かずに変数名書いた場合その配列の先頭アドレスが渡されます それが dequeue(UartSendBuf); と dequeue(&UartSendBuf[0]); は同じというのを意味します 特定の配列要素のアドレスを渡したい場合は (&UartSendBuf[j] のように)必ず & と 要素番号 を書く必要があります UartSendBuf[j] と書くと UartSendBuf[j]に格納されている数値が渡されます (関数側はそれをアドレスと思い込んで処理を行います)
その他の回答 (5)
- Tacosan
- ベストアンサー率23% (3656/15482)
いや, C では「コンパイルエラー」にはならないかもしれません>#4. もっとも, 今どきのコンパイラなら警告にすると思うので, 警告を出さないコンパイルオプションをつけている || 警告を見逃す という条件にヒットしなければ分かるでしょうが.
お礼
回答頂きありがとうございます。 私はコンパイラがエラーになるのとならないの原因に関してはちんぷんかんぷんです。ちゃんと変数型とかプログラムをしなきゃなと思いました。
- kmee
- ベストアンサー率55% (1857/3366)
> QueueState = dequeue(UartSendBuf[i]); > というように&を付けずにこのプログラムを動かした場合 動かす以前に、 & UartSendBuf[i] と UartSendBuf[i] とでは型が違うのでコンパイルエラーになりそうですが
お礼
回答頂きありがとうございました。 良くプログラムを作成していて、プログラムの動作を確認するときにシミュレートを使って結果を追って行った時にポインタがどのような動きをするのか理解していなくて混乱させられます。 koi1234さんがおっしゃったように引数にポインタが宣言されているような関数 BYTE dequeue(BYTE *x) こんな関数です。 これで、 BYTE dequeue(test); で使うか、 BYTE dequeue(&test); というのは本当にちんぷんかんぷんだったので、説明をもらってはっと気がつかされました。この点に関して型の問題でコンパイルエラーがでるとかというのは聞いたことがありますが、いまだにちんぷんかんぷんです。 これから頑張ります。
- koi1234
- ベストアンサー率53% (1866/3459)
補足しておきます (&UartSendBuf[0]); この場合UartSendBuf[0]変数の格納アドレスが渡ります 関数側で*X=123; とすると UartSendBuf[0]に123が代入されます (UartSendBuf[0]); この場合UartSendBuf[0]にセットされている数値がアドレスとして渡されます 関数側で*X=123; UartSendBuf[0]に入っていた数値をアドレスと思い どこか見当違いのメモリに123が代入されます その後の結果は最初に書いたとおり
- koi1234
- ベストアンサー率53% (1866/3459)
>QueueState = dequeue(UartSendBuf); >このように使う方がいらっしゃったのですが 上記のように書いた場合は dequeue(&UartSendBuf[0]); と書いているのと同じです (UartSendBuf[0]) ではありません
お礼
回答頂きありがとうございます。、 QueueState = dequeue(UartSendBuf); dequeue(&UartSendBuf[0]); この2つの意味が同じということなんですね。”UartSendBuf”でアドレス番号を指すのですね。 再度質問させて頂き申し訳ないのですが BYTE dequeue(BYTE *x)関数をちょっと改造してみて、 BYTE dequeue(BYTE *x) { if(Head==Tail){ if(QueueState != QSTATE_FULL){ return QSTATE_EMPTY; } } x[0]=QBuf[Head]; Head=(Head+1)%MAX_BUF_NUM; return QSTATE_VALID; } もし、このようにプログラムした場合、 i = 8; QueueState = dequeue(UartSendBuf[i]); というようにしてこの関数を使ったとしても、以前の関数の動作と全く同じということになるということでしょうか?
- koi1234
- ベストアンサー率53% (1866/3459)
プログラムをちゃんと見たわけではありませんが >というように&を付けずにこのプログラムを動かした場合、どのような動きをプログラムはしてしまうのでしょうか? ポインタ使用した処理を処理を間違えると ・一見動いているように見える(実際意図した結果は得られない) ・アプリが暴走して異常終了する ・他のアプリを異常終了する(させる) ・システムに影響してOS自体が落ちる どれかになります(そのときのメモリ状態でどうなるか不定って事です)
お礼
回答いただきありがとうございます。 なんかポインタって今でもかなり自分の理解量に疑いを持っていて、想像がつかない時が結構あり、他人のプログラムをみてて結構戸惑うことが多々あります。 ちょっとこの関数に似たもので BYTE dequeue(BYTE *x) これをこのように、 BYTE UartSendBuf[8]; QueueState = dequeue(UartSendBuf); このように使う方がいらっしゃったのですが、この場合もどのようにプログラムが動いていくのかよくわかりません。たぶんですが、UartsendBufの配列変数が、すべてその関数内の引数として登録されて、これも関数プログラムが動作完了すると、UartsendBuf配列にその関数で得たデータがその配列に自動的に入っているというように使っているようなのですが、
お礼
回答頂きありがとうございます。 >i = 8; >QueueState = dequeue(UartSendBuf[i]); 大変申し訳ありません。QueueState = dequeue(&UartSendBuf[i]); &をつけ忘れていました。 訂正して頂きありがとうございました。 >改造とかかれてますが >>x[0]=QBuf[Head]; >のことでしょうか? そのコードであれば >*x=QBuf[Head]; >と書いているのと同じですので結果は変わりません これはやはり同じ意味になるのですね。 この質問内で2重に質問してしまったのですが、一応自分の理解が正しいか判断したくてしてしまいました。 QueueState = dequeue(&UartSendBuf[8]); この関数の引数で渡しているデータはアドレスの番号なのですね。 &UartSendBuf[8]これのアドレスが0xFFFF08だったならば、関数内の”*x”も”x[0]”も 0xFFFF08というアドレスだということになるんですね。x[1]=0xFFFF09,x[2]=0xFFFF0A ということになって行くんですね。 なんとなくですが、メモリ番地というのを意識するようになってよりマイコンの内部の仕組みが漠然とわかるようになりました。C言語とかわからなくても(それじゃダメじゃん)マイコンなどのIOレジスタ設定などはまさに住所に行って手紙を出しに行くみたいな感覚ですね。 それぞれの作業にkoi1234さんがおっしゃっているような専門用語がすでについているようなので、追って勉強していきたいと思います。