如何在不使用臨時變量的情況下交換兩個指針的值。通過交換值我指的是存儲在每個指針中的地址。指針可以是任何類型,如int。這是高通的面試問題。據我所知,只有指針才允許減法,我們不能執行任何其他的算術運算。交換指針值
交換指針值
回答
這是一個解決方案,適用於amd64(又名x86_64)或任何其他64位系統,其中高16位地址位未使用(此要求未在代碼中檢查!)。
#include <cassert>
#include <cstring>
#include <iostream>
// swap two pointers without using any additional space
// this is really a terrible idea and should never be used
template <typename T>
void ptr_swap(T*& p1, T*& p2)
{
// this only works on amd64, where the high 16 address bits are unused
static_assert(sizeof(T*) == 8, "only works on amd64");
// swap Nth pair of bytes
#define PTR_SWAP_PAIR(N) \
memcpy((char*)&p1 + 6, (char*)&p2 + N, 2); \
memcpy((char*)&p2 + N, (char*)&p1 + N, 2); \
memcpy((char*)&p1 + N, (char*)&p1 + 6, 2); \
PTR_SWAP_PAIR(0);
PTR_SWAP_PAIR(2);
PTR_SWAP_PAIR(4);
// restore amd64 pointer invariant (sign extension)
p1 = (T*)(((intptr_t)p1 << 16) >> 16);
}
int main()
{
int a = 1234567890;
int b = 999777555;
int* pa = &a;
int* pb = &b;
ptr_swap(pa, pb);
assert(pa == &b);
assert(pb == &a);
std::cout << *pa << '\n';
std::cout << *pb << '\n';
}
關於高16個地址位作爲可用作高速暫存序號:Using the extra 16 bits in 64-bit pointers
如果您想了解對於上述生成的彙編代碼:
movzx eax, WORD PTR [rsi]
mov WORD PTR [rdi+6], ax
movzx eax, WORD PTR [rdi]
mov WORD PTR [rsi], ax
movzx eax, WORD PTR [rdi+6]
mov WORD PTR [rdi], ax
movzx eax, WORD PTR [rsi+2]
mov WORD PTR [rdi+6], ax
movzx eax, WORD PTR [rdi+2]
mov WORD PTR [rsi+2], ax
movzx eax, WORD PTR [rdi+6]
mov WORD PTR [rdi+2], ax
movzx eax, WORD PTR [rsi+4]
mov WORD PTR [rdi+6], ax
movzx eax, WORD PTR [rdi+4]
mov WORD PTR [rsi+4], ax
movzx eax, WORD PTR [rdi+6]
mov WORD PTR [rdi+4], ax
mov eax, 16
shlx rax, QWORD PTR [rdi], rax
sar rax, 16
mov QWORD PTR [rdi], rax
對戰使用std::swap()
:
mov rax, QWORD PTR [rdi]
mov rdx, QWORD PTR [rsi]
mov QWORD PTR [rdi], rdx
mov QWORD PTR [rsi], rax
所以是的,太可怕了。
編輯:這是一個被@阿杰的回答生成的彙編:
mov rax, QWORD PTR [rdi]
xor rax, QWORD PTR [rsi]
mov QWORD PTR [rdi], rax
xor rax, QWORD PTR [rsi]
mov QWORD PTR [rsi], rax
xor QWORD PTR [rdi], rax
相比std::swap()
,它花費兩個額外的指令並保存一個寄存器(rdx
)。
LOL,我印象非常深刻:) – ThingyWotsit
這種簡單的方法將工作,照顧類型轉換。在我的機器中,它的指針大小等於很長。
#include <stdio.h>
int main()
{
int *x = malloc(sizeof(int)), *y = malloc(sizeof(int));
printf("Before Swap x: %p y: %p \n", x, y);
// if x= 5 & y = 10,
// then code to swap 'x' (1010) and 'y' (0101)
x = (int*)((uintptr_t)x^(uintptr_t)y); // x = x^y, now x becomes 15 (1111)
y = (int*)((uintptr_t)x^(uintptr_t)y); // y = x^y, y becomes 10 (1010)
x = (int*)((uintptr_t)x^(uintptr_t)y); // x = X^y, x becomes 5 (0101)
printf("After Swapping: x = %p, y = %p", x, y);
return 0;
}
如果使用'uintptr_t'而不是'long',則可以避免一些可移植性問題。 –
@JohnZwinck我更新了答案 – Ajay
它很美。我將相應的彙編代碼發佈到我的答案中。 –
- 1. 交換指針指針
- 2. 交換指針
- 3. 交換指針
- 4. C++交換指針
- 5. 交換方法指針
- 6. 用指針交換變量
- 7. 指針交換奇怪
- 8. 混亂交換指針
- 9. memcpy vs指針交換?
- 10. 切換指針/值
- 11. C語言:如何交換指針與交換指向的值不同?
- 12. 使用交換函數void指針
- 13. 使用XOR交換兩個指針
- 14. C++:交換向量和指針失效?
- 15. 交換字符只給指針
- 16. 在C中交換雙指針
- 17. 交換函數 - 指針 - 混淆
- 18. 如何使用指針交換項目
- 19. 使用指針交換對象
- 20. 使用指針交換字符變量
- 21. 帶指針的基本整數交換
- 22. 使用boost :: swap交換原始指針?
- 23. 交換實現指針在C
- 24. 使用指針交換結構
- 25. 與nullptr原子交換指針
- 26. 交換指針而不是memcpy
- 27. 交換/交換指針時未定義的行爲
- 28. 指針值C空指針
- 29. 有沒有其他方法將交換指針的地址交換爲交換值?
- 30. 用公用指針交換指向已分配內存的指針
這些問題的關鍵不在於你知道你給他們的一些答案,而是你聰明地理解了這個問題並展示知識和命令。 –
所以你希望我們幫你在面試中作弊? – Borgleader
@DavidSchwartz無論是這個,還是面試官都沒有線索。我的錢是在第二天,每週的任何一天。 –