初学 C 的指针和字符串,使用时出现一些问题,还请指点一下

2015-01-21 14:23:25 +08:00
 zeroday

我的代码是要处理这样的字符串

$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50

程序要读入多行这样的字符串,依据","分割字符串

然后判断0号字段是否为"$GPRMC",2号字段是否为“A",并且验证校验和,即从字符'$'到''中间的所有字符的异或为''后面的两个字符(这两个字符为十六进制表示)

最后将最后一个符合要求的字符串的1号字段前6个字符(即 uc t时间)转化为 bjt 时间

在最后一步,我遇到这样一个问题,我开了一个大小为7的字符数组,将转化后的 bjt 时间用 strcpy()填充到字符数组中却得到乱码,请问是怎么回事呢?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* str_sub( char str[], int start, int end );
void str_split( char* words[], char str[], char* delim );
int chk_sum( char sen[] );
int hex_to_dec( char *s );
int chk_val( char sen[] );
void print_bjt( char uct[] );
int is_vaild( char *words[], int chksum, int chkval );

int main()
{
    /*char str[] = "$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50";*/
    char sen[255];
    char uct[7];
    scanf ( "%s", sen );
    while ( strcmp( sen, "END" ) != 0 )
    {
        char *words[17];
        int chksum = chk_sum( sen );
        int chkval = chk_val( sen );
        printf ( "chksum=%d chkval=%d\n", chksum, chkval );
        str_split( words, sen, "," );

        {
            printf ( "word[1]=%s\n", words[0] );
            printf ( "word[2]=%s\n", words[1] );
            printf ( "%s\n", sen ); 
        }

        if ( is_vaild( words, chksum, chkval ) == 1 )
        {
            printf ("%s\n", str_sub( words[1], 0, 6 ) );
            strncpy( uct, str_sub( words[1], 0, 6 ), 6 );
            printf ("%s\n", uct );
        }
        scanf ( "%s", sen );
    } 
    printf ("%s\n", uct );
    print_bjt( uct );
    return 0;
}

char* str_sub( char str[], int start, int end )
{
    char new_str[end - start + 1];
    char *result =  new_str;
    for ( int i = start, j = 0; i < end - start; i++, j++ )
    {
        new_str[j] = str[i];
    }
    result[end-start] = '\0';
    return result;
}

void str_split( char* words[], char str[], char* delim )
{
    int i = 0;
    char *buf = str;
    while ( (words[i] = strtok( buf, delim ) ) != NULL )
    {
        i++;
        buf = NULL;
    }
}

int chk_sum( char sen[] )
{
    char *p = NULL;
    p = strchr ( sen, '$' ) + 1;
    int xor = *p++;
    while ( *p != '*' )
    {
        xor ^= *p;
        p++;
    }
    xor %= 65536;
    return xor;
}

int chk_val( char sen[] )
{
    char *p = NULL;
    p = strchr( sen, '*' ) + 1;
    int checkval = hex_to_dec( p );
    return checkval;
}

int hex_to_dec( char *s )
{
    int n = 0;
    int i = 0;
    for (i = 0; s[i] != '\0'; i++)
    {
        if (s[i] >= '0' && s[i] <= '9')
            n = n * 16 + s[i] - '0';
        if (s[i] >= 'a' && s[i] <= 'f')
            n = n * 16 + s[i] - 'a' + 10;
        if (s[i] >= 'A' && s[i] <= 'F')
            n = n * 16 + s[i] - 'A' + 10;
    }
    return n;
}

int is_vaild( char *words[], int chksum, int chkval )
{
    int ret = 0;
    if ( strcmp( words[0], "$GPRMC" ) == 0 &&
            strcmp( words[2], "A" ) == 0 &&
            chksum == chkval )
    {
        ret = 1;
    }
    return ret;
}

void print_bjt( char uct[] )
{
    int uct_h1 = ( uct[0] - '0' ) * 10;
    int uct_h2 = ( uct[1] - '0' );
    int uct_hh = uct_h1 + uct_h2;
    int bjt_hh = ( uct_hh + 8 ) % 24;
    printf ( "%2d:%c%c:%c%c", bjt_hh, uct[2], uct[3], uct[4], uct[5] );
}
3224 次点击
所在节点    问与答
23 条回复
besto
2015-01-22 12:28:20 +08:00
@fliar 可以。还有for (int i = 1; i < 10; i++)
canautumn
2015-01-22 13:38:52 +08:00
@zeroday 之前没仔细看你的代码。现在发现你没必要自己写一个str_sub。你想想,strncpy不就是str_sub吗?你把
printf ("%s\n", str_sub( words[1], 0, 6 ) );
strncpy( uct, str_sub( words[1], 0, 6 ), 6 );
这两行换成
strncpy( uct, words[1], 6 );
一样能跑通,还没有你出现的内存的问题。

另外楼上有提到,你的uct的最后一个字符串结束符\0没有处理。最好的办法其实是在初始化uct时把uct[6]初始化为0。数组在创建时是不自动初始化的,里边的值可能是任意值,只不过程序刚开始很可能是0,但是不初始化是不安全的。应该养成好习惯。万一不是0,你的uct就可能出问题了。
fliar
2015-01-22 15:30:35 +08:00
@besto 所以可以申請變長數組喔

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/164134

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX