我正在測驗“用 C 掌握演算法(Kyle Loudon)”中的鏈表示例
在示例中,使用 void** 引數的函式的操作出現了錯誤。操作錯誤如下代碼。
代碼:
#include <stdio.h>
void myswap(void **val1, void **val2)
{
void **val3;
*val3 = *val1;
*val1 = *val2;
*val2 = *val3;
}
int main()
{
int val1 = 10;
int val2 = 20;
printf("%d, %d\n", val1, val2);
myswap((void **)&val1, (void **)&val2);
printf("%d, %d\n", val1, val2);
return 0;
}
結果:
10, 20
0, 10 <- must be 20, 10
這似乎是由變數大小和指標大小之間的差異引起的錯誤。這可以通過使用 long 變數而不是 int 變數或通過在 main() 中的兩個變數之間創建填充變數來解決。(我使用的是 64 位系統。因此,指標和長型別的大小為 64 位。)
但是,我想知道如何在不修改已經撰寫的示例的變數、結構和函式的情況下解決它。如果有可能。
如果有人知道這個問題,請幫助
uj5u.com熱心網友回復:
您不能取消參考 void 指標。它是 GCC 擴展,底層型別是 unsigned char。要獲得整數,您需要正確型別的指標。
您需要一個指標來傳遞一個指向它的指標。在我的示例中,我使用復合文字
void myswap(void **val1, void **val2)
{
int val3;
int **i1 = (int **)val1;
int **i2 = (int **)val2;
val3 = **i1;
**i1 = **i2;
**i2 = val3;
}
int main()
{
int val1 = 10;
int val2 = 20;
printf("%d, %d\n", val1, val2);
myswap(&(void *){&val1}, &(void *){&val2});
printf("%d, %d\n", val1, val2);
return 0;
}
你確實需要雙指標。如果您嘗試創建通用交換功能:
void myswap(void *val1, void *val2, size_t size)
{
unsigned char val3[size];
memcpy(val3, val1, size);
memcpy(val1, val2, size);
memcpy(val2, val3, size);
}
int main(void)
{
int val1 = 10;
int val2 = 20;
double d1 = 1.0;
double d2 = 2.0;
printf("%d, %d\n", val1, val2);
myswap(&val1, &val2, sizeof(val1));
printf("%d, %d\n\n", val1, val2);
printf("%f, %f\n", d1, d2);
myswap(&d1, &d2, sizeof(d1));
printf("%f, %f\n", d1, d2);
return 0;
}
你可以用它交換任何物件。陣列,結構,聯合等。
uj5u.com熱心網友回復:
使用 構建gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0,您的函式在取消參考未初始化myswap時會引發分段錯誤(參見陳述句)。val3*val3 = *val1
如果myswap' 的目標是val1對所指(和相反)的內容提出觀點val2,那么代碼應該是:
void myswap(void **val1, void **val2)
{
void *tmp;
tmp = *val1;
*val1 = *val2;
*val2 = tmp;
}
這樣,您的代碼將列印預期10, 20和20, 10訊息。
但是,它仍然以“ *** stack smashing detected ***: terminated”和abort (core dumped)錯誤訊息結尾。
這是由于錯誤的傳遞方式val1和val2函式引數myswap。
該myswap函式將val1(resp. val2) 視為一個雙指標變數,它指向一個void *地址(它本身指向其他東西)。
在main背景關系中,&val1是指向int變數的東西,而不是void *內容!
因此,當myswap運行一個操作時,*val1 = ...如果不同,就會出現問題(x86_64 架構就是這種情況)。sizeof(int)sizeof(void*)
所以,你可以做 3 件事:
- 使用
intptr_t(fromstddint.h) 代替int,因為intptr_t與 具有相同的大小void *。
但這不適用于非整數變數(即int main() { intptr_t val1 = 10; intptr_t val2 = 20; printf("%ld, %ld\n", (signed long)val1, (signed long)val2); myswap((void **)&val1, (void **)&val2); printf("%ld, %ld\n", (signed long)val1, (signed long)val2); return 0; }struct,float...),您不能保證變數大小與void * - 使用中間指標,并切換它們:
但這保持int main() { int val1 = 10; int val2 = 20; int * ptr1 = &val1; int * ptr2 = &val2; printf("%d, %d\n", *ptr1, *ptr2); myswap((void **)&ptr1, (void **)&ptr2); printf("%d, %d\n", *ptr1, *ptr2); return 0; }val1和val2變數不變,這可能不是你想要的。 - 使用
memcpyandsizeof,正如@0___________所建議的那樣。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/506501.html
