4

我有一大块代码,旨在获取一个数组并完成它。在当前项目中只有一个元素,因此我没有将变量更改为 char,而是将其声明为 char array[1]。这样我就不需要修改我的代码和冒险添加任何错误,并且可以在需求增长时轻松增加它。

它似乎可以编译,但我对引擎盖下发生的事情感到好奇,我是在浪费内存吗?这是否会增加额外的处理时间,编译器会优化它,所以如果我输入它也不会有什么不同?

任何人都可以用这种方式解释使用数组的任何可能的缺点。

我使用c和c ++,它们之间有什么不同吗?

4

4 回答 4

9

听起来是个不错的策略,而且没有缺点。您绝对不会在 C 或 C++ 中浪费内存。大小为 1 的数组占用的内存与相同类型的变量占用的内存相同。

编译器可能会生成微观上效率较低的代码,但这真的不值得担心。

于 2013-09-27T10:36:31.467 回答
7

该标准说您可以获取不是数组的对象的地址并将其视为大小为 1 的数组(因此您可以获取指向过去的指针)。

请参阅 C++11 标准的第 5.7.4 节:

对于这些运算符,指向非数组对象的指针的行为与指向长度为 1 的数组的第一个元素的指针相同,该数组的元素类型为对象的类型。

于 2013-09-27T10:41:59.853 回答
3

首先,您的代码是有效的,但如果您关心缺点,我可以看到下面列出的问题:

使用数组,当您不小心循环数组时,您会增加通过越界访问访问它的机会。

另一个缺点是数组不与多态性交互。有时您尝试将派生对象存储到基本类型的数组中,对象将被切片而您可能没有注意到。

所以我不会写 array[1] 代码。希望这能回答你的一些问题。

于 2013-09-27T10:58:16.270 回答
0

在这里,我们面临 2 块代码。

  • 一大块代码,旨在获取一个数组并处理它。
  • 一段代码,它使用前一个代码块和一些数据。

结构化你的代码。

大代码块应该是一个函数,可能分为几个子函数。另一段代码将调用此函数。

函数的参数。数组或单个字符。

  (a) void work( char  c );
  (b) void work( char& c );
  (c) void work( const char v[], size_t size);
  (d) void work(       char v[], size_t size);

如果这种工作对数组没有意义,则应使用选项 (a) 和 (b)。事实并非如此。
如果工作对数组有意义,则应使用选项 (c) 和 (d)。

所以使用数组。

保存数据的变量。数组或单个字符。

如果您只需要保存一个字符,则使用单个非数组字符。您仍然可以调用数组函数。

char c;
c = 'b';
work( &c, 1 );
//////
char a[1];
a[0] = 'b';
work( a, 1 );

工作函数将单个变量和数组视为大小为 1 的数组。代码在这两种情况下都可以正常工作,并且没有效率问题。

测试

让我们看看真实的代码是否包含我之前的陈述。

#include <iostream>
#include <ctime>
#include <vector>
#include <cstddef>
#include <chrono>

using namespace std;

unsigned long miliTime()
{
    return std::chrono::system_clock::now().time_since_epoch() /
           std::chrono::milliseconds(1);
}
// An hypotetical work function with arrays
void workArray( char v[], size_t size )
{
  for ( size_t n=0; n<size; ++n )
  {
    // large block of code
    for ( int i=0; i<1000; ++i )
    {
      v[n] += 3 + i;
      if (v[n] == '3' )
        v[n] = 'J' - v[n];
      v[n] = toupper( v[n] ) + '-';
    }
  }
}

// Same function just for a single character
void workSingle( char& c )
{
  // large block of code
  for ( int i=0; i<1000; ++i )
  {
    c += 3 + i;
    if (c == '3' )
      c = 'J' - c;
    c = toupper( c ) + '-';
  }
}

int main(void)
{
  const long int repeats =1000000;
  long int n;
  unsigned long start;
  double dif;

  start = miliTime();
  char c;
  c = 'b';
  for ( n=0; n<repeats; ++n)
    workArray( &c, 1 );
  dif = miliTime() - start;
  cout << "Result = " << c << endl;
  cout << "Non-array var passed to array code = " << dif << " ms" << endl;

  start = miliTime();
  char a[1];
  a[0] = 'b';
  for ( n=0; n<repeats; ++n)
    workArray( a, 1 );
  dif = miliTime() - start;
  cout << "Result = " << a[0] << endl;
  cout << "Array var passed to array code = " << dif << "ms" << endl;

  start = miliTime();
  char c2;
  c2 = 'b';
  for ( n=0; n<repeats; ++n)
    workSingle( c2 );
  dif = miliTime() - start;
  cout << "Result = " << c2 << endl;
  cout << "Non-array var passed to non-array code = " << dif << "ms" << endl;

  start = miliTime();
  char a2[1];
  a2[0] = 'b';
  for ( n=0; n<repeats; ++n)
    workSingle( a2[0] );
  dif = miliTime() - start;
  cout << "Result = " << a2[0] << endl;
  cout << "Array var passed to non-array code = " << dif << "ms" << endl;
}

当使用此命令行在 gcc-4.7 下编译并在我的计算机中执行时:

g++ -O2 -Wall -std=c++11 x.cpp -o x.out && ./x.out

我得到这个输出:
结果 = z
传递给数组代码的非数组变量 = 5520 ms
结果 = z
传递给数组代码的数组变量 = 5515ms
结果 = z
传递给非数组代码的非数组变量 = 5203ms
结果 = z
数组变量传递给非数组代码 = 5203ms

正如预期的那样,结果总是一样的。对于两种实现,将数组或非数组变量传递给工作函数没有显着差异。

workSingle 比 workArray 快 6%。
外部循环的执行(workSingle 中不存在)不太可能是原因,因为内部循环执行了 1000 次。原因可能是由于间接访问 v[n] 比访问 c 慢。
虽然如果你在内部循环中为从 std::cin 读取的全局变量更改 1000,那么 workSingle 实际上给出的时间比 workArray 慢!

某种优化、缓存未命中或其他低级别的东西可能是原因。我不会为了 workSingle 不确定的效率而牺牲 workArray 的可重用性,除非时间如此紧迫以至于您愿意进入汇编级别。

结论。

将您的变量声明为非数组,因为它只需要包含一个字符。
将大部分代码实现为采用数组参数的函数。如果它这么大,可能会分成几个小节。

此帖子仅CC-BY-SA 3.0下向公众授权

于 2013-09-28T09:47:20.750 回答