Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Need best & shorter solution?

Status
Not open for further replies.

perlguy

Programmer
May 17, 2001
26
0
0
US
I have wrote the following C prg. to display random record contents from text file 'pix.db'. It generates random num from 1 to 10 and then fetches corr. record from 'pix.db'

File pix.db format: (note '|' is my field sepator)
ID|pix file|pic name

for example:
1|pix1.gif|pix1name
2|pix2.gif|pix2name
3|pix3.gif|pix3name
;;
;;
;;
10|pix10.gif|pix10name

Here is the 'C' code which I consider best but I don't know how efficient it is..... Does anyone know better & efficeint code for the following code....I am not 'C' guru....but I know this forum has some finest 'C' experts....hope they help me out here....Thanks in advance.

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

void file_process(char *flname, int rnd_num, char *cdata);
void err_default(void);

int main(void)
{
FILE *rd_fp;
char *temp, *pch, *pname, *pix, got_err='N';
int pnum = 10; /* for random no. any record between 1..10 */

temp = (char *) malloc( sizeof(char) * 150);
pch = (char *) malloc( sizeof(char) * 150);

/* calling function passing 'pnum' */
file_process(&quot;pix.db&quot;, pnum, temp);

/* split the record */
strcpy(pch, strtok(temp, &quot;|&quot;));
if ( (pix = strdup(pch)) == NULL) got_err='Y';
strcpy(pch, strtok (NULL, &quot;|&quot;));
if ( (pname = strdup(pch)) == NULL) got_err='Y';

if(got_err == 'Y') print_error(); /* if error show default pix */

/* display content */
printf (&quot;%s = %s&quot;, pix, pname);

free(temp); free(pch);
free(pix); free(pname);

return(0);
}

void file_process(char *flname, int rnd_num, char *cdata)
{
FILE *fp;
char recflag = 'N';
int rec_number, rnd_number;
time_t t;

/* generate random number */
srand((unsigned) time(&t));
rnd_number = rand() % rnd_num+1;

/* now get the corr. record */
if ((fp = fopen(flname, &quot;r&quot;)) == NULL) print_error();
fscanf(fp, &quot;%d&quot;, &rec_number);

while( !feof(fp))
{
fgets(cdata, 150, fp);
if(rec_number == rnd_number)
{
recflag = 'Y';
break;
}
fscanf(fp, &quot;%d&quot;, &rec_number);
}
fclose(fp);
if(recflag == 'N') err_default();
}

void print_error(void)
{
printf (&quot;ERROR - NO REC FOUND \n&quot;);
exit(1);
}
 
It depends if your records are fixed format or free.

It looks like they are free since you have a separator. If they were fixed, you could use the seek and read functions in C. Much faster for large files.
 
Yes .... the record format is free....no fix format. That's why I am concern about my code.....I do not know how good it is for such free format file.
 
Can you or someone suggest some changes in the above code that will improve performance or will make my code shorter. I wish someone could help me here. waiting....

regards
perlguy
 
It depends on how much your program knows about the data in the file. Is it guaranteed that the records are sorted in ascending order? Are the records all approximately the same length?

If your program knows these things, then it can seek to about where the record will be in the file (you can come up with the algorithm to do this), use getc() or fgetc() to find the next newline character. At this point the file pointer will be positioned at the next record in the file. If the next record is greater than the search record, seek backwards for the record, if it's lesser than the search record, call fgets() until you find the record. Otherwise, it matches and you're done.

You should probably just stick with your original method, though, unless you've actually proven that it constitutes a performance bottleneck. If it's fast enough, great! If it ain't broken, don't fix it.

BTW, I didn't compile your code and test it, but it has at least one problem. Don't test for feof() at the top of your loop like that. feof() doesn't evaluate the stream it's passed. As a result, your fgets() call below it will return NULL when *it* encounters end-of-file.
Russ
bobbitts@hotmail.com
 
Thanks for reply. YES all the records are stored in Ascending order(1..100) but are of different length.
Any suggestion?

regards
perlguy.
 
Another variation on the seek method described above is to use mmap() (if it's available to you), which allows you to treat the contents of the file as an ordinary array of char. This might be easier and will probably be faster.
Russ
bobbitts@hotmail.com
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top