• ベストアンサー

ポインタ配列について

/************配列 change1.c ***********/ #include <stdio.h> void change(char *c) { c[0]='a'; c[1]='b'; c[2]='c'; } int main(int agrc, char **agrv) { change(*++agrv); printf("%s",*agrv); return(0); } /**********ポインタ change2.c ***********/ #include <stdio.h> void change(char *c) { c="abc"; } int main(int agrc, char **agrv) { change(*++agrv); printf("%s",*agrv); return(0); } ********************* この2つのプログラムchange1.c,change2.cにおいて、次のようにしたとき結果がこうなります \change1.exe 123 abc \change2.exe 123 123 change2.c において、ポインタでの文字の格納 c="abc"; は何故実行されないのですか?

  • rousei
  • お礼率56% (111/196)

質問者が選んだベストアンサー

  • ベストアンサー
  • MovingWalk
  • ベストアンサー率43% (2233/5098)
回答No.7

私の説明が適切じゃなかったようです。 関数void change(char *c) の引数cは、ポインタ型の変数で、これは、main関数に その実態がある文字列(実際にはargv[1])の先頭アドレスを指していますね。 ・まず、strcpy(c,"abc"); や c[0]='a'; とした場合ですが、  この場合は、そのアドレスの中にあるデータ(文字を)を直接書き換え  ますので、main関数にも反映されます。 ・一方、c="abc"; とした場合は、ポインタ変数cの値(文字列の位置)を  "abc"が配置されているアドレスに書き換えることになります。  このため、もともとcが指していたアドレスにあったデータ(文字)の内容が  変わるわけではなく、main関数には反映されません。  (引数cの値自体が変わっても呼び出し元には反映されません)

rousei
質問者

お礼

詳しくありがとうございます^^ なんとなく理解できました

その他の回答 (6)

  • gimmick
  • ベストアンサー率49% (134/270)
回答No.6

change1.cのchange()ではポインタ変数cの指している領域の値を変更します。それに対し、change2.cのchange()ではポインタ変数cの値自体を変更します。change2.cのcはローカル変数なので、cの値が変化したところでmain()の方に影響はありません。なお、以下のようにポインタのポインタを利用すれば"abc"と表示させる事が可能です。(ただし、書き換え禁止領域を指しているので注意が必要です。) void change(char **c) {   *c = "abc";   return; }

rousei
質問者

お礼

ありがとうございます^^ なんかわかったような気がしてきました・・ 参考にして自分でもう一度考えて見ます!

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.5

change2.c において、引数 char* c の c は change 関数内の動的変数です。いくら c の値を書き換えても change 関数を抜ければローカル変数(スタックに積まれた変数)は解放されてしまいます。 main () {  int a = 1;  func (a);  printf ("%d\n", a); } func (int b) {  b = 9; } 下のプログラムでやっていることはこれと同じ事です。

rousei
質問者

お礼

ありがとうございます^^

  • nightowl
  • ベストアンサー率44% (490/1101)
回答No.4

すみません、長々と説明しておいて恐縮ですが、 これを「スコープ」の問題というのは適当ではありませんでした。 MovingWalk さんのおっしゃった通り、ああした形の初期化(代入)は 宣言の時にしか行えません。 また、これもご質問とは直接関係はないのですが、change1.c における change() 中の "abc" は書き換え不可能な領域に置かれていて、 プログラマが自由に代入できる文字の配列とは別種の文字列です。 それを除けば、change() 内の「c="abc";」の結びつきが関数を出れば失われる というのは本当です。失礼しました。

rousei
質問者

お礼

ありがとうございます^^ でも何故 c[0]='a'; といった格納は関数を抜けてもmainで生きているのでしょうか。 c="abc" と c[0]='a'; c[1]='b'; c[2]='c'; c[3]='\n'; は同じだと思っていたのですが^^; cがローカルならc[0..3]もローカルってわけではないのですか?

  • nightowl
  • ベストアンサー率44% (490/1101)
回答No.3

プログラム change2.c における文字列 "abc" は、 関数 change() の中でのみ生きています。 だから、change() を抜けた次の printf() の時点では "abc" はすでに死んでおり、 *agrv とは縁もゆかりもなくなってしまいます。 これは変数の「スコープ(有効範囲)」の問題ですね。 プログラム change1.c では change() 内で実際に *agrv の要素が 書き換えられてしまうのとは対照的です。 「スコープ」や、「値渡し」と「参照渡し」の違いについても 「C言語FAQ」などで勉強してみてください。 ついでに言えば agrc, agrv はそれぞれ argc(argument count), argv(argument vector) の typo ですね。

参考URL:
http://www.catnet.ne.jp/kouno/c_faq/c_faq.html#contents,http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide4-0.html
  • MovingWalk
  • ベストアンサー率43% (2233/5098)
回答No.2

>こういう格納は出来ないようになっているものなんですか? そうですね。 char *c="abc"; というように初期化のときできますが、それ以外ではできません。

rousei
質問者

お礼

ありがとうございます^^ すいません、くだらないことですが、 char *c c="abc"; と char *c="abc"; は何か違いがあったりしますか? char *c c="abc"; でも一応cに文字を格納することができました^^;

  • MovingWalk
  • ベストアンサー率43% (2233/5098)
回答No.1

c="abc";  → strcpy(c,"abc"); としてください。

rousei
質問者

お礼

あ、わざわざありがとうございます! 実を言うとそれは大丈夫なのですが、何故ダメなのかという理由を知りたいです^^; こういう格納は出来ないようになっているものなんですか?

関連するQ&A

  • 配列について

    初歩的な質問ですいませんが、質問よろしくお願いします。 ◎1----------------------------- #include<stdio.h> int main(void) { char ss[10]="AB"; printf("ss=%s\n",ss); return 0; } ------------------------------------ ◎2-------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss[0]='A'; ss[1]='B'; ss[2]=0; printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎3------------------------------- #include<stdio.h> #include<string.h> int main(void) { char ss[10]; strcpy(ss,"AB"); printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎4------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss="AB"; printf("ss=%s\n",ss); return 0; } ---------------------------------- 以上4つのプログラムで、◎2と◎3は正常に動くと理解できたのですが、何故、◎1は正常に動き、◎4は「'const char [3]' から 'char [10]' に変換できません。」といったようなエラーが出てしまうか分かりません。 教えていただければ嬉しいです。

  • 配列やポインタに文字列を設定することについて

    ◎1------------------------- #include<stdio.h> int main(void) { char ss[80]; scanf("%s",ss); printf("%s\n",ss); return 0; } ---------------------------- ◎2--------------------------- #include<stdio.h> int main(void) { char *ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- ◎3---------------------- #include<stdio.h> int main(void) { char *ss; ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- 以上3つプログラムで疑問をいだいたのですが、 まず◎1で、これは例えば、 cahr ss[80]="abc"; のように配列ssに文字列"abc"そのものを入れているのか、 char *ss="xyz"; のようにまず"xyz"という文字列をメモリ上のどこかに設定し、その先頭番地をssに代入しているのか、どちらの考えでいいのかわかりません。 次に、◎2、3ではどちらも正常に実行できたのですが、特に◎3で「ss="abcde";」と記述していますが、ssにはアドレスを代入するという認識かあるのですが、文字列定数を代入しても問題ないのか?という疑問があります。 教えていただけたら嬉しいです。

  • ポインタについて

    今初めてポインタというものを勉強しております。 よろしくお願いします。 ◎1---------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt; pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } --------------------------------------- ◎1のようにmydtのアドレスをポインタptに代入すれば、このプログラムは正常に動きました。 ◎2----------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } ---------------------------------------- ◎2で「int *pt=&mydt;」があまりどういう意味かはわかりませんが、これも正常に動きました。 ◎3------------------------------------ #include<stdio.h> int main(void) { int mydt=1234; int *pt; *pt=&mydt printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } -------------------------------------- ◎3のように◎2と違って「*pt=&mydt」の代入を後から行うと、「'=' : 'int *__w64 ' から 'int' に変換できません。」といったようなエラーが起きてしまいます。 ◎1と◎2の違い、後何故◎3はダメなのかがわかりません。 教えていただけると嬉しいです。 後補足として、配列とポインタについてですが、 ◎4------------------------------ char ss[10]="ABCDE"; char *ssp=ss; --------------------------------- ◎5---------------------------- char ss[10]="ABCDE"; char *ssp; ssp=ss; -------------------------------- ◎4と◎5も同じような事だとは思いますが違いを教えていただけると嬉しいです。 よろしくお願いします。

  • ポインタ

    #include<stdio.h> int main() { char *p; p="ポインタ"; printf(p); return 0; } なぜ p="ポインタ"; とできるのですか? 普通は  int *i, j; i=&j; *i=100; こんな感じでやるのでは?

  • ポインタについて(初心者です)

    おはようございます。「独習C」を使って独学している者です。わかったような、わからないような、そんな感じでポインタの所まできたのですが、文字列定数とポインタのところで分からないところがあります。 #include <stdio.h> int main(void) { char *p; p = "ひとつ ふたつ みっつ"; printf(p); return 0; } #include <stdio.h> int main(void) { char *p; printf("文字列を入力して下さい:"); gets(p); return 0; } 上のような二つのプログラムが出てきたのですが、下の方はメモリが設定されていないので正しくないと書かれていました。しかし上のプログラムでもメモリは設定されていないように思うのですが違うのでしょうか?メモリを設定するというのは、 char ch; p = &ch; ということだと思うのですが、上のプログラムではこのような文が無くても正常に動きます。この二つのプログラムは何か違いがあるのでしょうか?そもそも根本的に考え方が間違っているのでしょうか?なにぶん初心者な者で見当違いの質問だったら申し訳有りません。よろしくお願いします。

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • ポインタ配列のアドレスについて

    #include <stdio.h> int main() { int i; char *ary[] = { "a" , "b" , "c" }; for(i=0; i<3; i++) printf("%u\n" , &ary[i]); return 0; } /*実行結果 6618616 6618620 6618624 */ 上記のプログラムを実行したときポインタ配列*aryがchar型だろうがdouble型だろうがアドレスが4つとびになるのですがなぜなんでしょう?アドレスを求めるプログラム自体が間違っているのでしょうか?

  • 配列要素内の数値

    #include <stdio.h> int main(void) { int arr[1]={123456789}; int *x[1]; *x = arr; printf("%d ",*(x[0])); /* 123456789 と表示*/ return 0;} 実行すると123456789と表示されるまでは分かるのですが、*(x[0])の部分を別の書き方にして、arr[0]に入ってある「123456789」という数値の千の値である6という数値のみを取り出して、表示することは可能なのでしょうか?(6000と取り出したいのではなく、6として取り出したい) 次のように数値を文字列の一つ一つを扱うかのように、扱いたいのです。*(x[0])の部分の変更だけで6を取り出せるような方法はありますか? #include <stdio.h> int main(void) { char *arr[]={"pen"}; printf("%c\n",*(arr[0]+0)); printf("%c\n",*(arr[0]+1)); printf("%c\n",*(arr[0]+2)); return 0;}

  • ポインタ配列

    配列をポインタでとって、配列要素を足していこうと思ったのですが、 #include <stdio.h> int main (void) { int p[11]={11,23,43,66,54,67,51,88,22,43,-1}; int *e=p; int x=0; int i=0; while( *e!=-1 ) { x + = ( * (e+i) ); i++; } printf("%d\n",x); return 0; } x = ( * ( e+i ) ); ↑この部分がなぜだめなのか理解できません どなたか教えてくださるとありがたいです

  • 配列とポインタについて

    #include <stdio.h> int main() { char x[3]; char *y; x[0]='a'; x[1]='b'; x[2]='\0'; y="abc"; printf("xの値は%s\n",x); printf("yの値は%s\n",y); } 通常の配列宣言では、このままだと文字列をまとめて 代入できないのに対して、ポインタ変数ならまとめて代入することができるのは何故ですか?そういう仕組みだと言われてしまえば、それまでなんですが・・・

専門家に質問してみよう