• 締切済み

charのポインタについて

同じような質問ばっかりたて続けにしてしまってすみません・・ あの,以下のような例の時↓ ------ { char array[7]; char *ptr; strcpy(array, "abcdef"); ptr = &(array[0]); printf(" array = %s\n ptr = %s\n", array, ptr); } ------ これを実行したら、 array = abcdef ptr = abcdef となりますが、ポインタとして宣言してるptrから文字列を得たい時は *ptr と書くんではないのでしょうか? %s のように出力形式のところを指定をするだけで 文字列で表示してくれるのはなぜですか? 上の例のように書くのが正しいのでしょうか

みんなの回答

  • tatimi
  • ベストアンサー率34% (19/55)
回答No.6

%dや%xは、引数の値を表示する機能です。 %sは引数の値をアドレスとみなして、その先にあるメモリーを 0x00が現れるまで文字列として表示する機能です。 char *ptr;という定義があって、実行文中で*ptrと書くと 「ptrのさすメモリー」の中にあるデーターの値を意味します。 このとき、型定義にしたがって最終的な値はcharとして扱われます。 ただ単にptrと書くと、変数の型定義にしたがってchar *の意味、 つまり「「charの入っているメモリー」のアドレス」の意味になります。 printf("%s",*ptr);の意味は、 printf("引数をアドレスとみなしその先のメモリーを表示する",   「ptrのさすメモリーの中のデーター」をアドレスとして使う); printf("%s",ptr);の意味は printf("引数をアドレスとみなしその先のメモリーを表示する",   ptrそのもの(←つまり"abcdef"の入っているメモリーのアドレス) ); ちょっと難しいですが、仕様にたちかえって説明してみました。 最初はこんがらがりますが、がんばってください。

yuki7505
質問者

お礼

すごく頭がこんがらまってます。はあ。。むずかしいですね・・。もっと勉強します。

  • k-ji
  • ベストアンサー率57% (11/19)
回答No.5

printf(" array = %s\n ptr = %s\n", array, ptr); を良く見て下さい。 array は何と等価でしょうか? 配列を配列名だけで書いたときは、その値は配列の先頭アドレスをさします。 つまり、arrey は &arrey[0] とは同じアドレス(つまり同じ値です)を差し ています。 また printf のフォーマット部分で %s は他の方も書かれているように、 「ポインタの指し示すアドレスから\0 が見つかるまでを文字列として表示する。」 というprintf への指示です。 そのため、yuki7505 さんの書いたプログラムは、yuki7505 さんの書かれたような 結果が返ってきたのです。 また、*ptr とした場合は arrey 配列の先頭の文字 "a" の値が得られます。 これは、char *型の変数は はコンパイラから見てchar 配列のポインタなのか char 変数のポインタなのかはまったく区別つかないし、区別してはいけない ものだからです。そうしないと、配列用のポインタ、1文字変数用のポインタ・・・ ととんでもない数の型を言語仕様で作らなければならなくなります。 それで、*ptr と書いた場合は char 型の値が帰ってくるのです。では *ptr が差すものが、配列だったらどうするの?と言われると、 「それはプログラマがそれを配列として扱い処理する。」 と言うことになります。 ということでたぶん、yuki7505 さんは、 printf("arrey = %s\n ptr = %08x\n",arrey,ptr); として、文字列とそのアドレスを表示されることを期待していたのではと思い ますがどうでしょうか?

yuki7505
質問者

お礼

そう期待してたんですが違うんですね。もっともっと勉強します。ありがとうございました。

  • bluesky
  • ベストアンサー率33% (3/9)
回答No.4

C言語を勉強している人が陥りやすいワナにかかりましたね C言語というものはシンプルですからもっと客観的に考える必要があります それぞれの変数にどんな値が入っているかを良く考えながらもう一度トレース してみてはいかがでしょうか ちなみにこのプログラムでは ptr = &(array[0]); の処理の結果 ptr == array となります ( ただし array は変数ではないですが 代入できない char * 変数と考えればOKです ) ですからこの行の処理は ptr = array; とやっていることはまったく同じです この行に置き換えてこのプログラムを見直してみてください ・・・いかがでしょう、少しはわかりやすくなったのでは・・・?

yuki7505
質問者

お礼

ありがとうございます。色々試してみます。

  • selenity
  • ベストアンサー率41% (324/772)
回答No.3

失礼ですが、もう一度C言語の教科書を 読み直しましょう。 まず、ポインタの前に文字型以外の配列の勉強を して正しい理解をしてください。 (「文字列」はちょっと特殊なので、、、) 「*ptr」の「*」は「ptr」が参照する先のアドレス の中身(特定の1バイト)を参照するための演算子です。 ですから、*(ptr+1)とすれば「b」を指します。 printf(" array = %s\n ptr = %s\n", array+1, ptr+1); とすれば、 array = bcdef ptr = bcdef と表示されます。 array自身はアドレスを指していますので 「array+1」で「array」から「sizeof(char)*1」分 だけアドレスがインクリメントされるため 「*(array+1)」は「array[1]」と等価となり、「array+1」は「&array[1]」と等価となります。 「%s」書式指定子には参照先のアドレスを指定します。 「%s」書式指定子は指示されたアドレスから開始 され、「\0(null文字)」までのバイト列を単純に 表示するだけの機能です。 「ptr+1」も同様で「ptr」の参照先は「&array[0]」 なので「ptr+1」で「&array[1]」と等価となります。

yuki7505
質問者

お礼

ありがとうございます。

noname#25358
noname#25358
回答No.2

 %s は、指定された変数をポインタとして見るからです。

yuki7505
質問者

お礼

ありがとうございます。

  • madman
  • ベストアンサー率24% (612/2465)
回答No.1

*ptrで宣言した場合は、文字列表示する場合はptrと書くのが正しいのです。 ptrが文字列の先頭ポインタをさします。

yuki7505
質問者

お礼

ありがとうございます。

関連するQ&A

  • C言語のchar ポインタ

    char ポインタで分からないことがあるのですが・・↓ ------ { char array[7]; char *ptr; strcpy(array, "abcdef"); ptr = &(array[0]); printf(" array = %s\n ptr = %s\n", array, ptr); } ------ これを実行して, array = abcdef になるのは分かるのですが ptr = abcdef  になるのはどうしてでしょうか。 ポインタはアドレスを指し示すものですよね。だったら ptr = にはarray[0]のアドレス('a'のアドレス)が入るのでは 無いんでしょうか・・?

  • char型ポインタ

    よくプログラムで charポインタだけ指定して、 #include<stdio.h> int main(){ char* p; p = "abcdef"; printf("%s",p); return 0; } のようにしているのをみかけますが、 メモリーを確保していなくても問題ないのでしょうか? char* p; p = (char*)malloc(7); strcpy(p,"abcdef"); としたのと同じでしょうか?

  • ポインタについて

    #include<stdio.h> int main(void) { char str[10]; char *ptr = str; printf("文字列を入力してください。\n"); scanf("%s",ptr); printf("文字列は%sです。",str); return 0; } 上記のプログラムのscanf("%s",ptr);の ptrに&をつけるとなぜ先頭の4文字は入力しても 表示されなくなってしまうのでしょうか? よろしくお願いします。

  • 文字列を表すための配列とポインタ

    文字列を表すための配列とポインタ  配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、Visual Studio 2010 コマンドプロンプトです。 #include <stdio.h> void main(void) { char a[256]; char *b; printf("文字列を入力してください。\n"); printf("例「abcde」\n\n"); printf("配列型文字列を使います。\n"); scanf("%s", a); printf("文字列は%sです。\n\n", a); printf("ポインタ型文字列を使います。\n"); scanf("%s", b); printf("文字列は%sです。\n", b); }  すると、まずコンパイル時に、 「warning C4700: 初期化されていないローカル変数'b'が使用されます」 と表示されました。そして、実行すると、「配列型文字列」の方は問題ないのですが、「ポインタ型文字列」の方の実行後に、 「x.exeは動作を停止しました。 問題が発生したため、プログラムが正しく動作しなくなりま した。プログラムは閉じられ、解決策がある場合は Windowsから通知されます。」 と表示され、エラーとして終了してしまいます。 「char *b;」 と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。

  • [C]char型のダブルポインタ

    粗雑で申し訳ありませんが、 以下のソースをコンパイルできましたが、 うまく実行できません。 自分なりに間違いがないと思うのですが、 間違い等をご指摘頂ければ助かります。 #include <stdio.h> void func(char **ptr) ptr[][10] か (*ptr)[] なら通る *ptr[] は通らない { printf("----- func -----"); printf("%s\n", *ptr); printf("%c\n", **ptr); putchar('\n'); } int main(void) { char str[5][10] = {"AAAAA", *str[] にすると func で **ptr で通る "BBBBB", "CCCCC", "DDDDD", "EEEEE", }; printf("----- main -----"); printf("%s\n", *str); printf("%c\n", **str); putchar('\n'); func(str); return (0); } 実行結果 ----- main ----- AAAAA A ----- func ----- Bus error (core dump) 関数への受け渡しで、型が違うというお叱りを受けますが、 コンパイルはできました。 コンパイラはCCです。 ではよろしくお願いします。

  • ポインタのポインタの必要性

    書物によるとポインタのポインタの使用例として「ポインタの配列」はポインタを使ってアクセスすることができます。」[*]とありますが、どうしてポインタのポインタが必要なのかがいまいちピンと来ません。 どういう場合なのかを知りたく思っています。 [*]サンプルスクリプト ===================================================== char *mnthp[3] = {/* ポインタの配列の宣言 */ "January", "February", "March" }; char **p1;/* 「ポインタのポインタ」の宣言 */ int i, j; p1=mnthp;/* 「ポインタのポインタ」にポインタの配列 */ /* の先頭番地を設定 */ /***** 例1 *****/ for (i = 0; i < 3; i++) {/* 「ポインタのポインタ」の値を変えずに */ printf("%s\n", *(p1 + i));/* 相対的に文字列を出力 */ } ==> このようなことをしなくとも printf("%s", mnthp[i]); で値を参照出来ると思われる。 ===================================================== [*] http://www9.plala.or.jp/sgwr-t/c/sec10-4.html 宜しくお願い致します。

  • CHAR型ポインタについて。

    CHAR型ポインタについて。 当方C言語初心者です。 ポインタと文字列の関係分からないことが出てきました。 参考にしている本があり、そのページに下記のソースで「const char *pc1」のポインタ変数を用意して、そこに直接文字列を代入しています。 本来、「char *pc1」はchar型のアドレスを格納するための変数のはずなのに、その変数に文字列を代入してることに疑問を感じました。 この記述の仕方は間違っていないのでしょうか?また、アドレスを格納するための変数「*pc1」に「abcdefg」の文字列はどのようにメモリ上で格納されているのでしょうか? 知ってどうなるの?みたいな質問かもしれませんが、ご教授いただけると幸いです。 #include <stdlib.h> #include <string.h> void func(void) { const char *pc1 = "abcdefg"; //←ココ char *pc2 = (char *)malloc( strlen(pc1) +1); if ( pc2 ) { strcpy( pc2, pc1 ); free( pc2 ); } }

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

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #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() { 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); } 通常の配列宣言では、このままだと文字列をまとめて 代入できないのに対して、ポインタ変数ならまとめて代入することができるのは何故ですか?そういう仕組みだと言われてしまえば、それまでなんですが・・・

  • ポインタを用いた文字列操作について…。

    C初心者です。 「ある文字列を読み込んだ後、その文字列中にある文字(複数)を指定する。指定した文字を最初の文字列から消す」という関数を作りたいのですが、うまくいきません。 例を挙げると、 文字列 :OshieteGoo 指定文字:to 文字列改:OshitG のような感じにしたいです。 #define NULLC '\0' void strCpy(char *ptr1, char *ptr2, char *cMain) { char *cSub = cMain; /* ポインタバックアップ */ for(;*ptr1!=NULLC;ptr1++){ for(cSub=cMain;*cSub!=NULLC;*cSub++){ if(*ptr1!=*cSub){ *ptr2 = *ptr1; ptr2++; } break; } } *ptr2 = NULLC; return; } 自分なりにこう考えてみたのですが、これを実行すると 文字列 :OshieteGoo 指定文字:to 文字列改:OshitGoo となり、指定文字の2文字目以降がうまく削除できません…。 この問題を解決できるお知恵を拝借させて頂けると幸いです^^;