【问题标题】:Atoi / Atol - results in 0 [duplicate]Atoi / Atol - 结果为0 [重复]
【发布时间】:2013-09-09 20:09:10
【问题描述】:

我正在构建快速的“配置阅读器”,它可以从文件中读取设置。 问题是,该函数返回“800”字符串,而带有该输入的 atol 返回 0。我不确定自己做错了什么。

所以,大致是这样的:

char *txtval=GetParamFromLine("WINDOW_WIDTH");
val = atol(txtval); 

char* GetParamFromLine(char*parameter)
{
   char text[16];
   //
   // do the reading procedure and fill the text
   //
   return text;
}

结果:atol(text) = 0(其中 text = "800" )

感谢您的帮助!

【问题讨论】:

  • 你确定为 NULL 以终止 GetParamFromLine() 中的字符串吗?
  • 您正在从 GetParamFromLine 返回指向局部变量(文本)的指针。
  • 正如 Eugen 指出的那样,您正在返回一个指向在使用时不再存在的局部变量的指针。您不应提供错误和误导性的信息。 text 不是 "800"。以后使用调试器。
  • C++ 标签,有效吗?如果是,则按值返回 std::string,问题就解决了。不要在 C++ 程序中乱用 C 风格的字符串(没有很好的理由)。或者如果您仅限于 C,请删除 c++ 标签。
  • ...当然,忘记atol。如果需要使用 C 标准库函数,请使用strtol

标签: c


【解决方案1】:

您需要将“文本”存储在堆而不是堆栈上。否则,当函数结束时,变量会超出范围,并且您将在尝试访问该内存段时出现未定义的行为。您可以在堆上分配内存,然后在完成后释放它,

char *txtval=GetParamFromLine("WINDOW_WIDTH");
val = atol(txtval); 
free txtval;

// Caller is responsible for freeing returned buffer
char* GetParamFromLine(char*parameter)
{
   char text* = malloc(sizeof(char)*16);
   //
   // do the reading procedure and fill the text
   //
   return text;
}

或者传递一个指向应该存储结果的缓冲区的指针。

char txtval[16];
GetParamFromLine("WINDOW_WIDTH", txtval);
val = atol(txtval); 

void GetParamFromLine(char *parameter, char *resultBuffer)
{
   //
   // do the reading procedure and fill the text into resultBuffer
   //
}

【讨论】:

  • sizeof(char) 将始终为 1。
  • 由于这个问题被标记为 C++,因此您应该认真考虑返回 std::string
  • @IInspectable:这应该是一个答案,而不是评论。
  • 该解决方案似乎更好。好的,我只是忘记了那个变量范围......再次感谢:)
【解决方案2】:

您正在返回一个指向本地范围变量的指针。内存text在函数调用后超出范围,因此指向它的指针没有意义,因为内存将被回收......

您需要为text 分配一些长期存储空间,或者将GetParamFromLineatol 合并到同一个函数中。

【讨论】:

  • 我不确定“永久存储”是否正确。你可以只返回 strdup(text)。
  • +1 建议将atol 合并到GetParamFromLine,但我建议为此创建一个新函数:GetLongParamFromLine
  • 是的,这是我的意图,但我会有很多函数:GetLongFromLine GetStringFromLine GetFloatFromLine 所以我想获取参数值并随心所欲地处理它。
【解决方案3】:

使文本静态:

char* GetParamFromLine(char*parameter)
{
    static char text[16];
    ... do something
    return text;
}

您的版本正在使用堆栈驻留版本,在使用之前可能会被覆盖。静态存储类说明符确保

返回的缓冲区只会在下一次调用 GetParameterFromLine 之前有效。

一般来说,调用者最好将缓冲区和缓冲区大小作为参数提供给这样的函数。

char *GetParamFromLine(const char *parameter, char *text, size_t text_size)
{
    ... do something
    return text;
}

“做某事”代码应仔细观察该大小。您必须决定是否截断参数、返回一个空字符串、返回一个 NULL 指针,或者如果实际数据比缓冲区长的话。

【讨论】:

  • 或者,将目标缓冲区作为参数传递。
  • 并希望没有人在多线程上下文中调用任何此代码。
  • 非常感谢 Mike,这解决了我的问题 :)
  • 或者返回 strdup(text);或使用 std::string
  • @mvp “不要那样做!” 是教条主义的。不要那样做!
【解决方案4】:

问题是由返回一个指向局部变量的指针引起的。当函数GetParamFromLine 返回变量text 时超出范围。返回的指针不再有效,导致未定义的行为。您必须以其他方式返回数据,例如:

std::string txtval=GetParamFromLine("WINDOW_WIDTH");
val = atol(txtval.c_str());

std::string GetParamFromLine(char*parameter)
{
   char text[16];
   //
   // do the reading procedure and fill the text
   //
   return std::string(text);
}

将返回类型从指向局部变量的指针更改为std::string 缓解了返回指向局部变量的指针的问题。 std::string使用的资源由​​对象管理,自动清理。

作为替代方案,您也可以删除 atol 调用并改用 std::istringstream。一个好处是这样可以更好地报告错误:

std::string txtval=GetParamFromLine("WINDOW_WIDTH");
std::istringstream iss(txtval);
int val( 0 );
iss >> val;

现在,如果您真的想更上一层楼,您可以将字符串检索和转换为整数数据类型结合起来,并参数化这个新函数模板的返回类型:

template<typename T>
T GetValueFromLine(const std::string& param) {
    std::string txtval=GetParamFromLine(param.c_str);
    std::istringstream iss(txtval);
    T val = T();
    iss >> val;
    return val;
}

使用此模板,您可以执行以下操作:

long wndWidth = GetValueFromLine<long>("WINDOW_WIDTH");
bool showInfo = GetValueFromLine<bool>("SHOW_INFO");
....

注意:省略错误处理。

【讨论】:

  • 这似乎也是个好主意。非常感谢您的解决方案和解释。
猜你喜欢
  • 2012-10-09
  • 1970-01-01
  • 1970-01-01
  • 2016-05-17
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多