这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
你的程序要从中找出$GPRMC语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条$GPRMC语句,以最后一条语句得到的北京时间作为结果输出。
10:48:13
源程序(仅供参考):
#include
#include
#include
#include
#define ARRAY_SIZE 10
#define ARRAY_LEN 150
#define CLEAR(x) memset(&(x), 0, sizeof(x))
/*
********************************************
函数:将一个字符串的第m位到第n位拷贝到另一个字符串中(m= end)) return NULL;
for(i = 0; i <= (end - start); i++)
{
*(des+i) = *(source + start + i);
}
return (source+start);
}
int main(int argc, char *argv[])
{
int i=0, k=0;
int right_verify = 0;
char verify[2]; //record verify hex data, use sprintf to change
char *s_start, *s_end, s_verify[2], *xor_verify, *pstr;
char UTC_time[10], *BJ_time = NULL;
char s_hh[2]={'\0', '\0'}, s_mm[2]={'\0', '\0'}, s_ss[2]={'\0', '\0'}; //hhmmss.sss
int d_hh, d_mm, d_ss;
char *res = NULL;
char *inputs[ARRAY_SIZE];
while(1) //read the line context is "END" or not
{
inputs[i] = (char *) malloc(ARRAY_LEN * sizeof(char));
res = fgets(inputs[i], 500, stdin); //read every line
if(strstr(inputs[i], "END") == 0) //find string "END" from the input
{
i++;
continue;
}
else
break;
}
putchar('\n');
for(int j=0; j= 24) d_hh = d_hh - 24;
if(d_hh < 10)
sprintf(s_hh, "0%d", d_hh);
else
sprintf(s_hh, "%d", d_hh);
d_mm = atoi(s_mm);
if(d_mm < 10)
sprintf(s_mm, "0%d", d_mm);
else
sprintf(s_mm, "%d", d_mm);
d_ss = atoi(s_ss);
if(d_ss < 10)
sprintf(s_ss, "0%d", d_ss);
else
sprintf(s_ss, "%d", d_ss);
// printf("%d:%d:%d\n\n", d_hh, d_mm, d_ss);
printf("BeiJing_Time = %s:%s:%s\n\n", s_hh, s_mm, s_ss);
return 0;
}
运行结果:
分析:
(1)题目要求是多条GPS语句输入,每条语句以回车换行结束,最后一行是END三个大写字母,因此,我们可以使用fgets函数来接受标准输入。(#include
char * fgets(char* s,int size,FILE * stream);
说明:文件指针stream,对于标准输入输出分别取stdin和stdout
返回值:若成功则返回s指针,返回NULL则表示有错误发生。
(2)对于单行字符串的存储,我们首先会想到字符数组(char a[]),或者是字符型指针变量(char*),对于多行字符串数据,当然可以选用二维数组,那么就需要预先假设这个数组空间很大,在这里我们不用这个办法,选用指针数组(char *a[])存储,[]的优先级比*高,因此,这表示一个数组,数组中的每个元素类型都为char*型,需要存储字符串时,就使用malloc函数分配一块空间,用a[i]指向这一块存储空间。可见,在内存中,每个字符串存储空间之间并不是连续的。(#include
(3)判断是否输入结束,我们还需要判断每个字符串的内容,最后一行是END三个大写字母,可以使用strstr函数查找或者是strcmp函数比较。(#include
int strcmp(const char *s1,const char *s2);
返回值:若参数s1和s2字符串相同则返回0;
s1若大于s2则返回大于0的值;
s1若小于s2则返回小于0 的值。
char *strstr(const char *haystack,const char *needle);
返回值:返回指定字符串第一次出现的地址,否则返回0。
(4)验证校验和:我们需要查找字符'$'和'*',这里就有多种方法,1.已知字符'$'是第0个,'*'倒数第3个,直接就可以查找;2.利用for循环遍历每个字符,标记位置即可;3.用strchr或strstr查找函数,同样标记'$'和'*'出现的位置。找到了字符串开始和结束位置,依次对每个字符进行异或就可以得到校验和,我们自己计算出来的校验和可以是十进制或者16进制,而GPS语句最后两位数表示的检验和为16进制,因此这里可以使用格式化函数sprintf将字符转换成16进制格式化字符,再使用atoi函数将字符串转换成整数来比较,即可验证校验和。(#include
char *strchr(const char *s, int c);
返回值:如果找到指定的字符则返回该字符所在地址,否则返回0。
int sprintf( char *str,const char * format,.........);
返回值:成功则返回参数str 字符串长度,失败则返回-1。
int atoi(const char *nptr);
返回值:返回转换后的整型数。
使用这两个函数之前自己最好简单测试下,看看适用情况
(5)提取每个字段的信息:GPS语句行中以逗号","隔开各个字段,每个字段的大小(长度)不一,我们要获得每个字段的信息,只有标记前后两个','字符。题目中要求查找字段1的时间信息,代码中使用的方法就是查找第一个字符',',而且字段0与字段1的长度都是一定的,因此设计了一个子函数来提取时间信息,将GPS语句中的字段1信息拷贝出来。
(6)UTC时间与北京时间的转换:本地时间 = UTC + 时区差