What makes pointers faster than arrays?

时间:2023-01-15 10:41:38

I was googling and found the following syntax for pointers

我在Google上搜索并找到了以下指针语法

  void main()
 {
  char a[10]="helloworld";
  char *p=a;
  printf("%c",p[0]);
 }

I didnt know that Pointers can be accessed in the array form too. I used to use * for pointer operations I used a[0] for arrays and *p for pointer operations, which is why I didnt know the other 2 things. Now from the above, we can access the second element of array in any one of the following ways

我不知道Pointers也可以以数组形式访问。我曾经使用*作为指针操作我使用[0]表示数组,* p表示指针操作,这就是为什么我不知道其他两件事。从上面可以看出,我们可以通过以下任何一种方式访问​​数组的第二个元素

  printf("%C",a[1]);   \\ this is the array
  printf("%c",*(a+1));  \\ this is the array using *
  printf("%c", p[1]);     \\ using the pointer 
  printf("%C",*(p+1));    \\ using the pointer

Now I wonder: which is the faster operation? I read that operations using pointers are faster, and that this is why C stays at the top for fast execution and that no other language can beat its fastness.

现在我想知道:哪个操作更快?我读到使用指针的操作更快,这就是为什么C保持在顶部以便快速执行并且没有其他语言能够超越其坚固性的原因。

Now the real question: What makes the pointer operations faster?

现在真正的问题是:什么使指针操作更快?

1) *(p+0) the *(Value at address) that makes the trick or

1)*(p + 0)*(地址的值)制作技巧或

2) p[0]

since we use

因为我们使用

 *(a+1) or *(p+1) both are same 
  a[1] or p[1] both are same 

when a normal array can be used as *(a+1)( which uses * value at address) like a pointer. why do we use pointers for faster operations? When both have the same syntax, when normal array and pointer uses * in those syntaxes why pointers are faster?

当一个普通数组可以用作*(a + 1)(在地址中使用*值)时,就像指针一样。为什么我们使用指针来加快操作?当两者具有相同的语法时,正常数组和指针在这些语法中使用*时为什么指针更快?

But guys please tell me then why we use pointers ? My professor told me pointers are faster because they point to address rather a variable should be searched in the location.

但伙计们请告诉我为什么我们使用指针?我的教授告诉我指针更快,因为它们指向地址而不是应该在该位置搜索变量。

6 个解决方案

#1


8  

I wouldn't actually expect *(ptr + offset) to be faster than ptr[offset]. In fact, on my machine, the following functions are compiled into exactly the same assembly code:

我实际上不希望*(ptr + offset)比ptr [offset]快。事实上,在我的机器上,以下函数被编译成完全相同的汇编代码:

int
ArrayRef(int* array, int index)
{
    return array[index];
}

int
PointerRef(int* array, int index)
{
    return *(array + index);
}

which (cleaned up) looks like:

哪个(清理过)看起来像:

ArrayRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

PointerRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

(gcc 4.5.0, x86_64, no optimisations). Or with -O3

(gcc 4.5.0,x86_64,没有优化)。或者使用-O3

ArrayRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

PointerRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

#2


3  

Array access is faster if the array is allocated in the local stack scope or in static memory since it can be directly accessed via an offset of the value in the EBP register or via a direct offset from a fixed address, rather than attempting to access the value of a pointer in a stack variable, and then adding to that variable's value and dereferencing.

如果阵列在本地堆栈作用域或静态存储器中分配,则阵列访问速度更快,因为它可以通过EBP寄存器中的值的偏移量或通过固定地址的直接偏移量直接访问,而不是尝试访问堆栈变量中指针的值,然后添加到该变量的值并解除引用。

For instance, if you write you array like:

例如,如果你写的数组如下:

int main()
{
    int array[5] = {1, 2, 3, 4, 5};
    //... more code

    return 0;
}

In order to access the value at array[3], the complier will only issue a simple command like (this is for x86):

为了访问数组[3]中的值,编译器只会发出一个简单的命令(这适用于x86):

MOV -8(%ebp), %eax

This is because if we look at the stack, we would see the following:

这是因为如果我们查看堆栈,我们会看到以下内容:

EBP + 4 : Return Address
EBP     : Previous function's stack activation record
EBP - 4 : array[4]
EBP - 8 : array[3]
EBP - 12: array[2]
EBP - 16: array[1]
EBP - 20: array[0]

So in order to access the value at array[3], only one instruction is needed. That's very fast.

因此,为了访问数组[3]的值,只需要一条指令。那很快。

#3


1  

In the examples that you provided, p[1] will not be faster than a[1].

在您提供的示例中,p [1]不会比[1]快。

#4


0  

An array name is essentially the pointer to the first element of that array - so, they should be pretty much the same.

数组名称本质上是指向该数组的第一个元素的指针 - 因此,它们应该几乎相同。

Statically created arrays have their own type which incorporates their compile-time defined size which makes them different than pointers technically, but for all intensive purposes the array name and the character pointer in your example can be used identically.

静态创建的数组有自己的类型,它包含了编译时定义的大小,这使得它们在技术上与指针不同,但是出于所有密集的目的,示例中的数组名称和字符指针可以相同地使用。

#5


0  

Array is a pointer, there is no difference between p and a after

数组是指针,p和a之后没有区别

char a[10]="helloworld";
char *p=a;

both a and p are a pointer to char and they are pointing to the same place - beginning of your array in memory.

a和p都是指向char的指针,它们指向同一个地方 - 数组在内存中的开头。

using "operator []" is equivalent to pointer arithmetic too

使用“operator []”也等同于指针算术

a[i] 

will be substituted to

将被替换为

*(a+i)

it means that pointer to the beginning of the array will be shifted by i*sizeof(char) to the place of i-th element of your array.

这意味着指向数组开头的指针将被i * sizeof(char)移动到数组的第i个元素的位置。

The real difference in time appears when you try loop over all elements, for example, copy the string:

当您尝试遍历所有元素时,会出现真正的时间差异,例如,复制字符串:

char a[10] = "helloworld";
char b[10];
for (int i = 0; i < 10; ++i) b[i] = a[i]; // using array element accessing method

will produce arithmetic like b+i (aka b shift by i*sizeof(char) ) and a+i (aka a shift by i*sizeof(char) ) for each iteration of loop, and

对于循环的每次迭代,将产生类似b + i(又名为b by i * sizeof(char))和a + i(也称为i * sizeof(char)的移位)的算术,以及

char a[10] = "helloworld";
char b[10];
char *_a, *_b;
for (_a = a, _b = b; *_a != '\0'; ++_a, ++_b) *_a = *_b; // using pointers arithmetic method
*b = '\0';

is free from this those calculations, you only shift two pointers by size of char each time.

从这些计算中解脱出来,每次只能按char的大小移动两个指针。

#6


-1  

Pointers being faster than arrays is coming from the following example.

指针比数组更快来自以下示例。

Say you want to implement the strcpy function, i.e. copy one null-terminated string to another. Let's look at two examples:

假设您要实现strcpy函数,即将一个以空字符结尾的字符串复制到另一个字符串。我们来看两个例子:

First one:

char* strcpy(char* dest, const char* src)
{
    int i = 0;
    while( src[i] != '\0' ) {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';

    return dest;
}

Second one:

char* strcpy(char* dest, const char* src)
{
    char *save = dest;
    while( *src != '\0' )
    {
        *dest++ = *src++;
    }
    *dest = '\0';

     return save;
}

The second example is implemented more efficiently, cause it does less memory modifications in each iteration, and it uses pointers instead of arrays. But there are two things:

第二个示例更有效地实现,因为它在每次迭代中执行的内存修改更少,并且它使用指针而不是数组。但有两件事:

  1. It's not pointers which are fast, it's algorithm using them for optimization.
  2. 它不是快速的指针,它是使用它们进行优化的算法。

  3. Optimizer can easily perform this kind of optimization automatically, so you probably end up with the same generated code anyway.
  4. 优化器可以轻松地自动执行这种优化,因此您最终可能会得到相同的生成代码。

#1


8  

I wouldn't actually expect *(ptr + offset) to be faster than ptr[offset]. In fact, on my machine, the following functions are compiled into exactly the same assembly code:

我实际上不希望*(ptr + offset)比ptr [offset]快。事实上,在我的机器上,以下函数被编译成完全相同的汇编代码:

int
ArrayRef(int* array, int index)
{
    return array[index];
}

int
PointerRef(int* array, int index)
{
    return *(array + index);
}

which (cleaned up) looks like:

哪个(清理过)看起来像:

ArrayRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

PointerRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

(gcc 4.5.0, x86_64, no optimisations). Or with -O3

(gcc 4.5.0,x86_64,没有优化)。或者使用-O3

ArrayRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

PointerRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

#2


3  

Array access is faster if the array is allocated in the local stack scope or in static memory since it can be directly accessed via an offset of the value in the EBP register or via a direct offset from a fixed address, rather than attempting to access the value of a pointer in a stack variable, and then adding to that variable's value and dereferencing.

如果阵列在本地堆栈作用域或静态存储器中分配,则阵列访问速度更快,因为它可以通过EBP寄存器中的值的偏移量或通过固定地址的直接偏移量直接访问,而不是尝试访问堆栈变量中指针的值,然后添加到该变量的值并解除引用。

For instance, if you write you array like:

例如,如果你写的数组如下:

int main()
{
    int array[5] = {1, 2, 3, 4, 5};
    //... more code

    return 0;
}

In order to access the value at array[3], the complier will only issue a simple command like (this is for x86):

为了访问数组[3]中的值,编译器只会发出一个简单的命令(这适用于x86):

MOV -8(%ebp), %eax

This is because if we look at the stack, we would see the following:

这是因为如果我们查看堆栈,我们会看到以下内容:

EBP + 4 : Return Address
EBP     : Previous function's stack activation record
EBP - 4 : array[4]
EBP - 8 : array[3]
EBP - 12: array[2]
EBP - 16: array[1]
EBP - 20: array[0]

So in order to access the value at array[3], only one instruction is needed. That's very fast.

因此,为了访问数组[3]的值,只需要一条指令。那很快。

#3


1  

In the examples that you provided, p[1] will not be faster than a[1].

在您提供的示例中,p [1]不会比[1]快。

#4


0  

An array name is essentially the pointer to the first element of that array - so, they should be pretty much the same.

数组名称本质上是指向该数组的第一个元素的指针 - 因此,它们应该几乎相同。

Statically created arrays have their own type which incorporates their compile-time defined size which makes them different than pointers technically, but for all intensive purposes the array name and the character pointer in your example can be used identically.

静态创建的数组有自己的类型,它包含了编译时定义的大小,这使得它们在技术上与指针不同,但是出于所有密集的目的,示例中的数组名称和字符指针可以相同地使用。

#5


0  

Array is a pointer, there is no difference between p and a after

数组是指针,p和a之后没有区别

char a[10]="helloworld";
char *p=a;

both a and p are a pointer to char and they are pointing to the same place - beginning of your array in memory.

a和p都是指向char的指针,它们指向同一个地方 - 数组在内存中的开头。

using "operator []" is equivalent to pointer arithmetic too

使用“operator []”也等同于指针算术

a[i] 

will be substituted to

将被替换为

*(a+i)

it means that pointer to the beginning of the array will be shifted by i*sizeof(char) to the place of i-th element of your array.

这意味着指向数组开头的指针将被i * sizeof(char)移动到数组的第i个元素的位置。

The real difference in time appears when you try loop over all elements, for example, copy the string:

当您尝试遍历所有元素时,会出现真正的时间差异,例如,复制字符串:

char a[10] = "helloworld";
char b[10];
for (int i = 0; i < 10; ++i) b[i] = a[i]; // using array element accessing method

will produce arithmetic like b+i (aka b shift by i*sizeof(char) ) and a+i (aka a shift by i*sizeof(char) ) for each iteration of loop, and

对于循环的每次迭代,将产生类似b + i(又名为b by i * sizeof(char))和a + i(也称为i * sizeof(char)的移位)的算术,以及

char a[10] = "helloworld";
char b[10];
char *_a, *_b;
for (_a = a, _b = b; *_a != '\0'; ++_a, ++_b) *_a = *_b; // using pointers arithmetic method
*b = '\0';

is free from this those calculations, you only shift two pointers by size of char each time.

从这些计算中解脱出来,每次只能按char的大小移动两个指针。

#6


-1  

Pointers being faster than arrays is coming from the following example.

指针比数组更快来自以下示例。

Say you want to implement the strcpy function, i.e. copy one null-terminated string to another. Let's look at two examples:

假设您要实现strcpy函数,即将一个以空字符结尾的字符串复制到另一个字符串。我们来看两个例子:

First one:

char* strcpy(char* dest, const char* src)
{
    int i = 0;
    while( src[i] != '\0' ) {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';

    return dest;
}

Second one:

char* strcpy(char* dest, const char* src)
{
    char *save = dest;
    while( *src != '\0' )
    {
        *dest++ = *src++;
    }
    *dest = '\0';

     return save;
}

The second example is implemented more efficiently, cause it does less memory modifications in each iteration, and it uses pointers instead of arrays. But there are two things:

第二个示例更有效地实现,因为它在每次迭代中执行的内存修改更少,并且它使用指针而不是数组。但有两件事:

  1. It's not pointers which are fast, it's algorithm using them for optimization.
  2. 它不是快速的指针,它是使用它们进行优化的算法。

  3. Optimizer can easily perform this kind of optimization automatically, so you probably end up with the same generated code anyway.
  4. 优化器可以轻松地自动执行这种优化,因此您最终可能会得到相同的生成代码。