I'm attempting to read a file into a simple database into an
array of structures. The datebase file has a simple ascii format
with each record on one line, terminated with a new line character:
MM DD Details \n
where MM is a two digit month
DD is a two digit day
and Details is an ascii string of event details. The details may have
varying length, up to 256 characters. The filed is called 1998.dat.
Code is below.
I am able to read in the month and day fine, but run into trouble
getting a duplicate string and assigning it to a char * that is part
of a struct.
My IDE inspector shows that db[count].details doesn't point to a
new string with the rest of "line" as I had expected.
What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#define LINE_MAX 256
main()
{
struct event
{
int month;
int day;
char * details;
} db[3000];
char line[LINE_MAX];
int count=0,x;
FILE *in;
in=fopen("1998.dat","r");
if (in==NULL)
{
printf("Can't open 1998.dat\n");
exit(0);
}
while (fgets(line,LINE_MAX-1,in)!=NULL)
{
if (*line!=';') /* skip comment lines which begin with ; */
if (sscanf(line,"%d %d",&db[count].month,&db[count].day)==2)
db[count++].details=strdup(line[6]);
}
/* print the database */
for (x=0;x<count;x++)
printf("%d %d %s\n",db[x].month,db[x].day,db[x].details);
return;
}
--
To reply by e-mail, it's tbarmann instead of nospam
> I'm having trouble assigning a char * the result of a strdup call.
>
> I'm attempting to read a file into a simple database into an
> array of structures. The datebase file has a simple ascii format
> with each record on one line, terminated with a new line character:
>
> MM DD Details \n
>
> where MM is a two digit month
> DD is a two digit day
> and Details is an ascii string of event details. The details may have
> varying length, up to 256 characters. The filed is called 1998.dat.
>
> Code is below.
>
> I am able to read in the month and day fine, but run into trouble
> getting a duplicate string and assigning it to a char * that is part
> of a struct.
>
> My IDE inspector shows that db[count].details doesn't point to a
> new string with the rest of "line" as I had expected.
What does it point to instead?
> What am I doing wrong?
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <alloc.h>
This is not a standard C header.
> #define LINE_MAX 256
> main()
>
> {
> struct event
> {
> int month;
> int day;
> char * details;
> } db[3000];
> char line[LINE_MAX];
> int count=0,x;
> FILE *in;
>
> in=fopen("1998.dat","r");
> if (in==NULL)
> {
> printf("Can't open 1998.dat\n");
> exit(0);
> }
>
> while (fgets(line,LINE_MAX-1,in)!=NULL)
You don't need to use LINE_MAX-1, fgets() is designed to work properly
if you use LINE_MAX. The other problem here is that if there are more
than 3000 of these records in the file you will try to write data past
the end of the array, a serious bug. Try:
while ((count < 3000) && ((fgets(line, LINE_MAX, in) != NULL)));
> {
> if (*line!=';') /* skip comment lines which begin with ; */
> if (sscanf(line,"%d %d",&db[count].month,&db[count].day)==2)
> db[count++].details=strdup(line[6]);
> }
> /* print the database */
> for (x=0;x<count;x++)
> printf("%d %d %s\n",db[x].month,db[x].day,db[x].details);
> return;
> }
<Jack>
There is no standard C function strdup() and it is in fact illegal to
have a function of that name, because all names beginning with "str"
followed by any lower case letter are reserved for the implementation.
In the common implementations of this illegally-named extension it is
usually specified that it return NULL if it was unable to allocate
space to make the copy. Your sample code does not check for this
NULL.
If your compiler's implementation of this non-standard function does
not do what their documentation says it will do, I guess you have
grounds for complaint with the supplier, but not on the grounds of
being non-compliant to the language standard.
</Jack>
--
Do not email me with questions about programming.
Post them to the appropriate newsgroup.
Followups to my posts are welcome.
> strdup() is a non-standard function.
> alloc.h is a non-standard header.
> line[6] is a character. Perhaps you want an address of a character.
^^^^^^^^^^^^^^^^^^^^^^
<Jack>
ARRGH! I missed that. Somebody shoot me!
strdup is not a standard C function. Therefore I do not get what you want to
do. What you need in this case is copying the string line from position 6 to
the structure. But details need to be not only a pointer but also memory
allocated on it. Make it an array details[LINE_MAX] and use
strcpy(details,line[6]). Before doing it, you might want to remove the \n at
the end of line.
> /* print the database */
> for (x=0;x<count;x++)
> printf("%d %d %s\n",db[x].month,db[x].day,db[x].details);
> return;
> }
> To reply by e-mail, it's tbarmann instead of nospam
Ciao Paolo
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
Remove the "[6]" and everything will be fine (I hope).
--
Helmut Leitner lei...@hls.via.at
Graz, Austria www.hls-software.com
Jack -- thanks for pointing this out ....
>if you use LINE_MAX. The other problem here is that if there are more
>than 3000 of these records in the file you will try to write data past
>the end of the array, a serious bug.
Yes. But that raises another question I have. What if I don't know how
many structures I'm going to need to read in the data file? Short of
pre-scanning the file and counting the number of records needed, is
there another way? (I want the program to be as fast as possible and I'm
assuming that opening and reading a file twice would slow it down.)
Is the answer to store the data into a linked list?
Please take a look at this code and make sure I haven't done something
terribly wrong.
Again, the format of the file being read is:
MM DD Details \n
for example:
01 01 New Year's Day
02 15 Valentine's Day
each record on its own line.
Many thanks to everyone.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_MAX 256
/* trims the given char c off the end of a string if it's there */
void strtrim(char *string, char c)
{
int x;
x=strlen(string);
while (*(string+--x)==c); /* backing up till target char is no longer
found */
x++; /* increase index to point to next char */
*(string+x)='\0'; /* add index to in and terminate string */
}
main()
{
struct event
{
int month;
int day;
char * details;
} db[3000];
char line[LINE_MAX];
int count=0,x;
char *p;
FILE *in;
in=fopen("1998.dat","r");
if (in==NULL)
{
printf("Can't open 1998.dat\n");
exit(0);
}
while ((count < 3000) && ((fgets(line, LINE_MAX, in) != NULL)))
{
if (*line!=';') /* skip comment lines which begin with ; */
if (sscanf(line,"%d %d",&db[count].month,&db[count].day)==2)
{
/* get rid of trailing newline character */
strtrim(line,'\n');
if ((db[count].details=(char *)malloc(strlen(line)-5))==NULL)
{
printf("Couldn't allocate memory space.\n");
exit (0);
}
strcpy(db[count++].details,line+6);
}
}
fclose (in);
for (x=0;x<count;x++)
{
printf("%d %d %s\n",db[x].month,db[x].day,db[x].details);
free(db[x].details);
}
return;
}
--
Yes. But that raises another question I have. What if I don't know how
many structures I'm going to need to read in the data file? Short of
pre-scanning the file and counting the number of records needed, is
there another way? (I want the program to be as fast as possible and I'm
assuming that opening and reading a file twice would slow it down.)
Is the answer to store the data into a linked list?
You can use a linked list or you can allocate your array with malloc()
and then make it larger as necessary with realloc(). If you don't
expect the array to grow too large very often in practice then the
latter solution is probably better because arrays tend to be easier to
deal with.
--
"Large amounts of money tend to quench any scruples I might be having."
-- Stephan Wilms
Please: do not email me copies of your posts to comp.lang.c
do not ask me C questions via email; post them instead
You may also have a logic error relating to your data input and parsing. See the
comments within your post.
Timothy Barmann wrote:
> <snipped> MM DD Details \n
> where MM is a two digit month
> DD is a two digit day
> and Details is an ascii string of event details. The details may have
> varying length, up to 256 characters. The filed is called 1998.dat.
> <snipped>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <alloc.h>
> #define LINE_MAX 256
This may be a logic error. If the details member of your structure is a variable length
string to a max of 256 then limiting your total line length may leave data at the end of
the records during input. Read as a string the month and day including space delimeters
should use 6 chars leaving only 249 in the line array to store the potential 256 chars
in the details string.
--
Mark Merriam
Feel free to reply to me as well as the group
Remove "nospams." to reply
mark.m...@nospams.lmco.com