为什么C支持负数组索引?

时间:2013-08-11 14:18:06

标签: c arrays pointers

从SO this帖子中可以看出,C支持负指数。

  1. 为什么在程序中支持这种潜在的内存冲突?

  2. 编译器不应该至少抛出负指数警告吗? (我正在使用GCC)

  3. 或者这个计算是在运行时完成的吗?

  4.   

    编辑1:任何人都可以暗示它的用途吗?

         

    编辑2:表示3.)在[]数组/指针中使用循环计数器表示指数的运行时计算。

8 个答案:

答案 0 :(得分:17)

计算在运行时完成。

否定指数不一定必须导致违规,并且有其用途。

例如,假设您有一个指针,该指针当前指向数组中的第10个元素。现在,如果您需要在不更改指针的情况下访问第8个元素,则可以使用负索引-2轻松地执行此操作。

char data[] = "01234567890123456789";
char* ptr = &data[9];
char c = ptr[-2]; // 7

答案 1 :(得分:11)

以下是使用示例。

无限脉冲响应滤波器部分地根据最近的先前输出值计算。通常,会有一些输入值数组和一个放置输出值的数组。如果当前输出元素是y i ,则y i 可以计算为y i = a 0 • x i + a 1 •x i-1 + a 2 •y i-1 < / sub> + a 3 •y i-2

为此编写代码的一种自然方式是:

void IIR(float *x, float *y, size_t n)
{
    for (i = 0; i < n; ++i)
        y[i] = a0*x[i] + a1*x[i-1] + a2*y[i-1] + a3*y[i-2];
}

观察到当i为零时,y[i-1]y[i-2]具有否定索引。在这种情况下,调用者负责创建一个数组,将输出的初始两个元素设置为“起始值”(通常为零或从前一个缓冲区保留的值),并将指针传递给第一个新值的位置是要写的。因此,这个例程IRR通常会接收一个指向数组中间的指针,并使用负索引来处理某些元素。

答案 2 :(得分:8)

  

为什么在程序中支持这种潜在的内存冲突?

因为它遵循指针算术,在某些情况下可能有用。

  

编译器不应该至少抛出负指数警告吗? (我正在使用海湾合作委员会)

当数组只有10个元素时,当您访问array[10]时编译器不会发出警告的原因相同。因为它将这项工作留给了程序员。

  

或者这个计算是在运行时完成的吗?

是的,计算是在运行时完成的。

答案 3 :(得分:5)

阐述Taymon的答案:

float arr[10];
float *p = &arr[2];

p[-2]

现在完全可以。我没有看到负面指数的良好使用,但是如果你指向一个有效范围之外,如果它通常是不可判定的,那么为什么标准会将其排除。

答案 4 :(得分:3)

数组下标只是用于解除指向内存中任意位置的指针的语法糖。编译器无法警告您有关负索引的信息,因为它在编译时不知道指针指向的位置。任何给定的指针算术表达式可能会也可能不会产生有效的内存访问地址。

答案 5 :(得分:3)

OP:为什么支持......潜在的内存违规?

它有潜在的用途,因为OP表示它是潜在违规而不是某些内存违规。 C是关于允许用户做很多事情,包括他们自己挂起所需的所有绳索。

OP:......抛出负面指数警告......

如果担心,请使用unsigned索引或更好,请使用size_t

OP ...在运行时完成计算?

是的,常见于a[i],其中i不是常数。

OP:暗示它的用途?

示例:一个正在处理点阵列(Pt)中的点,并且想要确定中点是否是共同事件的候选者。假设调用函数已经确定Mid既不是第一个也不是最后一个点。

static int IsCoincident(Pt *Mid) {
  Pt *Left = &Mid[-1];   // fixed negative index
  Pt *Right = &Mid[+1]; 
  return foo(Left, Mid, Right);
} 

答案 6 :(得分:0)

a[b]*(a+b)做同样的事情。由于后者允许负b,前者也是如此。

答案 7 :(得分:0)

使用负数组索引的示例。

我使用负索引来检查消息协议。例如,一种协议格式如下:

<nnn/message/f>

或者同样有效:

<nnn/message>

参数f是可选的,如果提供,则必须为单个字符。

如果我想获得字符f的值,我首先要获得一个指向>字符的指针:

char * end_ptr = strchr(msg, '>');
char f_char = '1';  /* default value */    

现在,我检查是否提供了f并将其提取(这里是使用负数组索引的位置):

if (end_ptr[-2] == '/')
{
    f_char = end_ptr[-1];
}

请注意,我省略了错误检查和其他与此示例无关的代码。