473,378 Members | 1,482 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

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
pd******@yahoo.com

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

Jun 27 '08 #1
4 1554
On Sat, May 24, 2008 at 02:26:55PM -0400, Paul David Buchan wrote:
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
[snip]

Let's get to your code
*********************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/*int readfile (char *, int, int, int, char ***); */
Why is this a comment? Using a function prototype is nothing evil.
int main ()
{
int i,j,nrecords,nfields,nchars;
char filename[100];
char ***input;

strcpy (filename, "input.dbf");

readfile (filename,&nrecords,&nfields,&nchars,input);
Uups, the 'input' variable inside of readfile() receives an uninitialised
value, and has no chance to return the initialised value to main().
Your second version does not have this problem. Why don't you pass the 'input'
pointer as a return value of the function?
printf ("\n%u %u %u", nrecords,nfields,nchars);
Are you sure about the %u ?
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");
}
}
Let's see the second attempt
*********************************************
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 ***); */
Ok, with deleting /* and */
>
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);
%u is for unsigned ints. Yours are plain ints, so better use %d.
printf (" %s",filename);

for (i=0; i<nrecords; i=i+1) {
I wonder why you keep writing i=i+1, most people do i++, but your version
is equally correct.
for (j=0; j<nfields; j=j+1) {
printf ("%s ",input[i][j]);
}
printf ("\n");
}
exit(1);
Does 1 mean a kind of failure? Normally exit(0) is used for
the successful termination, but from the main(), a 'return 0' will do.
>
}
And now comes your lengthy function
>
int readfile (filename,nrecords,nfields,nchars,input_array)
int *nrecords, *nfields, *nchars;
char filename[];
char ****input_array;
This is the ancient way of defining a function.
{
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));
The (int*) is superfluous and can be misleading.
sizeof(*dbf) is slightly easier to maintain than sizeof(int)
/* Read .dbf file into array dbf */
i=0;
fi = fopen (filename, "rb");
You are reopening a file. Are you doing so just to get again to its
begining? How about a rewind() (or fseek())?. A reopening should
again involve some error checking...

[snip some code]
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 **));
these casts in front of malloc are quite annoying. A C++ compiler
will sure require this, but well, this is C, so let's save those
keystrokes.
for (i=0; i<nrows; i=i+1) {
*input_array[i] = (char **) malloc(ncols*sizeof(char *));
Uups!
*input_array[i] is *(input_array[i]) that is input_array[i][0]
I what you really wanted is (*input_array)[i]=...
The catch is the operator precedence.
for (j=0; j<ncols; j=j+1) {
*input_array[i][j] = (char *) malloc(*nchars*sizeof(char));
Again: (*input_array)[i][j] will be better
}
}

/* 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';
Yet again: (*input_array)[i][j][k]=0 will be better.
Notice that '\0' is the four character long-hand for 0 (both are ints).

[snip], you'll have to correct the same error in a few
/* 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]);
???????
Are you releasing the memory before returning from the function?
Where is the caller (the main()) supposed to find the data?
And please do not cast the pointers to (void*), this conversion takes
place automatially.
}
}
free ((void *)input_array); */
???????
Are you planning to call free() on the the callers memory? Not very
polite. These lines stayed in your code from the times when everything
was in the main()
>
return (EXIT_SUCCESS);
This too.
}
By the way, you do not need to call free() on the malloced memory. This
is all done for you when your program exits. The friendly way of
the deallocation, if you need one, is to accompany your read routine with
a deallocator function.

Szabolcs
Jun 27 '08 #2
Thanks Szabolcs!

Looks like a lot of good information there.
It's going to take me some time to understand it all.
I've been FORTRAN programming for years, so C is hard for me.

I really appreciate your comments.

Dave
Jun 27 '08 #3
Hi guys,

Ben, You're right! I actually had a brief moment of clarity
when I was thinking of leaving everything in the dbf array,
but I somehow got onto the track I did.

Regardless, I totally missed the fact that I didn't terminate the strings.
And now that you mention is, there may be a screw-up in my trimming
routine. I need to check the bounds on that. I haven't looked yet.

Thanks for the input.

Dave

Jun 27 '08 #4
Szabolcs,

I'm pleased to report that I implemented your recommendations,
and now it works perfectly!

Thanks again,

Dave
Jun 27 '08 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Frank Jona | last post by:
Intellisense with C# and a multi-file assembly is not working. With VB.NET it is working. Is there a fix availible? We're using VisualStudio 2003 Regards Frank
3
by: Pat Deegan | last post by:
Greetings, I've been having issues while debugging programs. The problems only appear when using the '-d' switch and I get the impression it has to do with UTF8 and regex matching but I don't...
5
by: Mark Harrison | last post by:
I'm looking for feedback from anybody who has used pg in a multi-threaded program, particularly one in which several threads each open a database connection. It's documented to work in that...
2
by: NiponW | last post by:
Hi, I have SQL SERVER 2000 SP4 Enterprise , Windows 2003 Enterprise on Xeon 4 Processors (now with multi-threading CPU) and I have questions which seem weirds to me (used to have the same...
5
by: Olly | last post by:
Hello Everyone! Could someone please have a look at my JS Form I posted below....Something wrong there, but I don't understand what's exactly. Many thanks. Olly ...
20
by: mike | last post by:
I help manage a large web site, one that has over 600 html pages... It's a reference site for ham radio folks and as an example, one page indexes over 1.8 gb of on-line PDF documents. The site...
1
by: mknoll217 | last post by:
I am recieving this error from my code: The multi-part identifier "PAR.UniqueID" could not be bound. The multi-part identifier "Salary.UniqueID" could not be bound. The multi-part identifier...
0
by: Ling | last post by:
I am using boost.python to wrap C++ function which includes directmusic libraries to simply play the midi, but lots of linkage errors "error LNK2001: unresolved external symbol". I wonder if it is...
1
by: mskapek | last post by:
I need some advise on how to best create an Access 2002 report from multiple "total" queries, each which result in 3- 5 values that I need displayed on my report. Most of the queries do simple...
2
by: BruceWho | last post by:
I downloaded boost1.35.0 and built it with following command: bjam --toolset=msvc-7.1 --variant=release --threading=multi -- link=shared --with-system stage and it failed to compile, error...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.