2016-04-21 59 views
0

私は、宇宙を含む2D配列にいくつかの問題があります。私は、ConwayのGame of LifeのコードをCで記述しようとしています。私はあなたに問題の原因となるコードの一部を表示します。実際には私が扱うことができない2つの問題があります。Cの2次元配列ポインタアクセスセグメンテーションフォールト

#include <stdio.h> 
#include <stdlib.h> 
#include "file2ppm.h" 

typedef enum { false, true } bool; 

void *allocateMemoryFor2DArray(int x, int y);         //allocate memory for 2D array 
void initializeUniverseFromFile(char* path, int x, int y, int array[x][y]);  //set values of cells from a file 
void initializeUniverseRandomly(int x, int y, int array[x][y]);     //set random values 
int getNumberOfColumns (FILE *file);           //get number of columns in file (yDim of Universe) 
int getNumberOfLines (FILE *file);            //get number of lines in file (xDim of Universe) 
void print2DArray (int x, int y, int array[x][y]);        //print 2D array  
void setDimensionsFromFile(char* path,int* xDim, int* yDim, int* xDimB, int* yDimB);//set dimensions of Universe 

int main(int argc, char * argv[]) 
{ 
    int i, j, n;  //loop indexes 
    int nsteps;   //Number of generations 
    int im, ip, jm, jp; //neighbour boundaries 
    int yDim, xDim;  //Universe boundarier defined by user (Living area); 
    int xDimB, yDimB; //Universe boundaries expanded to each side by 1 
    int nsum, isum;  //sum of neighbours, sum of alive cells after iteration 
    //int **old, **new; //Universe 
    int (*old)[xDimB];  //Universe 
    int (*new)[xDimB];  //Universe 

    float x;   //to randomize first population 
    char *inputPath; //Path to file with ixDimBtial uxDimBverse 
    char *outputPath; //Path to output ppm files 


    //temporary copy 
    int yDim_copy, xDim_copy; 

    printf("argc: %d\n", argc); 
    switch (argc){ 
     case 4:   //Read the initial Universe from file 
      //Take arguments 
      nsteps = atoi(argv[1]); //Get number of iterations 
      outputPath = argv[2]; //Get path for outputimages 
      inputPath = argv[3]; //File with initialize uxDimBverse; 
      setDimensionsFromFile(inputPath, &xDim, &yDim, &xDimB, &yDimB); 
      old = allocateMemoryFor2DArray(xDimB, yDimB); //Alocate memory for expanded Universes 
      new = allocateMemoryFor2DArray(xDimB, yDimB); 
      printf("Before initialize: yDim: %d, xDim: %d\n", yDim, xDim);  //Here the values are good 
      //tmp copy 
      yDim_copy = yDim; 
      xDim_copy = xDim; 
      initializeUniverseFromFile(inputPath, xDim, yDim, old); 
      printf("After initialize: yDim: %d, xDim: %d\n", yDim, xDim);  //And here one dim is changed 
      yDim = yDim_copy;  //I took a copy to avoid this problem for now 
      xDim = xDim_copy; 

      printf("After taking from copy: yDim: %d, xDim: %d\n", yDim, xDim);//Here dimensions are good again 
      memcpy (new, old, xDimB*yDimB*sizeof(old[xDimB][yDimB]));   //Copy old to new 
      break; 


     default: 
      printf("Usage: %s iter_number, output_name, yDim, xDim\n", argv[0]); 
      printf("or\n"); 
      printf("Usage: %s iter_number, output_name, ixDimBtial_input_name\n", argv[0]); 
      printf("Note: Initial file have to be in ./data/\n"); 
      return 1; 
    } 

    print2DArray(xDim, yDim, old);  //this works fine 
    printf("In main: yDim: %d, xDim: %d\n", yDim, xDim); 
    printf("%d\n", old[0][0]);   //this works fine 
    printf("%d\n", old[2][2]);   //Segmentation failure 

    return 0; 
} 

void *allocateMemoryFor2DArray(int x, int y){ 
    int (*array)[y] = malloc(sizeof(int[x][y]));  //Allocate memory 
    if (array == NULL) {        /* always check the return of malloc */ 
     perror("malloc"); 
     exit(EXIT_FAILURE); 
    } 
    return array; 
} 

int getNumberOfColumns (FILE *file){ 
    int yDim = 0; 
    char ch; 

    do 
    { 
     ch = getc(file);       //Get 1 char from file 

     if (ch == '\n')    //If ch is new line 
     { 
      rewind(file);   //Move file pointer to beginxDimBng of file 
      return yDim;   //Found number of columns  
     }  
     else     
      ++yDim; 

    }while (ch != EOF); 
} 

int getNumberOfLines (FILE *file){ 
    int xDim = 0; 
    char ch; 

    do 
    { 
     ch = getc(file);       //Get 1 char from file 
     if(ch == '\n')        //If new line 
     { 
      ++xDim;        //Increase xDim (another row) 
     } 
    }while(ch != EOF); 
    rewind(file);         //Move file pointer to beginxDimBng of file 
    return xDim; 
} 


void print2DArray (int x, int y, int array[x][y]) 
{ 
    int i, j; 
    printf("x: %d, y: %d\n", x, y); 
    for (i = 1; i <= x; ++i) 
    { 
     for (j = 1; j <= y; ++j) 
     { 
      printf("%d ", array[i][j]); 
     } 
     printf("\n"); 
    } 
} 

void setDimensionsFromFile(char* path, int* xDim, int* yDim, int* xDimB, int* yDimB) 
{ 
    FILE *file; 
    int i,j; 
    file = fopen(path, "r");  //open file 
    if (file) 
    { 
     *yDim = getNumberOfColumns (file);     
     *xDim = getNumberOfLines (file); 
     *xDimB = *xDim + 2; // add 2 for left and right torus topology 
     *yDimB = *yDim + 2; 
     if (*xDim > 0 && *yDim > 0) 
     { 
      printf("UxDimBverse dimension %d x %d\n", *xDim , *yDim); 
     }   
     else 
     { 
      perror("Wrong initialize file"); 
      exit(EXIT_FAILURE); 
     }  

     fclose(file);      //Close file 
    } 
    else 
    { 
     perror("Open initialize file error"); 
     exit(EXIT_FAILURE); 
    } 
} 


void initializeUniverseFromFile(char* path, int x, int y, int array[x][y]) 
{ 
    FILE *file; 
    int i,j; 
    file = fopen(path, "r");  //open file 
    if (file) 
    { 
     //IxDimBtialize array 
     char *ch; 
     for (i = 1; i <= x; i++) 
     { 
      //printf("i: %d ", i); 
      for (j = 1; j <= y; j++) 
      { 
       //printf("j: %d ", j); 
       if (fscanf(file, "%c", ch) != 1) 
       { 
        perror("Read error\n"); 
       } 
       else if (isdigit((unsigned char)*ch)) 
       { 
        printf("%d", atoi(ch)); 
        array[i][j] = atoi(ch); 
       } 
       else 
       { 
        //printf("Numer znaku: %d ", ch); 
        j--; 
       } 
      } 
      printf("\n"); 
     } 
     printf("Done reading\n"); 
     fclose(file);   //Close file 
    } 
    else 
    {    //File open error 
     perror("Open initialize file error"); 
     exit (EXIT_FAILURE); 
    } 
    printf("In initialize yDim: %d, xDim: %d\n", x, y); 
} 

void initializeUniverseRandomly(int x, int y, int array[x][y]) 
{ 
    int i, j; 
    float r; 
    for (i = 1; i <= x; i++) { 
     for (j = 1; j <= y; j++) { 
      r = rand()/((float)RAND_MAX + 1); 
      if (r<0.5) { 
       array[i][j] = i*x+j; 
      } 
      else { 
       array[i][j] = i*x+j; 
      } 
     } 
    } 
} 

問題1: Iは、宇宙(変数xDimとyDim)の寸法を設定します。私は45行目にそれを表示します(コメントを確認してください//ここで値は良いです)。次に、私はinitializeUniverseFromFile(inputPath, xDim, yDim, old); と呼び出し、寸法値の1つが変更されます。なぜ私は考えていない。だからこそ私はこの変数の一時的なコピーを作るのです。なぜなら、私はそのエラーを探して2時間を費やしてきたからです。私はその変数の末尾にこの変数を表示することさえできます。しかし、私が再びメインに戻ると(50行目)、値が変更されます。これは小さな問題です。悪いのは:

問題2 int(* old)[xDimB];機能付き

print2DArray(xDim, yDim, old);  //this works fine 
printf("In main: yDim: %d, xDim: %d\n", yDim, xDim); //Dimensions are fine 
printf("%d\n", old[0][0]);   //this works fine 
for (i=0; i<=xDim; ++i) 
    printf("%d ", old[0][i];  //this works fine too 
printf("%d\n", old[2][2]);   //Segmentation failure 

印刷全体の配列は以下のとおりです。

xDimBので、その後、私はこれを行う、常に私は機能 allocateMemoryFor2DArray(xDimB, yDimB)

で配列を初期化

xDimよりも大きいxDim + 2でありますfine 1行目からの値の印刷が良好である アレイの中からの値の印刷がエラーです。

+0

'int(* old)[xDimB];': 'xDimB'はユニット化されています。 – BLUEPIXY

+0

最初の問題に関しては、なぜ最後のパラメータで完全な配列を送信していますか?代わりに配列への参照を送信するべきではありません(ダブルポインタパラメータ)? – Tarek

+0

@BLUEPIXY配列のメモリを割り当てる前に、 'setDimensionsFromFile'でxDimBを初期化します。または、int(* old)[xDimB] 'の開始前にxDimBを初期化する必要がありますか? – Marcin

答えて

2

私はあなたがあなたがのVLA int (*old)[xDimB];int (*new)[xDimB];を宣言前に、有効な数字が含まれているためにこれらを必要とする宇宙の大きさ(変数xDimとyDim)

を設定します。 xDimおよびyDimに既知の検証済み値がある場合、これらのVLA宣言をプログラムの後の点に移動します。

+0

これで問題は解決しました。2.私はすべての配列にアクセスできます。しかし、問題1とは何ですか?それはxDimの値を変更します... xDimが5の場合、初期化後に49になります。出力: '完了した読み取り 初期設定でyDim:5、xDim:5 初期化後:xDim:49 、yDim:5' – Marcin

+0

'initializeUniverseRandomly()'を使うと、この問題は起こりません。 – Marcin

-2

セグメンテーションフォルトの原因になる可能性があるコードで説明できないことが2つあります。

1)

void *allocateMemoryFor2DArray(int x, int y); 

あなたは明確に整数配列を返すしているのに、なぜそれが無効にされます。

2)2次元配列を1つのポインタにどのように戻していますか?第2の次元を定義するために、Xを紹介ループ

int** array = new int*[x]; 

for (int i=0;i<x;i++) 
    array[i] = new int[y]; 

あなたが最後にあなたの配列への参照である二重ポインタを返し、二重ポインタを必要とする2次元アレイを定義する 。

あなたの関数は次のようになります:

int** allocateMemoryFor2DArray(int x, int y) 
{ 

    int** array = new int*[x]; 
    for (int i=0;i<x;i++) 
     array[i] = new int[y]; 
    return array; 
} 

同様に、これらの機能:

void initializeUniverseFromFile(char* path, int x, int y, int array[x][y]) 
void initializeUniverseRandomly(int x, int y, int array[x][y]) 
void print2DArray (int x, int y, int array[x][y]) 

はなるはずです:

void initializeUniverseFromFile(char* path, int x, int y, int** array) 
void initializeUniverseRandomly(int x, int y, int** array) 
void print2DArray (int x, int y, int** array) 

は、最後にメインであなたのポインタは、ダブルポインタになるはずです。

他の行が印刷されていない状態で最初の行が印刷されている理由は、ループしていないということで、最初の次元をスローして2次元目の配列を初期化します。

+1

"[int']の2D配列を定義するには、ダブルポインタが必要です:絶対に、間違っています。 –

+0

コメントが間違っていても、印刷で問題が発生していない2番目のディメンションを初期化する必要があります。 'int * array [x]'と言っているのは、実際には明示的なダブルポインタと暗黙的な、つまり、初期化を待っている整数ポインタの配列ではありません。 – Tarek

+1

'int * array [x]'は2次元配列ではなく、 'int'へのポインタの1次元配列です。 *互換性がありません* int型の2次元配列です。配列を 'int array [2] [3]'と宣言すると、それが減衰するポインタの型はint(*)[3] 'になります。逆参照によって取得するオブジェクトは、3つの 'int'、* not *ポインタの配列です。より一般的には、** C配列はポインタではありません**。 OPのコードの配列の割り当ては完全にうまくいきます。実際には少し驚くべきことですが、人々はこれを間違ってしまう傾向があるからです。 –