OD IUM OD IUM - 3 months ago 14
C Question

allocate and fill 2d-array in a function using mpi in C

Im tryin to read a ascii-file consisting of 2 columns of and a variable nr of rows. Reading is done by processor 0 and then the data is distributed using MPI_Bcast(...). I had to create a 1-dim buffer array which contains the data and is sent to all other procs because I haven't found a way to directly broadcast the 2-dim. data.
There's something wrong with the allocation of the array arr. When I try to print the data, the first 3 rows are printed and then I get a segmentation fault. Most likely there are several mistakes.

I really tried to make the example as simple as possible.
my code:

//global variables
...
double **testarray;
int dim;
...
int main(int argc, char **argv){
...
...
read_file("test.txt",&testarray,&dim);
}

int read_file(char* infilename,double ***arr,int *rowsout)
{

FILE* infile;
int i,j,ch,number_of_lines=0;
int rows=0;
//first count lines
if(myid==0) //myid is processor id
{
infile = fopen(infilename, "r");
do
{
ch = fgetc(infile);
if(ch == '\n')
number_of_lines++;
} while (ch != EOF);
if(ch != '\n' && number_of_lines != 0)
number_of_lines++;
//close file
fclose(infile);
rows=number_of_lines-1;
*rowsout=rows;
}
// every proc should know about length of file in order
//to be able to allocate memory
MPI_Bcast(rowsout,1,MPI_INT,0,MPI_COMM_WORLD);

//allocate memory
double *buf; //1D-buffer for 2D-array
MPI_Alloc_mem((*rowsout)*2*sizeof(double), MPI_INFO_NULL, &buf);
MPI_Alloc_mem((*rowsout)*sizeof(double*), MPI_INFO_NULL,arr);
for (i = 0; i < (*rowsout); i++) {
MPI_Alloc_mem(2*sizeof(double),MPI_INFO_NULL,&arr[i]);
}
// Now read file on proc 0
if(myid==0)
{
infile=fopen(infilename,"r");
for(i=0;i<rows;i++)
{
for(j=0;j<2;j++)
{
fscanf(infile,"%lf",arr[i][j]);
printf("arr[%d][%d]:%e\n",i,j,(*arr)[i][j]);
}
}
fclose(infile);
}
return 0;

//dont go further, error occurs before loop finishs
MPI_Bcast(buf,(rows)*2,MPI_DOUBLE,0,MPI_COMM_WORLD);

//now reconstruct array from buffer
for(i=0;i<(*rowsout);i++)
{
for(j=0;j<2;j++)
{
*arr[i][j]=buf[i*2+j];
}
}
MPI_Free_mem(buf);
return 0;
}

Answer

You have some issues with your arr as you guessed. Here is a fixed version of your code (minus the MPI stuff):

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

void read_file(char *filename, double ***arr, int *rowsout);

int main(void)
{
    double **testarray;
    int dim;

    read_file("test.txt", &testarray, &dim);

    return 0;
}

void read_file(char *filename, double ***arr, int *rowsout)
{
    FILE *infile;
    int i, j, ch;

    infile = fopen(filename, "r");

    do
    {
            ch = fgetc(infile);
            if (ch == '\n')
                    ++*rowsout;
    } while (ch != EOF);
    rewind(infile);

    *arr = malloc(sizeof **arr * *rowsout);

    for (i = 0; i < *rowsout; ++i)
            (*arr)[i] = malloc(sizeof ***arr * 2);

    for (i = 0; i < *rowsout; ++i)
    {
            for (j = 0; j < 2; ++j)
            {
                    fscanf(infile, "%lf", &(*arr)[i][j]);
                    printf("(*arr)[%d][%d]: %e\n", i, j, (*arr)[i][j]);
            }
    }

    fclose(infile);
    for (i = 0; i < *rowsout; ++i)
            free((*arr)[i]);
    free(*arr);
}

Example input: test.txt

0.01 0.02
0.3 0.4
5.0 6.0

Example output:

(*arr)[0][0]: 1.000000e-02
(*arr)[0][1]: 2.000000e-02
(*arr)[1][0]: 3.000000e-01
(*arr)[1][1]: 4.000000e-01
(*arr)[2][0]: 5.000000e+00
(*arr)[2][1]: 6.000000e+00

I believe the mistake comes with your fscanf() line. fscanf() wants a double * when you are using "%lf", but you are instead passing arr[i][j] and there's two things wrong with that: since arr is actually a pointer to your 2-D array, you will need to deference it first ((*arr)), and second, since it needs the address of the double, you will need to use &: &(*arr)[i][j].