在 C 语言中,什么时候最好使用其中一个而不是另一个?
6 回答
这实际上是风格和编码约定的问题,因为在 Cp[i]
中被定义为与*(p+i)
wherep
是指针和i
整数索引相同。AFAIK 你甚至可以写i[p]
,但这很丑陋。
这在 C++ 中并不总是正确的(它赋予了您定义operator []
等的能力......)。
我个人不喜欢手工编码&p[i]
,更喜欢p+i
这种情况。
这通常取决于具体情况。我认为没有经验法则。
在某些情况下,数组索引更好。例如,当您分配了一个数组时
char* ptr = malloc(SIZE);
并且您需要ptr
不更改的值,因为您想稍后释放它,然后您可以使用索引。
或者,如果您将指针作为函数参数
void func(char* ptr)
并且您需要遍历数组,然后您可以增加指针本身,并且您不需要创建一个新变量来用作索引。
但是,在大多数情况下,这取决于您自己的喜好。
“数组索引”只是包装“指针算法”的语法糖。它纯粹是装饰性的,只是另一种表示法,这意味着使用一个或另一个将是个人喜好问题。
通常隐藏在您所问问题背后的真正问题是何时使用随机访问以及何时使用顺序访问(“指针算术”意味着指针的顺序递增/递减不超过 1)。答案是:尽可能使用顺序访问,仅在必须时使用随机访问。
只要性能不受影响,依靠最小的需求集来实现算法总是一个更好的主意。随机访问是比顺序访问更强的要求,这意味着应在合理可能的情况下避免前者。
在性能方面,最好使用指针算法(至少禁用编译器优化),因为在迭代数组时,您不必增加单独的变量。另见 K&R 第 97 页(第二版)。
否则,这只是编码风格的问题。
当编译时不知道数据结构的大小时,指针很有用。例如,当您不知道字符串的长度是多少,或者您期望有多少个整数等时。在这种情况下,指针可以根据需要动态分配内存。
另一方面,数组降低了灵活性。
但是,除了这种差异之外,还有更多。
根据 MISRA C++ 2008(规则 5-0-15):数组索引应是指针算术的唯一形式。
但这条规则有一个例外:
递增/递减运算符可用于由指向数组的指针实现的迭代器
template < typename IterType >
uint8_t sum_values ( IterType iter, IterType end )
{
uint8_t result = 0;
while ( iter != end )
{
result += *iter;
++iter; // Compliant by exception
}
return result;
}
void my_fn ( uint8_t * p1, uint8_t p2[ ] )
{
uint8_t index = 0;
uint8_t * p3;
uint8_t * p4;
*p1 = 0;
++index;
index = index + 5;
p1 = p1 + 5; // Non-compliant – pointer increment
p1[ 5 ] = 0; // Non-compliant – p1 was not declared as array
p3 = &p1[ 5 ]; // Non-compliant – p1 was not declared as array
p2[ 0 ] = 0;
p2[ index ] = 0; // Compliant
p4 = &p2[ 5 ]; // Compliant
}
uint8_t a1[ 16 ];
uint8_t a2[ 16 ];
my_fn ( a1, a2 );
my_fn ( &a1[ 4 ], &a2[ 4 ] );
uint8_t a[ 10 ];
uint8_t * p;
p = a;
*( p + 5 ) = 0; // Non-compliant
p[ 5 ] = 0; // Compliant
sum_values ( &a1[ 0 ], &a1[ 16 ] );