Need help with multi-dimensional arrays and functions



Hello,

I'm attempting to write a program to read in database files (.dbf).
When I do it all as a single procedure in main, everything works.
However, what I really want, is to pass the database filename to a function,
and have it pass back an array containing the database contents, and some
parameters telling me the dimensions of the array.
I've succeeded in getting my function to read in the dbf file, and it
returns the dimensions of the array to main, but the array is my stumbling
block. I keep seg-faulting.
I allocate memory for the array inside the function, because I won't know
how big the database is until the function opens it up and analyzes it.

So my question is: can I make this program work such that the function
"readfile" opens the database file, allocates memory for an array, and
then passes that array back to main, which had no prior knowledge of the
required size of the array?

I'm really struggling with the pointer concept, I'm afraid.
Any help is appreciated.

Below are two versions separated by asterisk lines. The difference is in
my treatment of array "input" and "input_array".
Sorry they're so long, but I didn't want to trim too much for fear of missing
something important.

I'm using GCC on windows XP.

Dave Buchan
pdbuchan@xxxxxxxxx

*********************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/*int readfile (char *, int, int, int, char ***); */

int main ()
{
int i,j,nrecords,nfields,nchars;
char filename[100];
char ***input;

strcpy (filename, "input.dbf");

readfile (filename,&nrecords,&nfields,&nchars,input);
printf ("\n%u %u %u", nrecords,nfields,nchars);
printf (" %s",filename);

for (i=0; i<nrecords; i=i+1) {
for (j=0; j<nfields; j=j+1) {
printf ("%s ",input[i][j]);
}
printf ("\n");
}

}





int readfile (filename,nrecords,nfields,nchars,input_array)
int *nrecords, *nfields, *nchars;
char filename[];
char ***input_array;
{
int i,j,k,c,b1,b2,b3,b4,headlen,reclen;
int nrows, ncols,max;
int *dbf,*fieldlen;
FILE *fi;

/* Attempt to open .dbf file */
fi = fopen (filename, "rb");
if (fi==NULL) {
printf ("Can't open .dbf file.\n");
exit (EXIT_FAILURE);
}

/* Count number of bytes in .dbf file */
i=0;
while ((b1=fgetc(fi)) !=EOF) {
i=i+1;
}
fclose (fi);

/* Allocate array for file contents */
dbf = (int *)malloc(i*sizeof(int));

/* Read .dbf file into array dbf */
i=0;
fi = fopen (filename, "rb");
while ((dbf[i]=fgetc(fi)) !=EOF) {
i=i+1;
}
fclose (fi);

/* Number of records (4 bytes) */
*nrecords=(dbf[7]*256*256*256)+(dbf[6]*256*256)+(dbf[5]*256)+dbf[4];

/* Length of header (2 bytes) */
headlen=(dbf[9]*256)+dbf[8];

/* Length of each record (2 bytes) */
reclen=(dbf[11]*256)+dbf[10];

/* Count number of fields in each record */
*nfields=0;
j=32;
while (dbf[j]!=13) {
j=j+32;
*nfields=*nfields+1;
}

/* Allocate array for field lengths */
fieldlen = (int *)malloc(*nfields*sizeof(int));

/* Populate array of field lengths (1 byte each) */
*nchars=0;
for (i=0; i<*nfields; i=i+1) {
fieldlen[i]=dbf[48+(i*32)];
if (fieldlen[i]>*nchars) {
*nchars=fieldlen[i];
}
}

nrows=*nrecords+1; /* Add 1 because of header */
ncols=*nfields;
/* Allocate 3-dimensional array nrows-by-ncols-by-nchars */
input_array = (char ***) malloc (nrows*sizeof(char **));
for (i=0; i<nrows; i=i+1) {
input_array[i] = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
input_array[i][j] = (char *) malloc(*nchars*sizeof(char));
}
}

/* Initialize array contents to NULL */
for (i=0; i<nrows; i=i+1) {
for (j=0; j<ncols; j=j+1) {
for (k=0; k<*nchars; k=k+1) {
input_array[i][j][k]='\0';
}
}
}

/* Write field titles to array */
for (i=0; i<*nfields; i=i+1) {
j=0;
while (dbf[(i*32)+32+j] !=NULL) {
input_array[0][i][j]=dbf[(i*32)+32+j];
j=j+1;
}
}

/* Write all data fields to array */
for (i=0; i<*nrecords; i=i+1) {
c=1; /* Ignore Record Delete Flag */
for (j=0; j<*nfields; j=j+1) {
for (k=0; k<fieldlen[j]; k=k+1) {
input_array[i+1][j][k]=dbf[headlen+(i*reclen)+c];
c=c+1;
}
}
}

/* Trim off any trailing spaces, tabs, or newlines */
for (i=0; i<*nrecords; i=i+1) {
for (j=0; j<*nfields; j=j+1) {
for (k=fieldlen[j]-1; k>=0; k=k-1) {
if (input_array[i][j][k] !=' ' && input_array[i][j][k] !='\t'
&& input_array[i][j][k] !='\n') {
break;
}
}
input_array[i][j][k+1]='\0';
}
}

/* De-allocate memory
free (dbf);
free (fieldlen);
for (i=0; i<nrows; i=i+1) {
for (j=0; j<ncols; j=j+1) {
free((void *)input_array[i][j]);
}
}
free ((void *)input_array); */

return (EXIT_SUCCESS);
}

*********************************************
In the following version I attempt to treat array "input"
and "input_array" inthe same manner as I treat nrecords,
nfields, and nchars.

*********************************************

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

/*int readfile (char *, int, int, int, char ***); */

int main ()
{
int i,j,nrecords,nfields,nchars;
char filename[100];
char ***input;

strcpy (filename, "input.dbf");

readfile (filename,&nrecords,&nfields,&nchars,&input);
printf ("\n%u %u %u", nrecords,nfields,nchars);
printf (" %s",filename);

for (i=0; i<nrecords; i=i+1) {
for (j=0; j<nfields; j=j+1) {
printf ("%s ",input[i][j]);
}
printf ("\n");
}
exit(1);

}





int readfile (filename,nrecords,nfields,nchars,input_array)
int *nrecords, *nfields, *nchars;
char filename[];
char ****input_array;
{
int i,j,k,c,b1,b2,b3,b4,headlen,reclen;
int nrows, ncols,max;
int *dbf,*fieldlen;
FILE *fi;

/* Attempt to open .dbf file */
fi = fopen (filename, "rb");
if (fi==NULL) {
printf ("Can't open .dbf file.\n");
exit (EXIT_FAILURE);
}

/* Count number of bytes in .dbf file */
i=0;
while ((b1=fgetc(fi)) !=EOF) {
i=i+1;
}
fclose (fi);

/* Allocate array for file contents */
dbf = (int *)malloc(i*sizeof(int));

/* Read .dbf file into array dbf */
i=0;
fi = fopen (filename, "rb");
while ((dbf[i]=fgetc(fi)) !=EOF) {
i=i+1;
}
fclose (fi);

/* Number of records (4 bytes) */
*nrecords=(dbf[7]*256*256*256)+(dbf[6]*256*256)+(dbf[5]*256)+dbf[4];

/* Length of header (2 bytes) */
headlen=(dbf[9]*256)+dbf[8];

/* Length of each record (2 bytes) */
reclen=(dbf[11]*256)+dbf[10];

/* Count number of fields in each record */
*nfields=0;
j=32;
while (dbf[j]!=13) {
j=j+32;
*nfields=*nfields+1;
}

/* Allocate array for field lengths */
fieldlen = (int *)malloc(*nfields*sizeof(int));

/* Populate array of field lengths (1 byte each) */
*nchars=0;
for (i=0; i<*nfields; i=i+1) {
fieldlen[i]=dbf[48+(i*32)];
if (fieldlen[i]>*nchars) {
*nchars=fieldlen[i];
}
}

nrows=*nrecords+1; /* Add 1 because of header */
ncols=*nfields;
/* Allocate 3-dimensional array nrows-by-ncols-by-nchars */
*input_array = (char ***) malloc (nrows*sizeof(char **));
for (i=0; i<nrows; i=i+1) {
*input_array[i] = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
*input_array[i][j] = (char *) malloc(*nchars*sizeof(char));
}
}

/* Initialize array contents to NULL */
for (i=0; i<nrows; i=i+1) {
for (j=0; j<ncols; j=j+1) {
for (k=0; k<*nchars; k=k+1) {
*input_array[i][j][k]='\0';
}
}
}

/* Write field titles to array */
for (i=0; i<*nfields; i=i+1) {
j=0;
while (dbf[(i*32)+32+j] !=NULL) {
*input_array[0][i][j]=dbf[(i*32)+32+j];
j=j+1;
}
}

/* Write all data fields to array */
for (i=0; i<*nrecords; i=i+1) {
c=1; /* Ignore Record Delete Flag */
for (j=0; j<*nfields; j=j+1) {
for (k=0; k<fieldlen[j]; k=k+1) {
*input_array[i+1][j][k]=dbf[headlen+(i*reclen)+c];
c=c+1;
}
}
}

/* Trim off any trailing spaces, tabs, or newlines */
for (i=0; i<*nrecords; i=i+1) {
for (j=0; j<*nfields; j=j+1) {
for (k=fieldlen[j]-1; k>=0; k=k-1) {
if (*input_array[i][j][k] !=' ' && *input_array[i][j][k] !='\t'
&& *input_array[i][j][k] !='\n') {
break;
}
}
*input_array[i][j][k+1]='\0';
}
}

/* De-allocate memory
free (dbf);
free (fieldlen);
for (i=0; i<nrows; i=i+1) {
for (j=0; j<ncols; j=j+1) {
free((void *)input_array[i][j]);
}
}
free ((void *)input_array); */

return (EXIT_SUCCESS);
}

.



Relevant Pages

  • Re: basic question about runtime query parsing
    ... solution is to read the table layout from the database and adapt your ... >if someone issues 'create table(x int, y int, z int),' I parse it and ... define a single expandable structure which contains a byte array to ... This creates a 'table' structure containing an array of 'n' map ...
    (comp.compilers)
  • Re: averages
    ... I wonder why you did not provide a prototype for geometric mean. ... the size of which is stored as that int he has in his prototype. ... includes the number of doubles in the array, and a pointer to the array ... He checks his database ...
    (comp.lang.c)
  • Re: Second Highest number in an array
    ... >> I was working on some database application and had this small ... >> task of getting the second highes marks in a class. ... >> 1st pass through the array and find the highest number. ... > int pri, sec, i, v; ...
    (comp.lang.c)
  • Re: Newbie
    ... to talk about the int value 3 and the int value 4, ... It also lets you talk about pointer ... C has a special rule for array objects. ... to printf() is: ...
    (comp.lang.c)
  • Re: Web Databases and Objects
    ... complex object classes (things that have Arrays, ... an array of ingredients... ... id int, ... really need a relational database at all. ...
    (comp.lang.ruby)