Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

problem with strdup

0 views
Skip to first unread message

Dann Corbit

unread,
Dec 29, 1998, 3:00:00 AM12/29/98
to
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.
--
Hypertext C-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-FAQ ftp: ftp://rtfm.mit.edu, C-FAQ Book: ISBN 0-201-84519-9
Try "C Programming: A Modern Approach" ISBN 0-393-96945-2
Want Software? Algorithms? Pubs? http://www.infoseek.com

Timothy Barmann

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
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 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

Jack Klein

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
On Wed, 30 Dec 1998 04:34:58 GMT, Timothy Barmann <nos...@home.com>
wrote:

> 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.


Jack Klein

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
On Tue, 29 Dec 1998 21:08:28 -0800, "Dann Corbit"
<dco...@solutionsiq.com> wrote:

> 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!

paolo...@my-dejanews.com

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
In article <3689AE26...@home.com>,

Timothy Barmann <nos...@home.com> wrote:
> 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 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]);
> }

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

Helmut Leitner

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
Timothy Barmann wrote:
>
> 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 am I doing wrong?
>
> #include <stdio.h>
> ...

> db[count++].details=strdup(line[6]);
===

Remove the "[6]" and everything will be fine (I hope).

--
Helmut Leitner lei...@hls.via.at
Graz, Austria www.hls-software.com

Timothy Barmann

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
Ok Dann, Jack, Helmut and all who replied. I've taken your
advice. Got rid of strdup and am now using malloc and strcpy in
its place. And got rid of trailing \n.

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;
}


--

Ben Pfaff

unread,
Dec 30, 1998, 3:00:00 AM12/30/98
to
Timothy Barmann <nos...@home.com> writes:

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

Mark Merriam

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to Timothy Barmann
Timothy,

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

0 new messages