ポインタについて
Re: ポインタについて
ポインタも値渡しなんですが、それは置いといて。
値を入れる箱(実体がはいる変数)がどこに用意されるのかということを考える必要があります。
関数に引数で渡された変数はローカル変数ですから、その関数から戻るときに消えてなくなります。
ですから、そこの値を関数内で変更しても呼び出し側からは知る由がないということです。
値を入れる箱(実体がはいる変数)がどこに用意されるのかということを考える必要があります。
関数に引数で渡された変数はローカル変数ですから、その関数から戻るときに消えてなくなります。
ですから、そこの値を関数内で変更しても呼び出し側からは知る由がないということです。
non
Re: ポインタについて
ほとんど回答になってない回答では質問者がかえって混乱するので、わかりやすく説明します。
例としてprintf()にint xを使います。
1.printf("%d\n",x);
仮引数が2つあります。よって、
関数呼び出したときにchar変数列に第一引数のコピー、int 型変数に第二引数(x)のコピーが作成されます。
関数終了時に仮引数は削除され、もとのxや"%d\n"に影響はないです。
2.printf("%d\n",&x);
仮引数が2つあります。よって、
関数呼び出したときにchar変数列に第一引数のコピー、int型ポインタに第二引数(xのアドレス)のコピーが作成されます。
関数終了時に仮引数は削除され、もとの"%d\n"に影響はないですが、アドレスによって参照されたxは変更されたままです。
例としてprintf()にint xを使います。
1.printf("%d\n",x);
仮引数が2つあります。よって、
関数呼び出したときにchar変数列に第一引数のコピー、int 型変数に第二引数(x)のコピーが作成されます。
関数終了時に仮引数は削除され、もとのxや"%d\n"に影響はないです。
2.printf("%d\n",&x);
仮引数が2つあります。よって、
関数呼び出したときにchar変数列に第一引数のコピー、int型ポインタに第二引数(xのアドレス)のコピーが作成されます。
関数終了時に仮引数は削除され、もとの"%d\n"に影響はないですが、アドレスによって参照されたxは変更されたままです。
Re: ポインタについて
「char変数列に第一引数のコピー」ってどういう意味でしょうか?ただの屍のようだ さんが書きました: 例としてprintf()にint xを使います。
1.printf("%d\n",x);
仮引数が2つあります。よって、
関数呼び出したときにchar変数列に第一引数のコピー、int 型変数に第二引数(x)のコピーが作成されます。
第一引数で渡されるのはアドレスのコピーであって、char変数列ではないと思いますが。
Re: ポインタについて
配列渡すときは先頭のポインタを渡すが
このタイミングでいうと今度は配列とポインタをごちゃごちゃしてしまいそうなので
あえて、わかりやすいようリテラルそのものをコピーしたという表現をとりました。まる
このタイミングでいうと今度は配列とポインタをごちゃごちゃしてしまいそうなので
あえて、わかりやすいようリテラルそのものをコピーしたという表現をとりました。まる
Re: ポインタについて
ポインタは便利な機能ですが、やはり2,3行で説明しきれるものではないので、
「C言語 ポインタ完全制覇」をお勧めします。ざっくり読んだだけでもポインタの知識は身につきます。
ついでに、ヘッダファイルやら可変長構造体やらも勉強できるので、
時間取れるのであれば書物での学習のほうが効率いいです。そのぶん、金かかります。
せっかくなので課題出します。 あとで聞かれてもいつ返事返せるか(返す気になるのか)わからないので、答えあらかじめいっておきます。 文字列リテラルは変更できません
「C言語 ポインタ完全制覇」をお勧めします。ざっくり読んだだけでもポインタの知識は身につきます。
ついでに、ヘッダファイルやら可変長構造体やらも勉強できるので、
時間取れるのであれば書物での学習のほうが効率いいです。そのぶん、金かかります。
せっかくなので課題出します。 あとで聞かれてもいつ返事返せるか(返す気になるのか)わからないので、答えあらかじめいっておきます。 文字列リテラルは変更できません
Re: ポインタについて
そんなんじゃわからないだろうと批判を受けましたので、もう少し詳しく。SD さんが書きました:それがなぜポインタを使うことによって値渡しをした関数内での変化が、もとの値渡しをする
変数に影響を与えるのかがしりたいです。
ポインタを使う場合、実際に値が入る箱は呼び出し側に用意されており、関数には、その箱のアドレスが渡されます。
関数側では、そのアドレスを使って、アドレスが指している場所(呼び出し側に用意された箱)の値を直接操作します。
関数から帰るとき、アドレスは忘れてしまいますが、呼び出し側の箱は直接変更されているため、値が変わってます。
non
Re: ポインタについて
int *p, a;
p = &a;
屍さんのようにpがaのエイリアスとなるかのように説明するので混乱するひとが後を絶たないのだと思いますが。
まず変数をきちんと理解しましょう。
int a;
と宣言するとint型の値を格納する記憶域が用意されます。
その記憶域をaという名前で参照できます。
変数名を使うのは記憶域にアクセスするための手段です。
記憶域には固有のアドレスがあります。
アドレスは値です。
&aは変数aの記憶域のアドレスです。
int *p;
変数pも変数です。
int*型の値を格納する記憶域を持ちます。
p = &a;
&aで取得したアドレス(値)をコピーして変数pに格納します。
pは変数pの記憶域にアクセスします。
そこには、アドレスが入っています。
*pだと変数pの記憶域に格納されたアドレスが示す先の記憶域にアクセスできます。
関数の仮引数にアドレスのコピーを渡すことで、そのアドレスが示す先の記憶域を書き換えることができるわけです。
p = &a;
屍さんのようにpがaのエイリアスとなるかのように説明するので混乱するひとが後を絶たないのだと思いますが。
まず変数をきちんと理解しましょう。
int a;
と宣言するとint型の値を格納する記憶域が用意されます。
その記憶域をaという名前で参照できます。
変数名を使うのは記憶域にアクセスするための手段です。
記憶域には固有のアドレスがあります。
アドレスは値です。
&aは変数aの記憶域のアドレスです。
int *p;
変数pも変数です。
int*型の値を格納する記憶域を持ちます。
p = &a;
&aで取得したアドレス(値)をコピーして変数pに格納します。
pは変数pの記憶域にアクセスします。
そこには、アドレスが入っています。
*pだと変数pの記憶域に格納されたアドレスが示す先の記憶域にアクセスできます。
関数の仮引数にアドレスのコピーを渡すことで、そのアドレスが示す先の記憶域を書き換えることができるわけです。
Re: ポインタについて
こういうふうに書くと、ウィンドウズだと書き換えられるけどなんで?って話になってしまうでしょう。ただの屍のようだ さんが書きました:あとで聞かれてもいつ返事返せるか(返す気になるのか)わからないので、答えあらかじめいっておきます。 文字列リテラルは変更できません
Re: ポインタについて
文字列リテラルはこの場合 "Hello!!" の部分を指します。ただの屍のようだ さんが書きました:ポインタは便利な機能ですが、やはり2,3行で説明しきれるものではないので、
「C言語 ポインタ完全制覇」をお勧めします。ざっくり読んだだけでもポインタの知識は身につきます。
ついでに、ヘッダファイルやら可変長構造体やらも勉強できるので、
時間取れるのであれば書物での学習のほうが効率いいです。そのぶん、金かかります。
せっかくなので課題出します。 あとで聞かれてもいつ返事返せるか(返す気になるのか)わからないので、答えあらかじめいっておきます。 文字列リテラルは変更できません
str[] と str* はリテラルとは関係ありませんから、文字列リテラルは変更できないというのは誤りです。
Re: ポインタについて
変更できません。実行時エラーになるはずです。
少なくとも自分のgccではちゃんと強制終了になりました。
あと、警告メッセージ見てみるとわかると思いますが、const付きなのでC++でconst_castしない限り変更できないはずです。
そして、変更できない理由としては、文字列リテラルは変数ではなく、定数ですから。
(結局、自分で問題出して、自分で解説して回答まで書く形になるとは・・・)
少なくとも自分のgccではちゃんと強制終了になりました。
あと、警告メッセージ見てみるとわかると思いますが、const付きなのでC++でconst_castしない限り変更できないはずです。
そして、変更できない理由としては、文字列リテラルは変数ではなく、定数ですから。
(結局、自分で問題出して、自分で解説して回答まで書く形になるとは・・・)
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ポインタについて
私の環境で試すと、ファイル名をmain.cと仮定しますがcygwinのgcc main.cでもcl main.cでコンパイルしてもエラーは出ませんし、実行したらhalloに書き換えられています。
状況を限定するなら特定の状況ではと書くべきで、全部に通じるかのように書くのは危険だと思います。
状況を限定するなら特定の状況ではと書くべきで、全部に通じるかのように書くのは危険だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ポインタについて
その通りですが、検証方法書かれていないただの屍のようださんの方が不明確な論証だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ポインタについて
だからウィンドウズの処理系では文字列リテラルを書き換えられると既に書いているでしょう。
未定義の動作についてきちんと調べてから書くようにしてはいかがですか?
そもそも今回は未定義の動作に触れる必要ないですし。
未定義の動作についてきちんと調べてから書くようにしてはいかがですか?
そもそも今回は未定義の動作に触れる必要ないですし。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ポインタについて
そうですね。質問者の方に迷惑なので、話を元に戻しましょう。
リテラルへの代入は話がややこしくなるだけなので、今回はパスしたほうが良いと思います。
ISLe さんのNo: 8の説明が一番明確だと思いますので、SDさんはその内容で疑問があれば質問してもらうのが良いと私は思います。
【追記】 一応図に書いてみたけど、イマイチかもしれません。
アドレスは仮の値で現実には、この値ではないです。アドレス0x1000などが変数に割り当てられるメモリ・アドレスです。
リテラルへの代入は話がややこしくなるだけなので、今回はパスしたほうが良いと思います。
ISLe さんのNo: 8の説明が一番明確だと思いますので、SDさんはその内容で疑問があれば質問してもらうのが良いと私は思います。
【追記】 一応図に書いてみたけど、イマイチかもしれません。
アドレスは仮の値で現実には、この値ではないです。アドレス0x1000などが変数に割り当てられるメモリ・アドレスです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ポインタについて
ふむふむ、これは突っ込むべきか、スルーすべきか、実に悩むところです。
必要最低限だけ説明しよう。
char str[] = "Hello!!"; は単なる str = {'H','e','l','l','o','!','!','\0'}; の略で、配列をHello!!で初期化すると言う意味です。
char *str = "Hello!!" は 文字列リテラルの先頭アドレスをstrに代入するという意味です。
*ちなみに、自分のPCはwindows7です。コンパイラはgccでもVC++2010でも実行時エラーで異常終了します。
必要最低限だけ説明しよう。
char str[] = "Hello!!"; は単なる str = {'H','e','l','l','o','!','!','\0'}; の略で、配列をHello!!で初期化すると言う意味です。
char *str = "Hello!!" は 文字列リテラルの先頭アドレスをstrに代入するという意味です。
*ちなみに、自分のPCはwindows7です。コンパイラはgccでもVC++2010でも実行時エラーで異常終了します。
Re: ポインタについて
gcc -fwritable-strings main.c を試してみてください。ただの屍のようだ さんが書きました:変更できません。実行時エラーになるはずです。
少なくとも自分のgccではちゃんと強制終了になりました。
Re: ポインタについて
別にgcc -fwritable-strings main.c で試すまでもない、ボーランドC++5.5なら警告すら出さずに通してくれます。エラーにもなりません。
昔、この掲示板で言われたことをそのまま(正確に覚えてないが可能な限り原文に近い形で)言い返します。
VC++だけ通るコードをいくら書いてもなんの価値もないです。そもそも肝心のVC++すら通らないじゃないですか(笑)
昔、この掲示板で言われたことをそのまま(正確に覚えてないが可能な限り原文に近い形で)言い返します。
VC++だけ通るコードをいくら書いてもなんの価値もないです。そもそも肝心のVC++すら通らないじゃないですか(笑)
Re: ポインタについて
「実際にどうなるのか」については置いといても,
>ボーランドC++5.5なら警告すら出さずに通してくれます。エラーにもなりません。
これって,ご自身で 「なぜ エラーになる のか」 という課題とやらを出してることに対して矛盾してますよね?
本題については 私も
>ISLe さんのNo: 8の説明が一番明確だと思います
>ボーランドC++5.5なら警告すら出さずに通してくれます。エラーにもなりません。
これって,ご自身で 「なぜ エラーになる のか」 という課題とやらを出してることに対して矛盾してますよね?
本題については 私も
>ISLe さんのNo: 8の説明が一番明確だと思います
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: ポインタについて
既に質問内容と論点がかけ離れてますのでSDさんの迷惑になります。リテラル問題は別のトピックに移っていただくようにお願いします。 以後はあちらでお願いします。
「激論中の文字列リテラル • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=13395
こちらは、質問主であるSDさんの質問に回答する場としたいと思います。
「激論中の文字列リテラル • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=13395
こちらは、質問主であるSDさんの質問に回答する場としたいと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: ポインタについて
>2.printf("%d\n",&x);
>仮引数が2つあります。よって、
>関数呼び出したときにchar変数列に第一引数のコピー、int型ポインタに第二引数(xのアドレス)のコピーが作成されます。
>関数終了時に仮引数は削除され、もとの"%d\n"に影響はないですが、アドレスによって参照されたxは変更されたままです。
誰も触れてないけど これでxの値が何か別のものに変更されるとは思えないのですが??
>仮引数が2つあります。よって、
>関数呼び出したときにchar変数列に第一引数のコピー、int型ポインタに第二引数(xのアドレス)のコピーが作成されます。
>関数終了時に仮引数は削除され、もとの"%d\n"に影響はないですが、アドレスによって参照されたxは変更されたままです。
誰も触れてないけど これでxの値が何か別のものに変更されるとは思えないのですが??
Re: ポインタについて
ポインタ型でない変数を引数にした場合とポインタ型変数を引数にした場合で
値の変化にどのような違いが出るかを調べるために以下のようなコードを書きました。
実行結果の例
functionAの場合は引数xで整数型の値を受け取り、引数xの値を変えるだけで他には何の影響もありません。
functionBの場合は引数qで整数型のポインタの値を受け取り、
整数型の変数bを宣言して引数qの値を&bに変えていますがこれも何の影響もありません。
functionCの場合は引数qで整数型のポインタの値を受け取り、引数qの値が示す場所の値を変えています。
例の場合ではqには&aが入り、aの値を変えることになります。
functionAでは受け取った値を10にしていて(x=10;)、
functionCでは受け取った値が示す場所の値を10にしている(*q=10;)
という違いがあります。
値の変化にどのような違いが出るかを調べるために以下のようなコードを書きました。
#include <stdio.h>
void functionA(int x){
x=10;
}
void functionB(int *q){
int b;
q=&b;
printf("functionB内で宣言されたbのアドレス\n");
printf("&b=%d\n\n",&b);
}
void functionC(int *q){
*q=10;
}
int main(void){
int a=0;
int *p=&a;
printf("初期化後\n");
printf("a=%d,&a=%d,p=%d,*p=%d\n\n",a,&a,p,*p);
functionA(a);
printf("functionA(a)実行後\n");
printf("a=%d,&a=%d,p=%d,*p=%d\n\n",a,&a,p,*p);
functionB(p);
printf("fuctionB(p)実行後\n");
printf("a=%d,&a=%d,p=%d,*p=%d\n\n",a,&a,p,*p);
functionC(p);
printf("functionC(p)実行後\n");
printf("a=%d,&a=%d,p=%d,*p=%d\n\n",a,&a,p,*p);
return 0;
}
初期化後
a=0,&a=4127592,p=4127592,*p=0
functionA(a)実行後
a=0,&a=4127592,p=4127592,*p=0
functionB内で宣言されたbのアドレス
&b=4127352
fuctionB(p)実行後
a=0,&a=4127592,p=4127592,*p=0
functionC(p)実行後
a=10,&a=4127592,p=4127592,*p=10
続行するには何かキーを押してください . . .
functionBの場合は引数qで整数型のポインタの値を受け取り、
整数型の変数bを宣言して引数qの値を&bに変えていますがこれも何の影響もありません。
functionCの場合は引数qで整数型のポインタの値を受け取り、引数qの値が示す場所の値を変えています。
例の場合ではqには&aが入り、aの値を変えることになります。
functionAでは受け取った値を10にしていて(x=10;)、
functionCでは受け取った値が示す場所の値を10にしている(*q=10;)
という違いがあります。