将文件内容读入动态分配的char *数组 - 我可以读入std :: string吗?

时间:2016-07-31 19:21:37

标签: c++ arrays string c++11

我发现自己编写的代码看起来像这样

// Treat the following as pseudocode - just an example

iofile.seekg(0, std::ios::end); // iofile is a file opened for read/write
uint64_t f_len = iofile.tellg();

if(f_len >= some_min_length)
{
    // Focus on the following code here
    char *buf = new char[7];
    char buf2[]{"MYFILET"}; // just some random string
                            // if we see this it's a good indication
                            // the rest of the file will be in the
                            // expected format (unlikely to see this
                            // sequence in a "random file", but don't
                            // worry too much about this)
    iofile.read(buf, 7);

    if(memcmp(buf, buf2, 7) == 0) // I am confident this works
    {
        // carry on processing file ...
        // ...
        // ...
    }
}
else
    cout << "invalid file format" << endl;

这段代码可能是打开文件时我们可能想要做的一个好的草图,该文件有一些指定的格式(我已经指定了)。我们做了一些初步检查,以确保字符串"MYFILET"位于文件的开头 - 因为我已经确定我所做的工作的所有文件都将从这个序列开始字符。

我认为如果我们不必使用&#34; c-style&#34;那么这段代码会更好。字符数组,但在任何地方都使用字符串。 这将是有利的,因为我们可以执行if(buf == buf2) bufbuf2 std::string s。

可能的替代方案是,

// Focus on the following code here
std::string buf;
std::string buf2("MYFILET"); // very nice
buf.resize(7); // okay, but not great
iofile.read(buf.data(), 7); // pretty awful - error prone if wrong length argument given
                            // also we have to resize buf to 7 in the previous step
                            // lots of potential for mistakes here,
                            // and the length was used twice which is never good
if(buf == buf2) then do something

这有什么问题?

  • 我们必须使用长度变量7(或在这种情况下为常量)两次。这是介于&#34;不理想&#34;并且&#34;可能容易出错&#34;。
  • 我们必须使用buf访问.data()的内容,我假设这里实现了返回某种原始指针。 我个人不太介意,但其他人可能更喜欢更安全的内存解决方案,也许暗示我们应该使用某种迭代器?我认为在Visual Studio中(对于Windows用户我不是),这可能会返回一个迭代器,这会给出[?]警告/错误[?] - 对此不确定。
  • 我们必须为buf添加额外的调整大小声明。如果buf的大小可以以某种方式自动设置,那会更好。

5 个答案:

答案 0 :(得分:2)

写入const char*返回的std::string::data()是未定义的行为。但是,您可以这种方式自由使用std::vector::data()

如果你想使用std :: string,并且不喜欢自己设置大小,你可以考虑是否可以使用std::getline()。这是免费功能,而不是std::istream::getline()std::string版本将读取到指定的分隔符,因此如果您有文本格式,则可以告诉它在'\0'或其他一些永不发生的字符之前读取,并且它将自动调整给定的大小用于保存内容的字符串。

如果您的文件本质上是二元文件,而不是文字,我认为大多数人会发现std::vector<char>std::string更自然。

答案 1 :(得分:1)

  

我们必须使用长度变量7(或在这种情况下为常数)两次。   这介于“不理想”和“可能容易出错”之间。

第二次使用buf.size()

iofile.read(buf.data(), buf.size());
  

我们必须使用.data()来访问buf的内容   假设这里实现了返回某种原始指针。

John Zwinck指出,.data()返回指向const的指针。

我想您可以将buf定义为std::vector<char>;对于vector(如果我没错),.data()会返回指向char(在这种情况下)的指针,而不是const char

size()resize()的工作方式相同。

  

我们必须为buf添加一个额外的resize语句。这将是   如果可以以某种方式自动设置buf的大小,那就更好了。

我认为read()不允许这样做。

p.s:抱歉我的英语不好。

答案 2 :(得分:0)

template<class Src>
std::string read_string( Src& src, std::size_t count){
  std::string buf;
  buf.resize(count);
  src.read(&buf.front(), 7); // in C++17 make it buf.data()
  return buf;
}

现在auto read = read_string( iofile, 7 );在使用时很干净。

buf2是一个糟糕的计划。我做了:

if(read=="MYFILET")

直接使用,或使用const char myfile_magic[] = "MYFILET";

答案 3 :(得分:0)

我们可以在没有双缓冲(rdbuf和字符串)的情况下验证签名并从堆中分配...

// terminating null not included
constexpr char sig[] = { 'M', 'Y', 'F', 'I', 'L', 'E', 'T' };     
auto ok = all_of(begin(sig), end(sig), [&fs](char c) { return fs.get() == (int)c; });
if (ok) {}

答案 4 :(得分:0)

我喜欢上面例子中的许多想法,但我并不完全满意,有一个答案可以为C ++ 11和C ++生成不定义的行为代码17。我目前在C ++ 11中编写了大部分代码 - 因为我不希望将来在的机器上使用它,它没有C ++ 11编译器。

如果没有,那么我添加一个新的编译器或更改机器。

然而,在我看来,编写一些我知道可能无法在C ++下工作的代码确实是个坏主意......这只是我个人的意见。我不希望再次使用此代码,但我不希望将来为自己制造潜在的问题。

因此我提出了以下代码。 我希望其他用户会提供反馈以帮助改善这一点。(例如,目前还没有错误检查。)

std::string
fstream_read_string(std::fstream& src, std::size_t n)
{
    char *const buffer = new char[n + 1];
    src.read(buffer, n);
    buffer[n] = '\0';
    std::string ret(buffer);
    delete [] buffer;
    return ret;
}

这似乎是一个基本的,可能是万无一失的方法......很遗憾,似乎没有办法让std :: string使用与{{1}调用分配的内存相同的内存}。

注意我们必须在C风格的字符串中添加一个额外的尾随空字符,该字符在C ++风格的new中被切掉。