Reputation: 404
I have written a simple small program to read a file with following format using snprintf,
skip first 15 chars , next 9 chars are sequence number, next 2 char is message and so on.
I am interested in sequence number and message i.e. from char no 16 to 26;
below is the program. It does not reads last char for each field. It reads 8 chars instead of 9 for sequence number and and 1 byte instead of 2 for message.
#include<stdio.h>
typedef struct
{
char seqno[9];
char msg[2];
}Header_T;
int main()
{
char buf[64]={'\0'};
FILE *fp;
int i = 0;
Header_T hdr1;
int skipbytes = 15;
fp=fopen("asdf", "r");
if (fp == NULL)
{
printf("FILE OPEN ERROR\n");
}
printf("--sequence--msg--\n");
while( fgets( buf, sizeof(buf), fp ) != NULL )
{
i=skipbytes;
snprintf(hdr1.seqno, 9, "%s", (buf+i));
i+=sizeof(hdr1.seqno);
snprintf(hdr1.msg, 2, "%s", (buf+i));
i=0;
printf("--%s--%s--\n", hdr1.seqno, hdr1.msg);
memset(buf, '\0', 64 );
}
fclose(fp);
return 0 ;
}
part of file contents is as follows
201301082323458000000001H QB234
201301082323558000000002J QB234
201301082323658000000003N QB234
201301082323758000000004JRQB234
201301082333458000000010JSQB234
so expected output is
--sequence--msg--
--000000001--H --
--000000002--J --
--000000003--N --
--000000004--JR--
--000000010--JS--
But Instead I am getting output as
--seqno--msgtype--
--00000000--H--
--00000000--J--
--00000000--N--
--00000000--J--
--00000001--J--
Can anyone explain this behavior and how to fix it?
Instead of snprintf I tried the same program using for loop character-by-character assignment and program works fine; but for that I need to add some fillers for byte alignment in structure.
I also tried using pragma pack() but it also makes no difference.
I am using gcc 4.4.3 on ubuntu 64 bit machine
Upvotes: 0
Views: 1550
Reputation: 122433
From cppreference
int snprintf ( char * s, size_t n, const char * format, ... );
n: Maximum number of bytes to be used in the buffer.
The generated string has a length of at most n-1, leaving space for the additional terminating null character.
So if you expect 9 characters, you should pass n
as 10
, instead of 9
:
snprintf(hdr1.seqno, 10, "%s", (buf+i));
Header_T
needs to get changed accordingly:
typedef struct
{
char seqno[10];
char msg[3];
}Header_T;
Upvotes: 4
Reputation: 40145
#include<stdio.h>
typedef struct {
char seqno[9+1];//+1 for EOS('\0')
char msg[2+1];
} Header_T;
int main(void){
char buf[64]={'\0'};
FILE *fp;
Header_T hdr1;
fp=fopen("asdf", "r");
if (fp == NULL) {
printf("FILE OPEN ERROR\n");
return 1;
}
printf("--sequence--msg--\n");
while( fgets( buf, sizeof(buf), fp ) != NULL ){
sscanf(buf, "%*15c%9c%2c", hdr1.seqno, hdr1.msg);
hdr1.seqno[sizeof(hdr1.seqno)-1] = hdr1.msg[sizeof(hdr1.msg)-1] = '\0';
printf("--%s--%s--\n", hdr1.seqno, hdr1.msg);
//memset(buf, '\0', 64 );
}
fclose(fp);
return 0 ;
}
Upvotes: 1
Reputation: 5132
You need to have an extra character to store the trailing '\0'
character, so your struct should look like
typedef struct
{ char seqno[10];
char msg[3];
}Header_T;
EDIT: since this is a simple data transfer, why not use memcpy
, like:
memset(hdr1, 0, sizeof(hdr1));
memcpy(hdr1.seqno, &buf[skipbytes], 9);
memcpy(hdr1.msg, &buf[skipbytes + 9], 2);
Upvotes: 1
Reputation: 2857
This anwser is after the two anwser above.They all give a some right suggestions . I just spliced them together .
First , use :
typedef struct
{ char seqno[10];
char msg[3];
}Header_T; //so we have the memory for '\0'
Then , use :
while( fgets( buf, sizeof(buf), fp ) != NULL )
{
i=skipbytes;
snprintf(hdr1.seqno, 10, "%s", (buf+i));//here we read 9 number and a '\0'
i+=sizeof(hdr1.seqno) -1; //the '\0' is not part of buffer.
snprintf(hdr1.msg, 3, "%s", (buf+i)); //also for '\0'
i=0;
printf("--%s--%s--\n", hdr1.seqno, hdr1.msg);
memset(buf, '\0', 64 );
}
Upvotes: 0