1

文字列を逆にするコードがあります。「ABC」と入力すると、出力は「CBA」になります。ただし、まったく理解できないコード行がいくつかあります。

1    #include <stdio.h>
2    #include <string.h>
3
4    void print_reverse(char *s) {
5   size_t len = strlen(s);
6
7   char *t = s + len-1;
8   while(t >= s) {
9       printf("%c", *t);
10      t = t-1;
11  }
12  puts("");
13  }
14
15    int main()
16    {
17  char charinput[100];
18  printf("Enter character you want to reverse:");
19  fgets(charinput, 100, stdin);
20  print_reverse(charinput);
21  getchar();
22    }

7 行目と 8 行目は何をしますか? ポインター t の出力はどうなるでしょうか?

4

6 に答える 6

8

投稿されたコードは、次のアルゴリズムを使用します。

  • 行 7 : 文字列の最後の文字へのポインターを設定しtます (注: ユーザーが 99 文字未満の文字列を入力した場合は改行文字になります)。-1は、終端の nil-char から 1 文字戻すことです。
  • 行 8 ~ 10 : これは反転レポート ループのコアです。ポインタtは、文字列の先頭にあるアドレスに対して繰り返しテストされます。t条件句は、値 (アドレス) が文字列の開始アドレス以上かどうかを確認します。である限り、ループ本体に入り、 に保持されているアドレスに現在存在する文字がt経由で stdout に送信されprintf()ます。のアドレスtは 1 種類の幅 (1 バイトのほとんどすべてのシステムでは 1 バイトchar) だけ減分され、ループが繰り返されます。前にtアドレスが含まれている場合にのみ、ループが中断されます (注: これは標準の範囲内ではありません。理由については以下を参照してください)。 s

このループについて知っておくべきことがあります (作成者でない場合は、作成者に指摘する必要があります)。最終的なポインター比較は標準に準拠していません。標準では、null 以外の like-type ポインター間の比較は、有効なシーケンスのベース アドレス (charinputこのコードでは、 によってパラメーター化されたアドレス) から、割り当てられたメモリ領域を超えるs1 つの型要素まで有効であると指定されています。tこのコードはと比較され、が「少ない」s場合にのみループが中断されます。しかし、が s より小さいtとすぐに、その値は に対して合法的に範囲比較できなくなります。標準によれば、これは、tstcharinputcharinputメモリ ブロックのサイズを 1 回通過します。

これを正しく行う 1 つの方法は次のとおりです。

t = s + len;
while (t-- > s)
    printf("%c", *t);

編集: Paul Hankin から提案された後の標準への旅の後、以前のコードは見過ごされた UB 状態を説明するために書き直されました。更新されたコードは次のとおりです。

t = s + len;
while (t != s)
    printf("%c", *--t);

これは、長さゼロの文字列でも機能します。仕組みは次のとおりです。

  • t文字列の終端のヌル文字のアドレスに設定されます。
  • tループに入ります。のアドレスが のベース アドレスと等しくない限り、この状態が続きますs
    • をデクリメントtし、結果のアドレスを逆参照して現在の文字を取得し、結果を に送信しprintfます。
    • 次の反復のためにループします。
于 2013-10-12T09:45:02.840 に答える
3

それを段階的に理解しましょう:

  1. len = strlen(s)バイト単位s指す文字列のサイズをに割り当てます(これが10であるとします)。 lenlen

  2. s 文字列の最初の文字を指しています。100この文字列の最初の要素のアドレスがで、次にsが含まれていると仮定しましょう100

  3. に追加len-1するsと が得られ109ます。

さて、7号線

   char *t = s + len-1;

address の要素、つまり文字列の最後 tの要素を指していることをコンパイラに伝えます。109

8号線

   while(t >= s) {

文字列の最初の要素の前の何かをt指すまでループが続くことをコンパイラに伝えます。

于 2013-10-12T09:43:10.510 に答える
1

7 行目: ポインターtは最後の文字を指してい(s+len-1)ます。
8 行目: t のアドレスが s のアドレス以上の場合、ステップを繰り返します。最初の入力文字列のアドレスを指す s が 1101 の場合、次の文字のアドレスは 1101+1=1102、3 番目の文字は 1102+1=1103 などとなります。入力が10文字の長さの場合、1101 + len-17行目を指します。 9 行目: で指定されたアドレスで保持されている文字を出力します。10 行目: 1 減分され、すぐ左の文字をポイントします。 アドレスが大きいか等しい間、9 と 10 が繰り返されます (私の図では 1110)。1101+10-1 (1110)
tt

于 2013-10-12T09:45:42.690 に答える
0

char *t = s + len-1; : 文字列 s の最後の文字を指す : 文字列 s の while(t >= s) すべての文字を逆の順序でスキャンする (s最初の文字をt指し、 で最後の文字を指すようにしたline 7)。

お役に立てれば。

于 2013-10-12T09:31:55.290 に答える