質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1924閲覧

ポインタを指すポインタ?

reotantan

総合スコア295

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2015/09/04 13:15

char *t=d;の部分なのですが、
d自体がs2配列の先頭アドレスを示すポインタなので、
tはポインタのアドレスを示しているポインタという事ですか?
あとwhile(*d++ =*s++)
;というのは
()の式を評価して1になる間は()の
中の命令を続けるという事ですよね?
詳しいかた、教えてください

char *str_copy(char *d,const char *s) { char *t=d; while(*d++ =*s++) ; return(t); } int main (void) { char s1[128]="ABCD"; char s2[128]="EFGH"; printf("s1:" ); scanf("%s",s1 ); str_copy(s2,s1); puts("copied s1 "); printf("s1=%s\n",s1 ); printf("s2=%s\n",s2 ); return 0; } コード

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

自分はほんの駆け出しですが…

まずは、下記をを復習してみてください。理解の助けになります。
文字列をポインタで操作する方法(こちらを参照)
関数から文字列を返す方法(こちらを参照)

その上で、私なりの説明を試みてみます。

  • 文字列操作関数「str_copy」は、{第一引数}←{第二引数} に文字列をコピーするもの

  • 関数呼び出し時に与えられる「実引数」は文字型配列の名前「s2」「s1」で、文字列の先頭アドレスを示す

  • 関数 str_copy が受け取る「仮引数」は文字列型へのポインタ型

  • 関数が呼び出された直後は、「d」「s」ともに受け取った文字列の先頭アドレスを示す

  • 第二引数は「コピー元」(=変更されることはない)なので、「const」として定義されている

  • 「while(*d++ =*s++) ;」の部分は、下記3種類のことを1行で実施(→補足1)
    ①先頭から1文字ずつ、②文字列の末尾まで、③コピーする

  • 「char *t=d;」はコピー結果を返すための準備(→補足2)

補足1)while文の意味するところ

while( {繰り返し条件} ) ; ← 普通はここに処理したいコマンドのフロック {〜} が来るが、ここでは何もしない

従って、すべての処理は繰り返し条件の部分に記載された「*d++ =*s++」というで実行される訳ですが、以下のように分けて考えると分かりやすいです。

  • ループの1回目では、第二引数の1文字目(*s++)が第一引数の1文字目(*d++)にコピー(=代入)される

  • コピーが完了した時点で各ポインタの値がインクリメント(++)され、次の文字をコピーする「準備」をしている

  • 上記が完了した時点で、{繰り返し条件} の「式全体の評価は、コピーされた「文字コード」(≠0)なので、ループ処理を終えずに2週目を実行する

  • もし処理が進んで文字列の「終端」に到達すると、コピーされる文字コードは「終端記号」(=\0)で式全体の評価はゼロとなり、繰り返し条件が「false」となって処理を終える

補足2)return(t); は実際のところ を返しているのか?
関数「str_copy」の引数は文字型配列(=配列の先頭アドレス)を受け取っている(=参照渡し)ので、文字列のコピー結果は、呼び出し元の文字型配列「s2」に直接反映されます。

しかし、「関数」である以上、関数の戻り値としてもコピー結果を受け取りたいです。
そこで、実際のコピー処理を開始する前に「準備」として char *t=d; としておくと、第一引数(コピー先)である文字型配列「s2」の先頭アドレス(ポインタ)を、文字列型ポインタ変数「t」に保存しておけます。

この変数「t」は通常の文字列型ポインタ変数であって、決してポインタのポインタではありません。
もしポインタのポインタを宣言したい場合は char **t のように * を重ねます。実際には使用されることはありませんが、「((ポインタのポインタ)のポインタ)の…」というように多重間接参照ということも可能です。(参考)

なぜコピー処理のにこんなことをしているか?というと、文字列を1文字ずつコピーする際に、変数「d」の値はインクリメントされていまう(コピー完了後は、もはや文字列の先頭を示していない)からです。

要するに、この関数は、文字列のコピー結果を呼び出し元の「コピー先配列:s2」へ直に反映させると共に、コピー先文字列の先頭アドレスを「関数の戻り値」としても返却しています。

このように、文字列など複数の値を関数の戻り値として返したい場合には、ポインタ型を使用するのが 常套手段 となっています。(参考)
なので、この関数は char *str_copy というように文字列型へのポインタ型として定義されています。

このように文章だけで説明しようとするとどうしても長くてややこしくなってしまうのですが、少しでも理解の助けになれば幸いです。

投稿2015/09/04 17:20

pi-chan

総合スコア5936

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

ポインタのポインタだったら
char**です。

質問文のコードは

char str[]="ABC"; char* d; char* t; t = d; ...

こんな感じです


C言語は真偽を「0だったら偽、それ以外は正」とします。
while(*d++=*s++)
dにsを代入して代入した値が0じゃなければまた繰り返す。
で、後置インクリメントつきなので操作の後にdとsをchar1つ分進める処理も入ってます。

「"ABC"のどこに0があるんだよ」と思うかもしれませんが、
"ABC"というのは{'A' , 'B' , 'C' , 0}と同等です。

投稿2015/09/04 13:43

ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/09/04 15:23

そういう事ですか、ただchar型を入れられるポインタとして宣言しただけだったんですね。 ありがとうございます
guest

0

おそらく、このstr_cpy()関数の仕様として、戻り値の値はコピー先の先頭アドレスを返すという仕様なのでしょう。そのため、dの値を退避しています。
#tは処理されず、戻り値としてしか使用されていませんよね。
アドレスを扱うため、ポインタ変数として宣言する必要があります。

whileループですが、考え方はその通りです。sの内容を一字ずつdへコピーするためのループです。
で、終了条件ですが、文字列なので、最後はNULL文字になります。NULL文字は文字コードが0のデータであるため、NULL文字をコピーしたと同時にループ条件が終了(0なので、条件が「偽」となり、ループを抜ける)となります。

投稿2015/09/04 13:31

archiver

総合スコア1557

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/09/04 15:23

解説ありがとうございます、とても理解に役立ちました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問