【问题标题】:Integer number as char* for dummies整数作为 char* 的假人
【发布时间】:2011-07-29 13:04:24
【问题描述】:

问题之前一直在问,但我对最好的方法还是有点茫然。我有一个整数,想获得一个 char* 用作结构的成员。

类似的问题例如 herehere。 我宁愿不使用 stringstream 或 lexical_cast。据我所知,基本上只剩下 itoa、sprintf 和 snprintf。

我想我的部分问题是我不太了解 char 指针是如何工作的。

  1. 如果我请求char str[12],它会保留 12 个字符吗?
  2. 我推测内存已经被分配了?
  3. 那么空终止是如何工作的呢?
  4. 是在 12 个字符的末尾(有空格填充?),或者 如果数字仅使用 2 个字符,是否会出现在两个字符之后?
  5. 缓冲区大小是否重要,或者我应该只使用一些最大值吗 (我相信 32 位是 30 左右)?
  6. 如果我稍后在一个简单的结构中使用指针,内存 自动清除还是需要析构函数?
  7. 析构函数是否需要知道初始化缓冲区的大小?
  8. 为什么没有人费心从 实际数量?
  9. 是否推荐使用 snprintf 而不是 itoa?

谢谢

【问题讨论】:

  • 为什么要求严格?您应该阅读本文以消除指针和数组之间的混淆。 stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c
  • char* 在第三方结构定义中。我自己不使用它们(正如您可能从问题中看出的那样)。
  • 简化您的生活:使用std::stringstd::stringstream。另请参阅std::string::c_str()

标签: c++ string integer itoa


【解决方案1】:

如果我请求一个 char str[12],它会保留 12 个字符吗?

是的,这会在 堆栈 上保留 12 个字符(字节)。

我推测内存已经被分配了?

str 现在指向已在堆栈上分配的 12 字节连续内存的开头。

那么空终止是如何工作的呢?是在 12 个字符的末尾(有空格填充?),还是如果数字只使用 2 个字符,会在两个字符之后发生吗?

在这种情况下,您必须自己对字符串进行空终止(这种类型的声明不会自动发生)。

因此,如果您想让str 保存一些(以空结尾的)字符串值,您可以执行以下操作:

str[0] = 'c';
str[1] = 'a';
str[2] = 't';
str[3] = '\0';

获取以 null 结尾的字符串的另一种方法是执行以下操作:

char *str = "cat"; // this is null-terminated

没有自动填充空格。

如果我稍后在简单结构中使用指针,内存会自动清除还是需要析构函数?

如果指针指向栈上分配的一块内存,那么出栈时内存会被回收。否则,如果你在堆上分配内存如:

char *newStr    = new char[12];
char *mallocStr = (char*) malloc(sizeof(char) * 12);

然后您将不得不使用deletefree 取消分配内存(取决于您使用的方法)。

析构函数是否需要知道初始化缓冲区的大小?

在这种情况下,我们谈论的是堆分配内存,因此答案是否定的。系统知道分配了多少内存。这就是为什么您只需将指针指向deletefree 而无需提供大小。

为什么没有人费心根据实际数字计算缓冲区长度?

如果您知道您的号码永远不会超过一定数量(例如,4 位数字),您可以这样做,但通常只给出可能的最大长度会更容易,因为最终您只会浪费几个字节字符串,这没什么大不了的,除非你有一些非常严格的内存限制。

是否推荐使用 snprintf 而不是 itoa?

我会说是的,因为 snprintf 被认为是“安全的”,因为它尊重您给它的缓冲区大小,而 itoa 会很高兴地填充您的缓冲区而不检查它的大小(可能运行超过分配的空间并覆盖其他记忆)。

int   num = 12345;
char *str = new char[4];

// this is bad because str is not big enough to hold the number
// itoa does not check buffer size and will overrun the buffer (overwriting other data)
str = itoa(num, str);

// snprintf takes the buffer size as one of it's arguments
// in this case the whole number will not fit, but at least we don't overrun the buffer
snprintf(str, 4, "%i", num);

snprintfitoa 都会为您的字符串以空值结尾。

【讨论】:

  • snprintf 应该是这样,但是有一些错误的实现,即使它可以防止初始缓冲区溢出,它也不能正确地为空终止。
【解决方案2】:

如果你真的不想使用std::stringstreamlexical_cast,你应该使用snprintf,因为它有一个缓冲区大小参数。 itoa 不是 ISO C 函数。

Null(字符 '\0',值 0)可以出现在缓冲区中的任何位置,大多数处理字符串的函数会忽略该点之后缓冲区中的所有内容,因此这是一种“浪费”的空间。

假设你有类似的东西

char str[] = { 'a', 'b', 'c', '\0', 'd' };

即使 printf 这样的函数在遇到 0 时停止处理数据,最后一个元素仍然存在。但并非每个函数都这样做。

数组(或任何其他原始数据类型)没有构造函数或析构函数。如果您使用newnew[]malloc 或类似的方式自行分配,您只需要担心释放分配的内存。

缓冲区大小当然很重要,如果它太小就无法容纳数字的每个字符,如果它太大,就会浪费内存。 22 个字符应该能够容纳每个 64 位整数(但不能容纳浮点数/双精度数!)。

最好的选择是使用std::stringstreamstd/boost::lexical_caststd::string,它会为您解决所有这些问题。

我建议您阅读 Martinho 的链接,非常有用。 (数组不是指针!)

【讨论】:

    猜你喜欢
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    相关资源
    最近更新 更多