【问题标题】:Memory error when copying parts of string using strtok使用 strtok 复制部分字符串时出现内存错误
【发布时间】:2013-11-20 19:22:23
【问题描述】:

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

无论如何,这就是我遇到的问题。此函数正在从配置文件中读取用户指定的字符串(这就是第一行中发生的事情)。该字符串是一个逗号分隔的列表,包含由冒号分隔的数字对,如下所示:

    int:float, int:float, int:float

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

这是我的代码:

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++ memory-management strtok


    【解决方案1】:

    对于 C 字符串,它需要在字符串末尾的终止空字符,所以对于你的代码:

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

    终止的空字符没有附加字符串“比率”,这会导致其他函数出现问题。例如,函数'strcpy()',如果你检查函数的实现,它会检查源字符串的终止空字符来决定复制过程是否完成。所以如果没有终止空字符,就会导致内存错误。

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 感谢您的快速回复!额外的字符是空终止符?我坚持使用 C 风格的字符串,因为这是一个更大(和更旧)项目的一部分。我尝试为 index_token 和 value_token 分别分配一个额外的字符,但这并没有解决问题。
      • 哦,没关系,我想通了。我也忘了在比率中添加一个字节。谢谢!
      猜你喜欢
      • 2021-01-25
      • 2014-01-21
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      相关资源
      最近更新 更多