2017-03-03 3 views
-1

私は、PPMファイルに対してさまざまな効果と操作を実行できるプログラムを開発中です。しかし、テストのために、入力ファイルではなくcinを使用します。一度に複数のエフェクトを実行できるようになっていますが、1つでも問題が発生しています。動作する行でremoveBlue()を実行し、別の値で再試行して、代わりに赤または緑を削除します。そんなこと。コードがたくさんあるので、必要なものだけを含めるようにします。C++:PPMファイルの操作に関する問題

#include <vector> 
#include <stdlib.h> 
#include <cstdlib> 
#include <string> 
#include <vector> 
#include <fstream> 
#include <sstream> 
#include <iostream> 
using namespace std; 

class SimpleImageEffect 
{ 
public: 
    virtual void processImage(vector<Point> &points) = 0; 
}; 

class RemoveRed : public SimpleImageEffect 
{ 
public: 

    virtual void processImage(vector<Point> &points) 
    { 
     for (Point& p : points) 
     { 
      p.setRed(0); 
     } 
    } 
}; 
//Just an example of one of the effect classes. 
//The code in them is correct, so I won't include the others unless needed. 

vector<Point> parse_line(string line) 
{ 
    istringstream scanner{line}; 
    vector<Point> result{}; 
    int red = -1; 
    int green = -1; 
    int blue = -1; 
    int counter = 0; 

    while(scanner.good()) 
    { 
     if (counter == 0) 
     { 
      counter++; 
      scanner >> red; 
     } 
     else if (counter == 1) 
     { 
      counter++; 
      scanner >> green; 
     } 
     else if (counter == 2) 
     { 
      scanner >> blue; 
      Point p{ red, green, blue }; 
      result.push_back(p); 
      counter = 0; 
     } 
    } 
    return result; 
} 

void readFromCin() 
{ 
    string line = ""; 

    vector<string> lines_in_file{}; 
    int i, effect_choice; 
    SimpleImageEffect *effect = nullptr; 

    getline(cin, line); 

    while (line.length() > 0) 
    { 
     lines_in_file.push_back(line); 
     getline(cin, line); 
    } 

    for (int i = 0; i < lines_in_file.size(); i++) 
    { 
     if (lines_in_file[i] != "P3") 
     { 
      effect_choice = strToInt(lines_in_file[i]); 
     } 

     else if (lines_in_file[i] == "P3") 
     { 
      cout << lines_in_file[i] << endl; 
      cout << lines_in_file[i+1] << endl; 
      cout << lines_in_file[i+2] << endl; 
     } 

     vector<Point> points = parse_line(lines_in_file[i]); 

     if (effect_choice == 1) effect = new RemoveRed; 
     if (effect_choice == 2) effect = new RemoveGreen; 
     if (effect_choice == 3) effect = new RemoveBlue; 
     if (effect_choice == 4) effect = new NegateRed; 
     if (effect_choice == 5) effect = new NegateGreen; 
     if (effect_choice == 6) effect = new NegateBlue; 
     if (effect_choice == 7) effect = new AddNoise; 
     if (effect_choice == 8) effect = new HighContrast; 
     if (effect_choice == 9) effect = new ConvertToGrayscale; 

     effect->processImage(points); 

     for (auto p : points) 
     { 
      cout << p; 
      cout << endl; 
     } 
    } 
} 

int main(int argc, char** argv) 
{ 
    string menu_choice; 
    getline(cin, menu_choice); 
    if (menu_choice == "1") 
    { 
     readFromFile(); 
    } 
    else 
    { 
     readFromCin(); 
    } 
    return 0; 
} 

だから例えば、

2 
1 
P3 
1 1 
255 
50 50 50 

の入力とそれを実行すると、

P3 
1 1 
255 
0 50 50 

を返しますが、私は

2 
3 
P3 
1 2 
255 
50 50 50 
1 2 3 

でそれを実行した場合、それは

を返します。
P3 
1 2 
255 
0 50 50 
0 2 3 

私はこの問題を引き起こしていることは全く考えていないので、助けを借りていただければ幸いです。ありがとう。

答えて

0

あなたのアルゴリズムロジック構造は、多くのにおい、これは私が見たものである。

  • が問題(ライン毎
  • lines_in_fileにすべての非空行を読んで(私にはよさそうだ)、中に追加のロジックが必要です内部ループ):
    • 「P3」でない場合は、解析しよう[EVERY]ライン整数と(それはいくつかの整数が提供されている行に何が起こるか、あなたのコードからも明らかではないが、JUD effect_choiceを設定最初の整数は正常)strToInt関数によって解析され、問題の説明から銀杏
    • 「P3」、現在の行と次の2つの出力にコピーされている場合
    • [EVERY]行は、数字のトリプレットのベクターとして解析されます
    • effectは、実際の値がeffect_choiceの新しいエフェクトで設定されています(すべての行について、末尾にdeleteeffectがないため、1行あたりのメモリがリークしています)。また、現在のエフェクトは、 "process"関数型の静的関数として実装できるように見えるので、それぞれを割り当てる必要はなく、要求された関数の特定のメモリアドレスを格納するだけです。そして、あなたはそれをprocessImageと呼びますが、画像全体ではなくラインのみを処理しています。
    • effectはトリプレット現在の行に対して実行され
    • ライントリプレットは、(次の行に
  • ループ
  • を出力しています!)入力のために例えばので

2 
3 
P3 
1 2 
255 
50 50 50 
1 2 3 

私はこれが起こる(あなたがコードの多くを提供しなかったとして、それを実行することはできません)と信じて:

行が読み込まれ、及びparticular line perこのはhappens:

lineは "2」:effect_choice = 2は、effect = RemoveGreenが、zero tripletsはpoints into parsed、empty vector over RemoveGreen::processImage() runは、empty vectorはprinted (つまり何もない)。

ライン "3":effect_choice = 3effect = RemoveBluepointsに解析ゼロトリプレット、空のベクター上ラン、空のベクターが印刷します。

行 "P3":行:{"P3", "1 2", "255"}が印刷され、0トリプレットがにパーズされ、が空ベクトルで実行され、空のベクトルが出力されます。

ライン "1 2":effect_choice = 1effect = RemoveRedpointsに解析ゼロトリプレット、空のベクター上RemoveRed::processImage()ラン、空のベクターが印刷します。

行 "255":effect_choice = 255、0トリプレットがにパーズされ、RemoveRed::processImage()が空ベクトルで実行され、空のベクトルが出力されます。

ライン "50 50 50" effect_choice = 50pointsに解析1つのトリプレット{50, 50, 50}、その上RemoveRed::processImage()ラン、修飾トリプレット出力{0, 50, 50}

ライン "1 2 3":effect_choice = 1effect = RemoveRedpointsに解析1つのトリプレット{1, 2, 3}、その上RemoveRed::processImage()ラン、修飾トリプレット出力{0, 2, 3}

これはすべてデバッガではっきりと表示され、コードをステップ実行している間はデバッグしていないので、私から質問を受け取り、デバッガなしでデバッグするはるかに難しいです。

また、アルゴリズムとコードアーキテクチャーについて考えずにコードを書くと、デバッグロットの可能性が高くなりますので、コードを書くことから始めて、ここでさらに時間を浪費します。

アルゴリズムとコードのアーキテクチャを設計する必要があります(どのようなデータが処理されるか、新しいメモリが必要な場合、どのように解放されるか、コードをループする必要がある場所、スキップする場所、一度だけなど)。

単一行のコメントにどのように作用するのかの概要を書いた後、数行のC++コードで実装できるまで、一般的なコメントを単純なステップに分割し、 (ほとんどのコメントは、「赤でポイントをゼロに設定する」のように実際に要求されるものであり、処理/準備/移動/その他は最小限に抑えられます)スマートなデザインで避けてください)。(たとえば、現在のコードでは、ループのないファイルのヘッダーを読み取って、ピクセルデータが入った後でのみループを開始できます)

次に、コードを記述します。デバッガで "実行"して空の状態を確認し、実装するのに十分明確であり、簡単にテストできるコメント(またはそれらの小さなグループ)を実装します(まだ実装されていない部品には大きく依存しません)。新しいコードをデバッグ+テストします。それがうまくいけば、本当に必要でないもの、作業中の変数名などを取り除くためにソースをクリーンアップしてみてください。そして、それが最終バージョンで動作することを確認してください。

また、実装が完了するまで、別のコメント(グループ)のためにもう一度やり直してください。

単体テストを使用すると、特にI/Oが純粋なデータであるため、特別なテストを簡単に行うことができるような場合に、write-short-code、test + debug、clean-up-sourceラウンドがさらに簡単になりますテストにデータを入力し、期待される出力データが生成されたことを確認します。

関連する問題