0

私は C++ にやってくる Java ユーザーですが、このステートメントの何が問題なのかを理解するのに苦労しています。私のプログラムは、push_backコマンドを入力した場所でセグメンテーション違反を起こしています。だから、具体的にどうなのか気になります。

class Process {
  public:
    int nice;
    int arrivalTime;
    int cpuBursts;
    list<int> burstList;

    Process() {
      burstList.push_back(10); // Segfaults here...
   }  
}; 

完全なコードは次のとおりです。

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

using namespace std;

int calcTimeslice(int priority);
int calcOriginalPrio(int nice);
int readFile(int ,char **);
int calcPrioBonus(int,int);
void tokenizeAndAdd(char *);

class Bursts {
  public:
    int isCPUBurst;
    int time;

    Bursts() {}
    // Constructor to make it easier to add to list
    Bursts(int tempIsCPU, int tempTime) {
      isCPUBurst = tempIsCPU;
      time = tempTime;
    }

};

class Process {
  public:
    int nice;
    int arrivalTime;
    int cpuBursts;
    list<int> burstList;

    Process() {
      burstList.push_back(10);
   }
};



int main(int arg, char **argv) {

  // This is if the file was not correctly read into the program
  // or it doesnt exist ...
  if(readFile(arg,argv)==-1) {
    cout << "File could not be read. \n";
    return -1;
  }
  //cout << "Original Calc Whatever: " << calcOriginal(19) << '\n';
  return 0;

}

/*
 *  Calculates the timeslice based on the priority
 */
int calcTimeslice(int priority) {
  double finalCalc;

  // This is the given function in the prompt
  finalCalc = ( (1 - (priority / 140)) * 290 + (.5) ) + 10;

  // Cast to int, this will be a truncate
  return ((int)finalCalc);
}

int readFile(int arg, char **argv) { 
  char *temp,*pointer;
  int endOfFile = 1;

  // While its not the end of the file
  while(endOfFile) {
    // Read in the input from stdin
    fgets(temp,256,stdin);

    // Check to see if this line had a * in it
    if(*temp =='*')
      endOfFile = 0;
    else
      tokenizeAndAdd(temp);
  }

  return 0; 

}

void tokenizeAndAdd(char *string) {
  char *token = strtok(string," \n"); 
  int i = 0;
  Process p;

  while(token != NULL) {
    cout << token << endl;
    if(i>2) {  // If it is odd (CPU burst)
      if(i%2 == 1) {
        int tempInt = atoi(token);
        //p.burstList.push_back(tempInt); 
      }
      else { // If it is even (IO burst)
        int tempInt = atoi(token);
        //p.burstLis.push_back(tempInt); 
      }      
    }
    else if(i==0)
      p.nice = atoi(token);
    else if(i==1)
      p.arrivalTime = atoi(token);
    else if(i==2)
      p.cpuBursts = atoi(token);

    token = strtok(NULL," \n");
    i++;
  }

  //cout << p.nice << " " << p.arrivalTime << " " << p.cpuBursts << "\n";
  //i = 0;
  //cout << p.burstList.size() << "\n";
  //  cout << 
  //}
  return;
}

/*
 *  Calculates and returns the original priority based on the nice number
 *    provided in the file.
 */
int calcOriginalPrio(int nice) {
  double finalCalc;

  // This is the given function from the prompt
  finalCalc = (( nice + 20 ) / 39 ) * 30 + 105.5;

  // Cast to int, this is a truncate in C++
  return ((int)finalCalc);
}

/* 
 * Calculates the bonus time given to a process
 */
int calcPrioBonus(int totalCPU, int totalIO) {
  double finalCalc;

  // How to calculate bonus off of the prompt
  if(totalCPU < totalIO)
    finalCalc = ( (1 - (totalCPU / (double)totalIO)) * (-5)) - .5;
  else
    finalCalc = ( (1 - (totalIO / (double)totalCPU)) * 5) + .5;

  // Cast to int
  return ((int)finalCalc);
}
4

2 に答える 2

2

temp次のコードでは uninitialized を使用しています。

char *temp;
...
while(endOfFile) {
  fgets(temp,256,stdin);
  ...

スタックまたはヒープ メモリの一部が破壊される可能性が高いため、これには何らかの副作用が生じる可能性があります。すぐに失敗する可能性があり(fgets()関数を呼び出すとき)、後で失敗する可能性があります(サンプルのように)、または正常に実行されることさえあります-おそらく、OS、コンパイラなどをアップグレードするまで、または同じ実行可能ファイルを実行するまで別のマシンで。これは未定義の動作と呼ばれます。

tempポインターだけでなく、変数にスペースを割り当てる必要があります。次のようなものを使用します

char temp[256];
...
while(endOfFile) {
  fgets(temp,256,stdin);
  ...

詳細については、fgets()ドキュメントを参照してください。最初のパラメーターは、char 配列へのポインターfgets()です。これは、読み取られたバイトが格納される場所です。fgets()コードでは、バイトを未定義のメモリ位置に格納することを意味する初期化されていないポインターを渡します。これは、セグメンテーション違反でアプリケーションを終了する OS によってキャッチされます。


ところで:コンパイル時にペダンティックな警告を有効にすることを検討する必要があります-私はでコンパイルしました

g++ -Wall -pedantic -o list list.cpp

次の警告が表示されました。

list.cpp: In function 'int readFile(int, char**)':
list.cpp:76:26: warning: 'temp' may be used uninitialized in this function [-Wuninitialized]
于 2013-03-08T08:42:14.647 に答える
0

これはおそらく、報告したエラーのある実際のコードではありません。しかし、ここにUBを与えることに関する問題の1つがあります。

  char *temp,*pointer; // uninicialized pointer  char temp[1000]; could work?
  int endOfFile = 1;

  // While its not the end of the file
  while(endOfFile) {
    // Read in the input from stdin
    fgets(temp,256,stdin);

最後の関数呼び出しは、stdinから最大256バイトを読み取り、ポインターtmpが指すメモリに書き込みます。したがって、最初にそのメモリを「準備」する必要があります。しかし、char*tmpを使用します。ポインタを定義するだけで、値は定義されていません。つまり、メモリに対して存在しないか、違法/アクセスできない可能性のあるポインタを指します。逆に、char tmp [1000]; 「スタックメモリ」に1000バイトのブロックを定義し、単純な変数tmpを使用するように指示できます。これがあなたにとって明らかであることを願っています。
編集:

I don't know why that would change the behavior of the list, 

あなたが正しいです。それが未定義動作(UB)です。未知のメモリ(初期化されていないポインタが指す)に書き込むと、データやコードが上書きされ、プログラムの正しい機能が予期しない方法で壊れてしまう可能性があります。ポインタについてもっと学ぶ必要がありますが、std :: stringを使用し、stringとstringstreamを使用してファイルを解析する方法を確認することをお勧めします。それはあなたのために記憶を管理します、

于 2013-03-08T08:44:13.370 に答える