So the problem at hand is to convert a string of digits in the format YYYYMMDD to a struct tm type member within some other structure. Truth is, I really only care about getting a struct tm with reasonable values in it.
Consider the following struct :
typedef struct some_node {
char somestring[64];
char anotherstring[128];
struct tm date_one;
struct tm date_two;
int some_val;
struct some_node *prev;
struct some_node *next;
} some_node_t;
Inside there I have two members of type struct tm from the time.h header. Seems very reasonable. Also there are pointer members in there to make a linked list however that isn't the issue.
So I create the first node in my yet to be created linked list like so :
/* begin the linked list of some_node_t */
struct some_node *t_head =
calloc( (size_t) 1, sizeof( some_node_t ) );
if ( t_head == NULL ) {
/*Memory allocation fault */
printf ( " FAIL : Memory allocation fault at %s(%d)\n",
__FILE__, __LINE__ );
exit ( EXIT_FAILURE );
}
/* I used calloc above which zero fills memory so these
* next lines are not really needed. Better safe than sorry. */
t_head->some_val = 0;
t_head->prev = NULL;
t_head->next = NULL;
Then I can stuff char data into the two char members :
strcpy ( t_head->somestring, "birthday" );
strcpy ( t_head->anotherstring, "19981127" );
No problem there.
Messing with the conversion of a string to a struct tm seems reasonable within a function as I have to do it twice perhaps.
Therefore I write this :
int timestr_to_tm ( struct tm **date_val, char *yyyymmdd ) {
/* assume 8 digits received in format YYYYMMDD */
int j, date_status = -1;
char yyyy[5]="0000";
char mm[3]="00";
char dd[3]="00";
/* copy over the year digits first */
for ( j=0; j<4; j++ )
yyyy[j]=yyyymmdd[j];
/* month digits */
mm[0]=yyyymmdd[4];
mm[1]=yyyymmdd[5];
/* day digits */
dd[0]=yyyymmdd[6];
dd[1]=yyyymmdd[7];
*(date_val)->tm_year = atoi(yyyy) - 1900;
*(date_val)->tm_mon = atoi(mm) - 1;
*(date_val)->tm_mday = atoi(dd);
*(date_val)->tm_hour = 0;
*(date_val)->tm_min = 0;
*(date_val)->tm_sec = 0;
*(date_val)->tm_isdst = -1;
return 0;
}
So my hope here is that I can pass a pointer to a pointer to the member date_one within t_node to that function.
if ( timestr_to_tm ( &(t_node->date_one), "19981127" ) < 0 ) {
/* deal with a bad date conversion */
}
Well my compiler has a fit here. Claiming :
error: argument #1 is incompatible with prototype:
Perhaps I should have &t_head->date_one but I think that the pointer dereference operator "->" takes precedence over the "address of" operator. Perhaps it is bad policy to even attempt to pass a pointer to a member within a struct?
Even worse, within the function timestr_to_tm() I get :
error: left operand of "->" must be pointer to struct/union
in those lines where I try to assign values into the struct tm variable.
I tried all this without passing pointers and the process works however upon return there is nothing in the struct tm member. So I am wondering, what am I missing here ?
strcpyis fine if you know that the target array is big enough to hold the string.strncpyis not just a "safer"strcpy; it will needlessly pad the target with extra null characters or, worse, leave the target without a null terminator (i.e., not a string). To do what you might expectstrncpyto do, you can set the initial byte of the target to'\0'and then callstrncat. See my rant on the topic.strncpy, which is why I mentioned passing 1 minus the allocated length. I forgot to mention the part about ensuring the'\0'is there. I appreciate the comment though, and the link, which I am reading now.