使用strtok复制字符串部分时出现内存错误

Memory error when copying parts of string using strtok

本文关键字:内存 错误 分时 strtok 复制 字符串部 使用      更新时间:2023-10-16

因此,我可以看到strtok似乎是一个备受鄙视的函数,但它确实非常适合我在这个特定实例中的需求,如果可能的话,我希望避免重写整个函数。当然,如果strtok真的走了,我愿意接受它必须走的事实。

不管怎样,这就是我的问题。这个函数从配置文件中读取用户指定的字符串(这就是第一行中发生的内容)。该字符串是一个逗号分隔的列表,包含由冒号分隔的数字对,如下所示:

    int:float, int:float, int:float

我想以某种方式存储这些值,将它们相互映射,int是关键点,float是值。只要第一个int只有一个数字,或者存在多个int:foat对,我为实现这一点而编写的代码就可以按照我希望的方式工作。如果字符串只有一个int:foat对,而第一个int是两位数字,那么函数会执行几次而不会出现问题,但最终垃圾会被读取到index_token和ratio_token字符串中,程序会出错。如果我在valgrind中运行程序,就不会发生这种情况,所以这一定是某种内存错误。每次执行此函数时,字符串都会从文件中新鲜读取。当我打印出const_ratios和ratio时,它们每次都是应该的。

这是我的代码:

const char * const_ratios = m_world->GetConfig().NON_1_RESOURCE_RATIOS.Get();
cout << "Const_ratios: " << const_ratios;
char * ratios = new char[strlen(const_ratios)]; #make non const version of ratios
strcpy(ratios, const_ratios);                   #so that I can use strtok
cout << ", Ratios: " << ratios;
map<int, float> ratioMap;
char * ratio_tokens = strtok((char *)ratios, ",:");
while (ratio_tokens != NULL){
  char * index_token = new char[strlen(ratio_tokens)];
  strcpy(index_token, ratio_tokens);
  cout <<", Index token: " << index_token;
  ratio_tokens = strtok(NULL, ",:");
  char * value_token = new char[strlen(ratio_tokens)];
  strcpy(value_token, ratio_tokens);
  cout << ", Value token: " << value_token << endl;
  ratioMap[atoi(index_token)] = atof(value_token);
  ratio_tokens = strtok(NULL, ",:");

有人知道为什么会发生这种事吗?我想这一定与strtok有关(也许与strcpy有关),但我看不出我缺少了什么。

对于C字符串,它需要在字符串末尾使用终止的null字符,因此您可以编写代码:

char * ratios = new char[strlen(const_ratios)]; 
strcpy(ratios, const_ratios);

终止的null字符没有附加字符串"ratio",这将导致其他函数出现问题。例如,函数"strcpy()",如果您检查该函数的实现,它会检查源字符串的终止null字符,以决定复制过程是否完成。因此,如果没有终止null字符,就会导致内存错误。

所以上面的代码应该是这样的:

int n = strlen(const_ratios) +1
char * ratios = new char[n]; 
strcpy(ratios, const_ratios);
ratios[n-1] = ''

您没有分配足够的内存。您分配了strlen(ratio_tokens),但随后又复制了一个字节。这是C样式字符串的一个烦恼——C样式总是比字符串中的字符数大一个字节。既然您使用C++进行编码,为什么不使用std::string呢?