【问题标题】:C++ Static Array Initialization - Memory IssueC++ 静态数组初始化 - 内存问题
【发布时间】:2010-06-17 22:49:58
【问题描述】:

我有一个头文件,其中包含一个静态字符数组的成员变量声明:

class ABC 
{ 
public:
static char newArray[4];
// other variables / functions
private:
void setArray(int i, char * ptr);
}

在 CPP 文件中,我将数组初始化为 NULL:

char ABC::newArray[4] = {0};

在ABC构造函数中,我需要用运行时构造的值覆盖这个值,比如整数的编码:

ABC::ABC()
{ 
int i; //some int value defined at runtime
memset(newArray, 0, 4); // not sure if this is necessary
setArray(i,newArray);
} 

...

void setArray(int i, char * value)
{
    // encoding i to set value[0] ... value [3]
}

当我从这个函数返回并打印修改后的 newArray 值时,它会打印出比数组声明中指定的 4 多得多的字符。

任何想法为什么会这样。 我只想将 char 数组设置为 4 个字符,仅此而已。

谢谢...

【问题讨论】:

    标签: c++


    【解决方案1】:

    你是怎么打印的?在 C++(和 C)中,字符串以 nul 结尾。 (\0)。如果你正在做类似的事情:

    char arr[4] = {'u', 'h', 'o', 'h'};
    std::cout << arr;
    

    它将打印“uhoh”以及它遇到的任何其他内容,直到它到达\0。您可能想要执行以下操作:

    for (unsigned i = 0; i < 4; ++i)
        std::cout << arr[i];
    

    (顺便说一句,将static 绑定到类的实例并没有什么意义。另外,你可以只做= {},尽管它不是必需的,因为static 变量无论如何都是零初始化的. 最后,不,memset 一些东西然后重写内容是没有意义的。)

    【讨论】:

    • 我认为std::cout &lt;&lt; string(arr, 4); 更漂亮,而不是循环。
    • @Stephen:是的,我只是不喜欢临时动态分配。 template &lt;typename T, size_t N&gt; std::ostream&amp; output_array(std::ostream&amp; pStream, T (&amp;pArray)[N], const std::string&amp; pFiller = "") { for (size_t i = 0; i &lt; N; ++i) pStream &lt;&lt; pArray[i] &lt;&lt; pFiller; return pStream; } 怎么样
    • 如果我没记错的话,在大多数字符串实现中,短字符串都是堆栈分配的。但是,如果您正在流式传输,您可能不会担心一点额外的 CPU 开销。 @Ben Voigt 的回答看起来很简单。
    【解决方案2】:
    cout.write(arr, count_of(arr))
    

    如果count_of 未在系统标头中定义:

    template<typename T, size_t N>
    inline size_t count_of(T (&array)[N]) { return N; }
    

    【讨论】:

    【解决方案3】:

    您是否使用类似的东西打印它

    printf("%s", newArray); //or:
    cout << newArray;
    

    ?如果是这样,您需要在字符串末尾为 nul 终止符留出空间。 C 字符串只是字符数组,因此没有字符串长度的指示;处理字符串的标准库函数期望它们以 nul (0) 字符结尾来标记结尾,因此它们将继续从内存中读取,直到找到一个。如果您的字符串需要包含 4 个字符,则需要 5 个字节宽,以便您可以将 \0 存储在第五个字节中

    【讨论】:

      【解决方案4】:

      除非您使用自定义 char-array 输出方法,否则您需要一个 0 字节的第 5 个字符来标记 4 个字符串的结尾。如果您将 value[3] 设置为 0 以外的值,您将开始在静态数据区域中的 newArray 旁边打印字节。

      也不需要显式 0 初始化静态数据。

      您可以使用 valgrind 的 memcheck 工具最好地捕捉这些类型的错误。

      【讨论】:

        【解决方案5】:

        它打印出一个字符串,该字符串从地址 &newArray[0] 开始,然后在内存中的第一个 0 结束(称为空终止符)。

        char strArr[] = {"Hello"};
        char strArr[] = {'H', 'e', "llo");
        char strArr[] = "Hello";
        char* strArr = "Hello"; // careful, this is a string literal, you can't mess with it (read-only usually)
        

        ...都是空终止的,因为双引号中的任何内容都会在末尾添加空终止符

        char strArr[] = {'H', 'e', 'l', 'l', 'o'};
        

        ...不是空终止符,单引号包含单个字符并且不添加空终止符

        以下是添加空终止符的示例...

        strArr[3] = '\0';
        strArr[3] = NULL;
        strArr[3] = 0;
        

        【讨论】:

          【解决方案6】:

          在性能稍有损失的情况下,您可以在 'c-style' 中适应 4 字节。
          打印 4 个字符或直到达到 \0:

          #include <cstdio>
          #include <cstring>
          ...
          //calculate length
          size_t totalLength = sizeof(ABC::newArray) / sizeof(ABC::newArray[0]);
          char* arrayEnd     = (char*)memchr(ABC::newArray, '\0', totalLength);
          size_t textLength  = arrayEnd != 0 ?
                               arrayEnd-ABC::newArray : totalLength;
          //print
          fwrite(
                 ABC::newArray, //source array
                 sizeof(ABC::newArray[0]), //one item's size
                 textLength, //item count
                 stdout); //destination stream
          

          顺便试试std::stringstd::cout

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-25
            相关资源
            最近更新 更多