• ベストアンサー

配列のポインタに渡す引数

2次元配列に値をつめて、char*[]に渡すための 引数XXXは、どう設定すれば、よいのでしょうか? a(work);で、問題ないのでしょうか? いまいちchar*とchar*[]の違いがよくわかりません。 void main { char work[3][5]; sprintf(work[0], %s, "abc"); sprintf(work[1], %s, "def"); sprintf(work[2], %s, "ghi"); a( XXX );←ここの引数 } int a( char* [] ){ }

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

  • ベストアンサー
回答No.3

 ポインタ変数を char *x と宣言すると、変数 x にアドレス値を保存でき、そのアドレスの記憶場所を char型の変数として使うことができます。その記憶場所は間接参照演算子*を変数名の前につけて *x で参照できます。 char **y と宣言すると、変数 y にアドレス値を保存でき、そのアドレスの記憶場所を char*型(ポインタ型)として使うことができます。 その記憶場所は *y で参照できます。*yで参照される記憶場所にアドレスが保存されていれば、そのアドレスの記憶場所をchar型として使うことができます。char型の記憶場所は **y で参照できます。  ところで、C言語では、仮引数の char* z[] は char** z と同じです。ポインタ変数 z に渡されたアドレスが指している記憶場所 *z は、char* のポインタ値(char型の記憶場所のアドレス)でなければなりません。zを配列として使うのであれば、z[0]の次の記憶場所であるz[1](*(z+1)と同じ)以降にもchar*型のポインタが保存されていなければなりません。関数の実引数はポインタの配列でなければならないことになります。  一方、2次元配列 char w[3][5] の配列名 w の型は、char** とも、char*[]ともおなじではありません。(ポインタの配列ではありません。)この2次元配列を宣言した関数の中では w を1次元配列として使うこともできます。w[0] は &w[0][0]と同じ、w[1] は &w[1][0] すなわち &w[0][0]+5 と同じです。 1次元配列として使った時の w の添字を1増やしたとき、アドレスを5だけ進めるというのは配列の宣言を見ればわかります。  ここで、2次元配列を実引数として関数 int a( char** z ) {} あるいは int a( char* z[] ) {} に渡したいとき、強引にキャストを使って a((char**)w); とすれば文法上のエラーはなくなります。ただし、関数の中でzを配列として使うことはできません。zには char*へのポインタが渡って、z[0]は文字列として使えますが、実引数は配列ではないので、配列要素 z[1] はどこにもありません。 ということで、#1を回答された方が示されたように、ポインタの配列を作ってそれを引数として渡すことになります。  #2の回答ですが、 > char *work[2]ではwork[0]とwork[1]のデータが必ずしも連続するとは限りません。 厳密にいうなら、workはポインタの配列ですから、 work[0]とwork[1]の記憶場所は連続しています。work[0]の値をたどって参照される文字列と、work[1]の値をたどって参照される文字列とは記憶場所が連続しているとは限らないということでしょう。

その他の回答 (2)

  • hashioogi
  • ベストアンサー率25% (102/404)
回答No.2

char work [n][m]とchar *work[n]ではデータのメモリ上での配置が違う場合があります。 例えば、char work[2][3] = {{'A','B','C'},{'D','E','F'}} ;はメモリ上では'A'から'F'の値が連続して並んでいますが、char *work[2]ではwork[0]とwork[1]のデータが必ずしも連続するとは限りません。 ですから、データがchar work[3][5]となっているなら、関数aの形式はint a (char w[3][5]) ;としないと、うまく渡せません。どうしても関数aの形式を変更できないなら、No.1氏のようにするしかありません。

回答No.1

#include <stdio.h> void a( char* args[] ){ printf("%s:%s:%s\n", args[0], args[1], args[2]); } int main() { char work[3][5]; char* args[3]; sprintf(work[0], "%s", "abc"); sprintf(work[1], "%s", "def"); sprintf(work[2], "%s", "ghi"); args[0] = work[0]; args[1] = work[1]; args[2] = work[2]; a( args ); return 0; }

関連するQ&A

  • C言語のポインタと配列

    どうにも理解しようとしていますが全体像が理解できないので、わかっていることわからないことまとめていくのでバンバン指摘してくださるとうれしいです。 1.配列の宣言には int a[]; a[] = {1,2,3}ですが、コンピュータは{"1","2","3"}の部分の数を数えて[]に代入しているので、 int [][3] = {{1,2,3},{4,5,6}}のような配列を作ったとき[][3]の部分の左側の数字も勝手に代入している。 この時なぜ3が勝手に代入されないかがわからない 2.数字とメモリ int s = {1,2,3}をメモリ的に表現すると、123の順に並んでいる。s[1]=2 int s[][2] = {{1,2,3},{4,5,6}}をメモリ的に表現すると123456に並んでいる。s[1][1]= 5 ここまで文字列以外の配列は添え字だけで管理されている。 3.文字列とポインタ char s[] = "abc"とするとメモリ的にはabc\0であり、[]には4が代入され、s[1]はb自身を指す。 char *s = "abc"をメモリで表すとabc\0であり、\0が来るまでを文字列と認識する。 sは&s[0]とも表現できるように、最初のアドレスを指し示している。 char *s[]= {"abc","def"}をメモリ的に表現するとabc\0def\0であり、[]には2がコンピュータにより判断されて代入される。\0までを文字列として表現しようとする。s [1] は"def"の最初のアドレスを指し示すが、s[1][1]とするとe自身を指すようになる。この時、s[1] = &s[1][0]と表現することは可能であると考えられる。 文字列を直接さす場合でも、ポインタで表現する場合でも、\0が要素の最後に来るのでしょうか? また、{{"abc","def"},{"ghi","jkl"}}を文字列で直接表す場合は char s[2][2] = {{"abc","def"},{"ghi","jkl"}}; となるかと思いますが char *s[2][2] = {{"abc","def"},{"ghi","jkl"}}; とするとs[1][1]でghiの最初のアドレスを、s[1][1][0]でg自身を表せるようになるのでしょうか?

  • 関数に配列を渡して値を変える

    関数に配列を渡して値を書き換えたいのですが、文字配列である char b[10]="abc"; の書き換えが綺麗にできません。 どのように書いたら綺麗にできますか? void hen(int *a, char *b,char **c){ *a=7; b[0]='d'; b[1]='e'; b[2]='f'; //こういう書き方なら渡せるけれどb[10]="def"; 見たいな書き方で一行で値を渡す方法はないものかな? *c="jkl"; } void main (void){ int a=5; char b[10]="abc"; char *c="ghi"; hen(&a,b,&c); printf("%d %s %s\n",a,b,c); }

  • 2次元配列とポインタの引数受け渡しについて

    2次元配列を関数に渡すときは、引数に渡す2次元配列と同じサイズを指定、もしくは2次元目のサイズのみ合わせて渡す方法がありますが、両方とも違うサイズで同じ関数を使いたいです。 最初は中身が同じで引数で受け取る2次元配列のサイズだけ、それぞれに合わせた引数を持つ関数を2つ作っていたのですが、なんだか冗長な気がしました。 そこで、2次元配列の先頭ポインタとサイズを受け取るようにすればいいのかと思い、テストとして次のプログラムを作成してみました。 #include <stdio.h> void func(unsigned char *a, int y, int x); int main(void) { unsigned char a[10][10]; func(a, 10, 10); printf("%d\n", a[7][4]); return 0; } void func(unsigned char *a, int y, int x) { int i, j; for (i = 0; i < y; i++) { for (j = 0; j < x; j++) { *(a + i*y + j) = i * j; } } } もちろんこれでも動くのですが、やはりこういう書き方はルールにはないので、コンパイルで警告が出ます。 a.c: In function ‘main’: a.c:10: warning: passing argument 1 of ‘func’ from incompatible pointer type a.c:4: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[10]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • ポインタ配列について

    /************配列 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"; は何故実行されないのですか?

  • D言語の連想配列

    D言語で以下のプログラムが動いてくれません。 なにがおかしいのでしょうか。 int main(char[][] args) { int[char[]] a; a["abc"]=1; a["def"]=2; a["ghi"]=3; char[][] x=a.keys; for(int i=0;i<x.length;i++) printf("%s\n",x[i]); return 0; } 実行結果 Error: Access Violation

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

    以下のような matrixの二次元配列の引数があるのですが、これを keisan2に渡す時にどのように記述すれば良いのでしょうか? ???部分が知りたいです。 また、char **matrixと matrix[][3]は違うものですか? 覚えるコツも知りたいです。 int keisan(int data, char matrix[][3]) { // 省略 return keisan2(dat, ???); } int keisan2(int data, char matrix[][3]) { // 省略 return 0; }

  • 引数に二重配列のある関数について

    void calc(int *a,int b,int c){ a[0]=b+c; a[1]=b-c; } void main(void){ int x[2]; int y=2,z=5; calc(x,y,z); printf("x[0]=%d,x[1]=%d\n",x[0],x[1]); } 上のように引数が普通の配列の関数ならできるのですが, 引数が下のような多重配列になるとエラーが出てしまいできません。 void keisan(int **a,int b,int c){ a[0][0]=b+c; a[0][1]=b-c; a[1][0]=b*c; a[1][1]=b/c; } void main(void){ int x[2][2]; keisan(x,6,2); printf("x[0][0]=%d,x[0][1]=%d\n",x[0][0],x[0][1]); printf("x[1][0]=%d,x[1][1]=%d\n",x[1][0],x[1][1]); } 引数に多重配列を使った場合の関数の作り方について教えてください. お願いいたします.

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

    #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); } 通常の配列宣言では、このままだと文字列をまとめて 代入できないのに対して、ポインタ変数ならまとめて代入することができるのは何故ですか?そういう仕組みだと言われてしまえば、それまでなんですが・・・

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

    ◎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にはアドレスを代入するという認識かあるのですが、文字列定数を代入しても問題ないのか?という疑問があります。 教えていただけたら嬉しいです。

  • ポインタ配列

    "one","two","three","four","five","six","seven","eight","nine","ten" のポインタ配列の文字列を、ASCIIコード順に並べ変えようと思ったのですが、 もうどこが間違っているかさえわからないぐらいになってしまいました。 まだまだはじめたばかりなもので、わからないことだらけなんで、 できるだけわかりやすい説明おねがいします。 関数の引数に問題があるのじゃないかと思ったのですが、 何かいいアドバイスありましたら、お願いします。 #include <stdio.h> /* 関数のプロトタイプ宣言 */ int strmp(char *,char *); void cpy(char *,char *); int main (void) { /* ポインタ配列の定義 */ char *x[10]={"oneee","twooo","three","fourr","fivee","sixxx","seven","eight","ninee","tennn"}; /* ポインタのポインタの定義 */ char **pp=x; char k[100]; char *p=k; int i,t,a,b,c,d; a=0; /* ポインタ配列を自作関数を使って、ASCIIコードの大きいほうからに並び替える */ for(i=0;i<9;i++) { for(t=1;t<10;t++) { a=strmp(*(pp+i),*(pp+t)); if(a<0) { cpy(p,*(pp+i) ); cpy(*(pp+i),*(pp+t) ); cpy(*(pp+t),p); } } } for(i=0;i<10;i++) { printf("%s ,",x[i]); } printf("\n"); return 0; } /* 文字の比較をする関数 */ int strmp(char *x,char *y) { int i; for(i=0;*(x+i)==*(y+i);i++) { if( *(x+i)=='\0') { return 0; } } return *(x+i)-*(y+i); } /* 文字をコピーする関数 */ void cpy(char *a,char *b) { int i; for(i=0;*(b+i)!='\0';i++) { *(a+i)=*(b+i); } *(a+i)='\0'; }