代码之家  ›  专栏  ›  技术社区  ›  Stowelly

非常奇怪的字符数组行为

c++
  •  0
  • Stowelly  · 技术社区  · 16 年前

    .

     unsigned int fname_length = 0;
    //fname length equals 30
    file.read((char*)&fname_length,sizeof(unsigned int));
    //fname contains random data as you would expect
    char *fname = new char[fname_length];
    //fname contains all the data 30 bytes long as you would expect, plus 18 bytes of      random data on the end (intellisense display)
    file.read((char*)fname,fname_length);
    //m_material_file (std:string) contains all 48 characters
    m_material_file = fname;
    // count = 48
    int count = m_material_file.length();
    

    现在,当尝试这种方法时,IntelliSense在将char数组设置为all“”之后仍然显示18个字节的数据,并且得到完全相同的结果。即使没有读取文件

    char name[30];
    for(int i = 0; i < 30; ++i)
    {
      name[i] = ' ';
    }
    file.read((char*)fname,30);
    m_material_file = name; 
    int count = m_material_file.length();
    

    你知道这里出了什么问题吗,可能是很明显的事情,但我被难住了!

    谢谢

    5 回复  |  直到 16 年前
        1
  •  3
  •   Bruce    16 年前

    听起来文件中的字符串不是以空结尾的,IntelliSense假定它是。或者,当您将字符串(30)的长度写入文件时,您可能没有在该计数中包含空字符。尝试添加:

    fname[fname_length] = '\0';
    

    在file.read()之后。哦,是的,你也需要分配一个额外的字符:

    char * fname = new char[fname_length + 1];
    
        2
  •  1
  •   Nikolai Fetissov    16 年前

    我猜IntelliSense正在试图解释 char* 作为C字符串,正在查找 '\0' 字节。

        3
  •  1
  •   Michael Burr    16 年前

    fname 是一个 char* 所以调试器显示和 m_material_file = fname 将以\0'终止。您从来没有显式地这样做,但是不管后面的数据是什么,内存缓冲区在某个点上有一个零字节,所以您不会崩溃(这在某个点上可能是一种情况),而是得到一个比您期望的长的字符串。

        4
  •  1
  •   avakar    16 年前

    使用

    m_material_file.assign(fname, fname + fname_length);
    

    这就不再需要零终止符了。还有,更喜欢 std::vector 原始数组。

        5
  •  1
  •   D.Shawley    16 年前

    std::string::operator=(char const*) 要求一个字节序列以 '\0' . 您可以通过以下任一方法解决此问题:

    1. 延伸 fname 按字符并添加 ‘0’ 正如其他人所建议的那样
    2. 使用 m_material_file.assign(&fname[0], &fname[fname_length]); 相反
    3. 使用重复呼叫 file.get(ch) m_material_file.push_back(ch)

    我个人会使用最后一个选项,因为它完全消除了显式分配的缓冲区。少一个明确的 new 是少一次泄露内存的机会。下面的代码段应该完成这项工作:

    std::string read_name(std::istream& is) {
        unsigned int name_length;
        std::string file_name;
        if (is.read((char*)&name_length, sizeof(name_length))) {
            for (unsigned int i=0; i<name_length; ++i) {
                char ch;
                if (is.get(ch)) {
                    file_name.push_back(ch);
                } else {
                    break;
                }
            }
        }
        return file_name;
    }
    

    注:

    你可能不想用 sizeof(unsigned int) 确定写入二进制文件的字节数。读/写的字节数取决于编译器和平台。如果您有一个最大长度,那么使用它来确定要写出的具体字节大小。如果保证长度小于255个字节,则只写一个字节作为长度。那么您的代码将不依赖于内部类型的字节大小。