• ベストアンサー

for(s=p; *p; p++)の*p(ポインタ)の意味

for(s=p; *p; p++)の*p(ポインタ)の意味 C言語初心者です。 今ポインタを勉強しているのですが、 for文で上記のようなものが出てきて、意味が分からず困っています。 *pで*p != NULL と同じような意味になるみたいなのですが…。 どうしてそのような意味になるのでしょうか? ちなみにsとpはポインタで、 sには配列(入力した文字列)の先頭アドレスが入っています。 pは文字列を指していて○○○○○NULL ←になるから上記のような条件で 回るんだろうなぁとはなんとなく考えているのですが。

  • upas
  • お礼率89% (239/266)

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

念のため: ヌルポインタは「ビットパターンとして」0 じゃないかもしれませんが, ソースプログラムにおいて「ポインタが要求される場面」で「0」とあれば, それは「ヌルポインタ」です. もうちょっと厳密に書くと「整定数 0」はヌルポインタに変換される.

その他の回答 (3)

回答No.3

まず、char *p に対して、for(s = p; *p; p++) に現れる、*p の型は(ポインタではなく)char そのものです。 ですから、*p は、「p がポイントしているところにある char のデータ」です。 一方、Cでは、文字列は、「'\0' で終端される」という規定になっています。 ですから、ちょっとくどく書けば、 for(s = p; *p != '\0' ; p++) ということで、「p がポイントする文字が、終端文字(文字列の終わり)にくるまで」という意味です。 そして、(Cのいろいろな背景から) *P != '\0' という表記は、 *P とだけ書いた時と同じ動作をします。 このため、文字列の終端をチェックするために、while(*p) とか、if(! *P) (こっちは、終端にきたときの判断)とかよく使われる表現です。 なお、NULL は、「何もポイントしていないポインタ」の値です。 そして、ちょっと面倒なのが、規格上は、「ヌルポインタ(何もポイントしていないポインタ)の値は、定数0と比較したときに等しくなる」と定義されている点です。 つまり、直接、「ヌルポインタはゼロである」という保証はありません。ただし、0と比較したときに等しくなるということは保証されています。そういうわけで、NULLは、定数ゼロを、ポインタにキャストした物が使われます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

#1 にちょっと補足: C では, 条件は全て「値が『0』のとき偽, 『0』でないとき真」と決まっています. ですから, 条件に「*p」とだけ書かれていたら, これは「*p != 0」と同じことになります. なお, NULL はポインタなので, 今の場合「*p != NULL」はおかしいです.

回答No.1

*pはforステートメントの条件式の部分に相当します。 条件式は、その式が「真」か「偽」であるかを評価し、処理を続行するかforステートメントを抜けるかを判断します。 C言語ではポインタ以外の型を持つ値はその型に関わらず真偽を判断する事が言語の仕様上可能であると定められており、値を構成するビットパターンが全て0の場合は「偽」、それ以外は「真」であるとされます。 大抵の処理系ではNULLは「0」とdefineされており、その場合*pの値がNULLになった時に条件式が偽に評価されるのでforステートメントを抜け次の式に処理が移ります。 (但しNULL定数が「0」でなければならないとは言語仕様に定められてません。NULLは元々ポインタに対して代入が可能な値なので、厳密に言えば*pの評価結果の型は値型ではなくポインタ型でなければいけません。質問内容を見る限りpは文字列を示しているので、もしNULLが0以外の値にdefineされていれば正常に動作しないでしょう。定数のNULLと'\0'を誤解しているのかもしれません。)

関連するQ&A

  • ポインタ変数とポインタのポインタ

    ポインタ変数の宣言 char *a[]; をしたとき僕の中では a[0],a[1]...という、ある文字列A,B,C...の最初のアドレスを指すポインタが、配列になっているものを宣言していると理解していました。 しかしこの次に、ポインタのポインタが出てきました。僕はこれを、 ある変数を指し示すアドレスのアドレスである、と理解しました。 この2つは1つめはいくつかのアドレスを指し示すもの、2つ目は1つのアドレスを指し示すものであるとして、僕の中で異なったものであると理解していましたが、参考書「C標準コースウェア」によると プログラムにおいて、関数でポインタ配列を受け取るときchar *p[]はchar **pとしてもよい と書かれており、またその実例として、 (9-5) #include <stdio.h> void disp (char *p[],int n){ int i; for (i= 1;i<n;i++){ printf("%s\n",p[i]); } } int main(void){ char *girl[] = {"Arica","Candy","Lisa"}; disp (girl,sizeof(girl)/sizeof(girl[0])); return 0; } というプログラムが書かれていました。 ここで一気に訳が分からなくなりました。 char *girl[] = {"Arica","Candy","Lisa"}; と宣言されているため、 girl[0]はAricaという文字列の最初のアドレスを指すポインタ、 *girl[0]はAricaという文字列を直接指し示していると解釈しています。 girlは{"Arica","Candy","Lisa"}という文字列の配列の最初のアドレスを指し示していると考えました。 sizeof(girl)を使った時に不思議なのですが、 girlはどのように配列の終わりを理解しているのでしょうか? (配列の要素数を渡していない点が不思議です。) また、 disp側が受け取ったのは*girl[]であり、いくつかのポインタの配列ですが、渡したものはgirlという要素数がないポインタ1つだけです。 そして最初の疑問が出てくるわけですが、*p[]を**pと書きかえてみると、 文字列のアドレスを示すgirlという名の1つのポインタを渡すと、pという名のポインタのポインタで受け取るというのも、よくわからなくなっています。 おそらくポインタ配列に対する理解がどこかでずれているようですが、自分でどこがわからないのかわからなくなっています。 どうかご教授ください。

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

    書物によるとポインタのポインタの使用例として「ポインタの配列」はポインタを使ってアクセスすることができます。」[*]とありますが、どうしてポインタのポインタが必要なのかがいまいちピンと来ません。 どういう場合なのかを知りたく思っています。 [*]サンプルスクリプト ===================================================== 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 *name[] = {"Alice","Ben","Chris","Diana","Elmo"} のようなポインタの配列を宣言・初期化したとき、配列nameの各要素の 中身には、初期化子として与えた、文字列の先頭アドレスが 格納されているという解釈でよろしいのでしょうか?つまり、 *(name+1)やname[1]は、「文字列Benの先頭アドレスを指す」という意 味でよろしいのでしょうか?また、このとき、(name+1)というように *をつけないときは、「文字列Benの先頭アドレスを格納したメモリの 先頭アドレス」というような解釈でよろしいのでしょうか? どうかご教授お願いします。

  • ポインタ

    文字列"apple", "orange", "strawberry"へのポインタをポインタ配列の各要素に代入した後,その文字列の文字を逆順に表示するようにプログラムを考えているのですが、 while文の中のjはそれぞれについて考える必要がありますか? ポインタを使って文字数を数得られそうですが出来ませんでした。 [実行例] ポインタ配列[0]の文字列の逆はelppaです. ポインタ配列[1]の文字列の逆はegnaroです. ポインタ配列[2]の文字列の逆はyrrebwartsです. #include<stdio.h> #define COUNT 3 int main(void) {   char * words[COUNT] = {"apple", "orange", "strawberry"};   int i, j;   for(i = 0; i < COUNT; i++) {    j =  ?  ;    printf("ポインタ配列[%d]の文字列の逆は", i);    while(   ?   ) {     printf("%c", *(words[i] + j));     j--;    }    printf("です.\n");   }   return 0; }

  • NULLポインタは0と書かなければだめ?

    C++言語を使っています。 C++言語でNULLポインタを表す場合、0やNULLを使用しますが、 「NULLは単なるマクロなので本来は0を使わなければだめ」という話を聞きました。 つまり、 int *p = 0; が本当の正しいNULLポインタであり、 int *p = NULL; は推奨されていない(?)NULLポインタというようです。 今まであまり疑うことなく、NULLポインタを表すのにNULLを使用していましたが、 上記の内容は本当でしょうか。

  • 構造体とポインタ配列

    現在C言語の勉強をしております。 環境はwindowsXP、コンパイラはVC6.0です。 構造体と、ポインタの配列についてなのですが、 以下のような構造体が宣言されている時に、リスト構造にデータがいくつか入っているとします。 // 構造体 typedef struct address { unsigned char names[NAME_SIZE+1]; /* 名前 */ char tels[TEL_SIZE + 1]; /* 電話番号 */ struct address *prev; /* 前へのポインタ */ struct address *next; /* 次へのポインタ */ }Address, *a_pt; そのリスト構造を先頭要素か順番にポインタ配列に格納するには以下の方法ではおかしいでしょうか? /* ポインタ配列を用意する */ Address *array[MAX_COUNT]; /* top_ptは先頭のポインタです */ pt = top_pt; /* データがなくなるまで配列へ格納する */ while(pt != NULL){ array[count++] = pt; pt = pt->next; } /* 配列の最後はNULLとする */ array[count] = NULL; また、配列の中身を確認する方法としては、 printf("配列の中身:%s\n", array[0]->names); では、アドレスが表示されてしまうのかな・・と思ったら、accessViolationで落ちてしまいました・・・。 中身はどうしたらデバッグ出来ますでしょうか? そもそも、以下の2つは何か違いはありますか? Address *ptA[100]; a_pt ptB[100]; 皆さん、どうかよろしくお願いいたします。 理解不能な場合はご指摘ください。

  • ポインタ

    字列2つを入力し,同じ文字列かどうかを判定するプログラム ポインタの操作で文字列の比較を実現する。 (ライブラリ関数 strcmp を仕様しない) 関数の中身が上手に実現出来ません。 文字列を指すポインタ変数 2 つを引数に取り,同じ文字列なら -1 を,異なる場合は先頭から一致した文字数 を返す関数 while(*s = *t != '\0'){ if(s != t){ return -1; } if(s == t){ count++; } {s++;t++;} } return -1; }

  • ポインタのポインタの初期化法

     文字列をポインタを使って扱うとき、例えば、初期化は次のように行えますよね。 #include <stdlib.h> char *s; s = (char *)malloc(1000); (これに続いてscanf("%s", s);など)  これと同様にして、二次元の配列を、ポインタのポインタを使って表したいとき、 char **s; と宣言したものを、malloc()関数を使って初期化することはできるのでしょうか。よろしくお願いします。

  • NULLポインタについて

    NULLポインタはどこのアドレスも指さないポインタのことですよね。 printf("%p\n",&NULL);とすると00000000が 表示されます これはアドレスの0番地を指しているということでしょうか? でもNULLのアドレスが0番地なら、NULLポインタはどこのアドレスも指さないポインタというのと矛盾しますよね? アドレスの0番地とNULLは関係ないのでしょうか? よくわからないので教えてください。

  • C言語 変換指定%sについてです。

    現場での経験もあるPGなのですが、C言語の基礎を復習していたら疑問に思うことが出てきてしまったので、質問させて下さい。 printf関数などに使われる変換指定%sについてですが、 char word[] = "test"; char *pointer; pointer = word; とした場合、pointerの値は文字列wordの先頭アドレスになるので、 printf ("%x", pointer); とすれば、そのアドレス値が表示されるのはとてもよくわかるのですが、 printf ("%s", pointer); とした場合に、"test"と表示されるのがイマイチ納得できないんです。 printf ("%s", *pointer); なら、まだわかるんですけど・・・ 変換指定の%sというものは、 「アドレスを受け取って、受け取ったアドレスにある文字列を\0がくるまで表示する」 というものなのでしょうか? int型のポインタで同じように printf ("%d", pointer); とすると、pointerの値であるアドレスが10進数表示されて、pointerが指している変数の値を表示するには、 printf ("%d", *pointer); としなければならないわけで、そういうことをいろいろ考えていたら、収拾がつかなくなってしまって(^_^;) 「とにかく%sはそういうものなの!!」と丸暗記すれば困るようなことはないのですが、どうにもモヤモヤしっぱなしなので、%sの動きについて詳しくお分かりの方がいらっしゃいましたら、ご教授下さい。 よろしくお願いしますm(__)m

専門家に質問してみよう