P
Paul David Buchan
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
(e-mail address removed)
*********************************************
#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[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=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=dbf[48+(i*32)];
if (fieldlen>*nchars) {
*nchars=fieldlen;
}
}
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 = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
input_array[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[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][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[j][k] !=' ' && input_array[j][k] !='\t'
&& input_array[j][k] !='\n') {
break;
}
}
input_array[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[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[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=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=dbf[48+(i*32)];
if (fieldlen>*nchars) {
*nchars=fieldlen;
}
}
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 = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
*input_array[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[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][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[j][k] !=' ' && *input_array[j][k] !='\t'
&& *input_array[j][k] !='\n') {
break;
}
}
*input_array[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[j]);
}
}
free ((void *)input_array); */
return (EXIT_SUCCESS);
}
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
(e-mail address removed)
*********************************************
#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[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=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=dbf[48+(i*32)];
if (fieldlen>*nchars) {
*nchars=fieldlen;
}
}
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 = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
input_array[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[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][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[j][k] !=' ' && input_array[j][k] !='\t'
&& input_array[j][k] !='\n') {
break;
}
}
input_array[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[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[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=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=dbf[48+(i*32)];
if (fieldlen>*nchars) {
*nchars=fieldlen;
}
}
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 = (char **) malloc(ncols*sizeof(char *));
for (j=0; j<ncols; j=j+1) {
*input_array[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[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][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[j][k] !=' ' && *input_array[j][k] !='\t'
&& *input_array[j][k] !='\n') {
break;
}
}
*input_array[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[j]);
}
}
free ((void *)input_array); */
return (EXIT_SUCCESS);
}