确定C++数组的正确大小

3

我需要根据文件中的字节数来设置数组的大小。

例如,我想要这样做:

// Obtain the file size.
    fseek (fp, 0, SEEK_END);
    size_t file_size = ftell(fp);
    rewind(fp);

// Create the buffer to hold the file contents.
    char buff[file_size];

然而,我遇到了编译时错误,提示缓冲区的大小必须是一个常量。如何解决这个问题?
5个回答

10

使用向量。

std::vector<char> buff(file_size);
整个向量首先会自动填充 '\0',但性能损失可能并不明显。这当然更安全、更舒适。然后像普通数组一样访问它。甚至可以将指向数据的指针传递给遗留的 C 函数。
legacy(&buff[0]); // valid!

是的,std::vector 是一个不错的选择。但我不明白他的代码为什么会失败。他基本上是在声明一个变长数组,我没有看到任何非法的地方?当我在 GCC 中尝试时它可以工作。 - Hans W
1
这是合法的 C99 代码,但不是合法的 C++98 代码。 - Raphaël Saint-Pierre
3
@Hans:可变长度数组是C99的特性。然而,C++是基于C89的。因此它们不是C++的特性。 - sbi
RaphaelISP 和 sbi:感谢你们的澄清,我不确定变长数组是否已被包含在C++ 中。我现在也注意到,如果使用“-pedantic”调用GCC,则会出现此类警告。 - Hans W

2

你应该使用 std::vector 而不是数组。

真正的数组需要你指定它们的大小,这样编译器才能为它们创建一些空间 -- 这就是为什么当你没有提供一个常量整数时编译器会报错的原因。动态数组由指向数组基址的指针表示 -- 你必须自己检索动态数组的内存。然后你可以使用下标符号访问指针。例如:

int * x;
x = (int *) malloc( sizeof(int) * 
                    getAmountOfArrayElements() /* non-const result*/ 
                  );
x[5] = 10;

这会导致两种问题:
  1. 缓冲区溢出/下溢:您可能会在数组的任一端之外进行下标索引。

  2. 您可能会忘记释放内存。

如果使用正确,向量提供了一个很好的接口来隐藏这些问题。

3
这段内容标记为 C++。你应该使用 new 而不是 malloc()。但是一旦你确保所有的异常都得到了处理,最好还是使用 std::vector... - sbi
2
@Hassan:我不会因为一个微不足道的原因而投反对票,但我认为在C++程序中使用malloc()并不是微不足道的。这在1991年Scott Meyers的第一版《Effective C++》中就被建议避免使用了——我认为最新版甚至都没有提到它,因为现在这已经是一个众所周知的规则了。 - sbi
当您想要在线程本地内存上分配对象时,您会怎么做?试图将该功能塞入“new”中吗? - Hassan Syed
如果这是为多核嵌入式设备而设计的,并且公司不允许您使用STL,那么您仍然会坚持使用new吗?分配是一个概念,您使用编码约定要求的内容...但是因为我选择使用c idom来说明我的回复而将一个完全有效的响应标记为错误是不合适的。 - Hassan Syed
2
在这种情况下,你已经非常清楚自己在做什么,而且也没有其他选择,所以通常的“不要这样做”的规则并不适用 :-) 但是,对于一般情况来说,提倡使用malloc仍然有点违反不成文的规则。 - Raphaël Saint-Pierre
显示剩余3条评论

1

替换

char buff[file_size];

使用

char *buff = new char[file_size];

一旦使用缓冲区完成,您可以使用以下方法释放内存:

delete[] buff;

2
不要这样做。在这里使用new []而不是std::vector没有好的理由。 - Jerry Coffin
我要点踩,因为没有提到“向量”,抱歉。答案不应该建议使用原始内存处理,而应该使用标准类型。这会鼓励不良编程习惯。 - GManNickG

1

你的问题有两个点我想要解答。

  1. 实际问题,如何创建数组。Johannes已经回答了这个问题。你可以使用std::vector并分配大小来创建它。
  2. 你的错误信息。当你声明某种类型的数组时,必须使用常量大小进行声明。例如:

    const int FileSize = 1000;

    // stuff

    char buffer[FileSize];

这是完全合法的。

另一方面,你所做的尝试声明一个具有可变大小的数组,然后没有使用new进行分配,会生成错误。


-3
问题在于需要在堆上创建缓冲区(而不是栈上)。编译器需要知道要在栈上创建的确切大小。
char* buff = new char[file_size];

2
在这里使用new[]而不是std::vector没有任何理由。 - Jerry Coffin
问题是设置数组的大小,而不是向量。我同意向量更好,但那是另一个问题。为什么会被踩呢? - RvdK
2
我进行了点踩,因为在这种(或几乎任何)情况下使用new[]根本不是一个好建议。是的,问题使用了“数组”这个词--如果他知道应该问关于“向量”,那么他就不需要问了。很明显,他想要的是一些数据存储--同样清楚的是,new[]不是获取它的好方法。 - Jerry Coffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接