[英]What makes pointers faster than arrays?
我在Google上搜索並找到了以下指針語法
void main()
{
char a[10]="helloworld";
char *p=a;
printf("%c",p[0]);
}
我不知道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
現在我想知道:哪個操作更快? 我讀到使用指針的操作更快,這就是為什么C保持在頂部以便快速執行並且沒有其他語言能夠超越其堅固性的原因。
現在真正的問題是:什么使指針操作更快?
1)*(p + 0)*(地址的值)制作技巧或
2)p [0]
因為我們使用
*(a+1) or *(p+1) both are same
a[1] or p[1] both are same
當一個普通數組可以用作*(a + 1)(在地址上使用*值)時,就像指針一樣。 為什么我們使用指針來加快操作? 當兩者具有相同的語法時,正常數組和指針在這些語法中使用*時為什么指針更快?
但伙計們請告訴我為什么我們使用指針? 我的教授告訴我指針更快,因為他們指向地址而不是應該在該位置搜索變量。
我實際上不希望*(ptr + offset)
比ptr[offset]
快。 實際上,在我的機器上,以下函數被編譯成完全相同的匯編代碼:
int
ArrayRef(int* array, int index)
{
return array[index];
}
int
PointerRef(int* array, int index)
{
return *(array + index);
}
哪個(清理過)看起來像:
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,沒有優化)。 或者使用-O3
ArrayRef:
movslq %esi, %rsi
movl (%rdi,%rsi,4), %eax
ret
PointerRef:
movslq %esi, %rsi
movl (%rdi,%rsi,4), %eax
ret
如果陣列在本地堆棧作用域或靜態存儲器中分配,則陣列訪問速度更快,因為它可以通過EBP
寄存器中的值的偏移量或通過固定地址的直接偏移量直接訪問,而不是嘗試訪問堆棧變量中指針的值,然后添加到該變量的值並解除引用。
例如,如果你寫的數組如下:
int main()
{
int array[5] = {1, 2, 3, 4, 5};
//... more code
return 0;
}
為了訪問array[3]
的值,編譯器只會發出一個簡單的命令(這是針對x86):
MOV -8(%ebp), %eax
這是因為如果我們查看堆棧,我們會看到以下內容:
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]
因此,為了訪問array[3]
的值,只需要一條指令。 那很快。
在您提供的示例中, p[1]
不會比a[1]
快。
數組名稱本質上是指向該數組的第一個元素的指針 - 因此,它們應該幾乎相同。
靜態創建的數組有自己的類型,它包含了編譯時定義的大小,這使得它們在技術上與指針不同,但是對於所有密集的目的,示例中的數組名稱和字符指針可以相同地使用。
數組是指針, p和a之后沒有區別
char a[10]="helloworld";
char *p=a;
a和p都是指向char的指針,它們指向同一個地方 - 數組在內存中的開頭 。
使用“operator []”也等同於指針算術
a[i]
將被替換為
*(a+i)
這意味着指向數組開頭的指針將被i * sizeof(char)移動到數組的第i個元素的位置。
當您嘗試遍歷所有元素時,會出現真正的時間差異,例如,復制字符串:
char a[10] = "helloworld";
char b[10];
for (int i = 0; i < 10; ++i) b[i] = a[i]; // using array element accessing method
對於循環的每次迭代,將產生類似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';
從這些計算中解脫出來,每次只能按char的大小移動兩個指針。
比數組更快的指針來自以下示例。
假設您要實現strcpy
函數,即將一個以null結尾的字符串復制到另一個字符串。 我們來看兩個例子:
第一:
char* strcpy(char* dest, const char* src)
{
int i = 0;
while( src[i] != '\0' ) {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return dest;
}
第二個:
char* strcpy(char* dest, const char* src)
{
char *save = dest;
while( *src != '\0' )
{
*dest++ = *src++;
}
*dest = '\0';
return save;
}
第二個示例更有效地實現,因為它在每次迭代中執行的內存修改更少,並且它使用指針而不是數組。 但有兩件事:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.