2D array pointer access segmentation fault in C

拜拜、爱过 提交于 2019-12-25 07:55:31

问题


I'm trying to write a code for a Conway's Game of Life in C. I have some problems with 2D array which contain my universe. I will show you a parts of code that cause me a problems. Actually there a two problems that I can't handle.

#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;
            }
        }
    }
}

Problem 1: I set the dimensions of universe (variables xDim and yDim). I print them in line 45 (check comment //Here the values are good). Then I call initializeUniverseFromFile(inputPath, xDim, yDim, old); And one of the dimensions values is changed. I have no idea why. That's why I make temporary copy of this variables, because I've spent 2 hours looking for that error. I even print out this variables at the end of that initializeUniverseFromFile function, and they are fine. But when I'm back in main again (line 50), the value is changed. This is minor problem. The worse is:

Problem 2 I have a pointer int (*old)[xDimB];

xDimB is xDim+2 so it is always bigger than xDim

I initialize the array with function allocateMemoryFor2DArray(xDimB, yDimB)

Then I do this:

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

Printing whole array with function is fine Printing values from first row are fine Printing value from middle of array create error.


回答1:


I set the dimensions of universe (variables xDim and yDim)

You need these to contain valid numbers before you declare the VLAs int (*old)[xDimB]; and int (*new)[xDimB];. Move these VLA declarations to a latter point in the program, when xDim and yDim have known, verified values.




回答2:


there are two things that i couldnt explain in the code that may be a reason for a segmentation fault.

1)

void *allocateMemoryFor2DArray(int x, int y);

Why is it void when you are clearly returning an integer array.

2) How are you returning a 2D Array on a single pointer? To define a 2D array you need a double pointer:

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

then you loop through x to define the second dimension:

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

you finally return you double pointer which is a reference to you array.

your function will become like this:

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;
}

Similarly these functions:

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])

should become:

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)

Finally your pointers in main should also become double pointers.

The reason why the first row is printing while other rows are not is that you are not looping throw the first dimension to initialise the array in the second dimension.



来源:https://stackoverflow.com/questions/36782015/2d-array-pointer-access-segmentation-fault-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!