0

先生から出された問題を解いていて、ちょっとひっかかりました。次のコードの出力を与えることになっています:(Turbo C++ で書かれています)

#include<iostream.h>
void main()
{
    char *p = "School";
    char c;
    c=++(*(p++));
    cout<<c<<","<<p<<endl;
    cout<<p<<","<<++(*(p--))<<","<<++(*(p++))<<endl;

}

プログラムの出力は次のとおりです。

T,chool
ijool,j,i

ポインター自体がインクリメントしてから、ポインターが指す値をインクリメントする部分を取得しました。しかし、文字列がijoolを出力する部分がわかりません

誰かが私を助けることができますか?

4

5 に答える 5

5

あなたが示したプログラムは非標準であり、形式が正しくありません (コンパイルするべきではありません)。

「小さな」問題:

  • C++ の入出力ストリームの適切なヘッダーは<iostream>であり、<iostream.h>
  • main()intではなく を返しますvoid
  • coutファイルの先頭にaなしでendl使用することはできません。using namespace std;std::coutstd::endl

「コア」の問題:

  • char* p = "School";文字列リテラルへのポインタです。この変換は C++03 で有効で、C++11 では非推奨です。それとは別に、通常、文字列リテラルは読み取り専用であり、それらを変更しようとするとセグメンテーション違反が発生することがよくあります (文字列リテラルの変更は、標準では未定義の動作です)。したがって、を使用するたびに未定義の動作pが発生します。これは、それが指すもの、つまり文字列リテラルを変更するためです。
  • より微妙な(および実際的な説明):p行で数回変更していますstd::cout<<p<<","<<++(*(p--))<<","<<++(*(p++))<<std::endl;。これは未定義の動作です。操作に使用される順序pは定義されていません。ここでは、コンパイラは右から開始するようです。より良い説明のために、シーケンスポイント、前後のシーケンスを見ることができます。

ライブ コード hereに興味があるかもしれません。これは、プログラムに期待しているように見えたものに似ています。

于 2013-03-14T17:59:39.677 に答える
4

あなたが正しいと仮定しましょう:

  1. へのヘッダー-ヘッダー<iostream>はありませんiostream.h
  2. coutendlstd::coutstd::endlそれぞれ使用する
  3. maintoの戻り型int

わかった、

char *p = "School";

文字列リテラル"School"の型は「7 の配列」const charです。への変換char*は C++03 で廃止されました。C++11 では、これは無効です。

c=++(*(p++));

ここで、未定義の動作にヒットします。前に言ったようにchar、文字列リテラルの s はconst. それらを変更することはできません。ここのプレフィックスは、文字列リテラルの文字++を変更しようとします。S

したがって、この時点から、何が起こるかについて推測しても意味がありません。未定義の動作があります。何でも起れる。

于 2013-03-14T17:54:56.310 に答える
3

前の行が有効であったとしても、この行も未定義の動作です。つまり、出力がどうなるかを正確に予測することはできません。

cout<<p<<","<<++(*(p--))<<","<<++(*(p++))<<endl;

その行で複数回の値を変更する方法に注意してくださいp(実際にはシーケンス ポイント間)。それは許可されていません。せいぜい「この実行時ライブラリとこの環境を備えたこのコンパイラで、実行の瞬間に次の動作を観察しました」と言うことができますが、これは未定義の動作であるため、毎回同じことを行うとは期待できません。プログラムを実行した場合、またはプログラムの同じ実行内で同じコードが複数回発生した場合でも。

于 2013-03-14T18:00:10.663 に答える
1

このコードには少なくとも3つの問題があります(おそらくそれ以上です。私はC ++の専門家ではありません)。

最初の問題は、OSがディスク上のexeファイルに直接マップするプログラムメモリの読み取り専用部分に配置できるため、のような文字列定数を変更しないことです(OSは同じの複数の実行中のインスタンス間でそれらを共有する可能性があります)たとえば、プログラムを実行するか、RAMが少ないときにスワップファイルに書き込む必要のあるメモリの部分を避けてください。これは、exeから元のファイルを取得できることがわかっているためです)。たとえば、この例は私のコンパイラでクラッシュします。文字列を変更するには、 strdupなどを使用して、文字列の変更可能な複製を割り当てる必要があります。

2番目の問題は、それを宣言せずに名前空間を使用していることですcout。アクセスの前に宣言を付けるか、宣言を追加する必要があります。endlstdstd::using namespace std;

3番目の問題は、2行目の操作が発生する順序が未定義の動作であり、1行目の終わりに表示されてから次の行coutに表示されるまでの間に文字列が明らかに不思議に変化することです。cout

このコードは特に何もすることを意図していないため、修正できるさまざまな有効な方法があります。これはおそらく実行されます:

#include <iostream>
#include <string.h>
#include <stdlib.h>

using namespace std;

int main()
{
    char *string = strdup("School");
    char *p = string;
    char c;
    c=++(*(p++));
    cout<<c<<","<<p<<endl;
    cout<<p<<","<<++(*(p--))<<","<<++(*(p++))<<endl;
    free(string);
}

(私のコンパイラでは、これは次のように出力します:T,chooldiool,i,d。)

ただし、まだ未定義の動作があります。これを修正するには、2cout行目を次のように作り直します。

cout << p << ",";
cout << ++(*(p--)) << ",";
cout << ++(*(p++)) << endl;

T,choolこれにより、が得られるはずですchool,d,U(AからZまでの文字セットを順番に持つと仮定します)。

于 2013-03-14T18:09:08.330 に答える
0
  1. p++ は、p の位置を「School」から「chool」に移動します。その前に、++pではなくp++なので、charの値をインクリメントします。今 c = "T" from "S"
  2. p を出力すると、p の残りの部分が出力されます。これは、前に「chool」として識別されました。
  3. 試行錯誤から学ぶのが最善であるため、このコードをデバッガーで実行します。それはあなたを永遠に追う素晴らしいツールです。これは、cout ステートメントの 2 番目のセットに役立ちます。gdb または VS デバッガーのヘルプが必要な場合は、順を追って説明します。
于 2013-03-14T17:47:44.720 に答える