使用strtok分割char *数组给出运行时错误

时间:2015-09-29 12:40:45

标签: c parsing split strtok scanf

我的代码很简单(只是拆分一个数组),但由于我没有c编译器,我在http://ideone.com上在线编译它。但是,它无论如何都会产生运行时错误,我也尝试使用sscanf解析但是徒劳无功。请帮忙。

#include<stdio.h>
#include<string.h>
typedef struct{
   char *header;
   char *body;
}AT_msg_Data;
static char *__rx_data = "AT+CGMI\r";
int main(){
    AT_msg_Data *data;
    printf("In main");
    data->header = strtok(__rx_data,"+");
    data->body = strtok(NULL,"+");
    //also tried sscanf_s(data->body,"[^=]%s\r",at_comm,sizeof(at_comm),at_param,sizeof(at_param));
    printf("%s %s", data->header, data->body);
}

2 个答案:

答案 0 :(得分:2)

您无法在字符串文字上调用strtok(),因为字符串文字是常量。通常,使用const限定符声明指向字符串文字的指针更安全,以确保编译器在程序尝试修改指针时会发出警告。

你需要让你的字符串成为一个数组而不是一个指向字符串文字的指针,比如

static char __rx_data[] = "AT+CGMI\r";

这是一个包含9个字符的8字节数组,您可以修改这些字符,strtok()会修改它的参数。

您还需要为struct分配空间才能使用它,您可以通过两种方式进行操作,使用malloc()

AT_msg_Data *data;
data = malloc(sizeof(*data));
if (data == NULL)
    return -1; /* failed to allocate memory -- exit the program */

或者,只需在堆栈上创建一个实例

AT_msg_Data data;
/*         ^ no star here */

然后使用.代替->访问其成员。

另一种不适用于此情况的方法是因为无法动态分配字符串,所以使用malloc()strdup()

你也可以像这样使用strchr()

const char *plus;
plus = strchr(__rx_data, '+');
if (plus != NULL)
{
    size_t length; /* maybe use `ptrdiff_t' here but just for illustration */
    length = plus - __rx_data;
    data->header = malloc(length + 1); 
    if (data->header != NULL)
    {
        memcpy(data->header, __rx_data, length);
        data->header[length] = '\0';
        data->body = strdup(plus + 1);
    }
    /* note: data->header can be `NULL' from here, so check that before using it */
    /*       this also applies to data->body */
}

这样你就不需要修改__rx_data哪个更好,因为它是一个全局变量,我假设你要重用它。您应该通过重新声明

使代码更安全
static const char *const __rx_data = "AT+CGMI\r";

如果您打算使用strchr()方法。

如果没有编译器抱怨,则无法重新分配或修改此__rx_data

您的代码无论如何都会失败,因为'\0'位于strtok()的位置+将被+覆盖,一旦您致电strtok() 1}}再次,strtok()保留一个内部缓冲区来恢复被替换的字符,如果你的程序是多线程的,这也会使它不安全。

答案 1 :(得分:1)

您可以使用sscanf,但首先需要为dataheaderbody分配内存。

data = malloc(sizeof(AT_msg_Data));
if(data==NULL){
      // handle error
 }
data->header = malloc(10);
if(data->header==NULL){
      // handle error
 }

data->body = malloc(20);
if(data->body==NULL){
      // handle error
 }

然后像这样使用sscanf -

 if(sscanf(__rx_data,"%[^+]+%[^\r]\r",data->header,data->body)==2){     // if sscanf is successful 
   //do something
  }

在此data->header之后,ATdata->bodyCGMI将来自字符串{。}}。