2010-02-09 90 views
8

我想交換對象的作業問題,使用void指針交換對象。我的函數的聲明必須是:使用指針交換對象

void swap(void *a, void *b, size_t size); 

我不是在尋找確切的代碼如何做到這一點,所以我可以通過我自己看着辦吧,但我不知道如果我理解正確。我發現有一個問題在做:

void *temp; 
temp = a; 
a = b; 
b = temp; 

只改變指針指向什麼。那是對的嗎?如果它是正確的,爲什麼不交換指針實際上改變了* a和* b之間的內容。因爲如果你的指針指向不同的東西,你不能解除引用它,並且對象現在會不同嗎?

類似的,只是切換的值,如:

void *temp; 
*temp = *a; 
*a = *b; 
*b = *temp; 

是不正確要麼,我不知道爲什麼。因爲在我看來,內容已被切換。

交換對象意味着完全交換內存和指針指向的值的值嗎?

因此,我似乎必須使用malloc爲我的交換分配足夠的空間。如果我爲一個對象分配足夠的內存,假設它們具有相同的大小,我真的不知道它與上述其他兩種方法有什麼不同。

void *temp = malloc(sizeof(pa)); 
// check for null pointer 
temp = a; 
// do something I'm not sure of since I don't quite get how allocating space is any 
// different than the two above methods??? 

謝謝!

+1

你靠近。不過,引用'void *'是不允許的。想想你可能會移動信息的其他方式,特別是考慮「size」參數以及對算法有什麼影響。 – 2010-02-09 21:39:55

+0

更改指針是一個不錯的嘗試,但不會工作,因爲它們是按值傳遞的。因此調用者在調用之前在指針中將具有相同的值。 – 2010-02-09 23:43:57

回答

19

交換三分球不改變指向的值。如果是這樣的話,那就像是將信封上的地址標籤交換到我的房子和你的房子裏。

你幾乎有:

void swap(void *a, void *b, size_t size) { 
    char temp[size]; // C99, use malloc otherwise 
    // char serves as the type for "generic" byte arrays 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 
} 

memcpy函數副本存儲器,這是在C中的對象的定義(稱爲POD或純醇」數據在C++中,要比較)以這種方式, memcpy的是你怎麼做任務,而無需關心對象的類型,你甚至可以寫其他任務的memcpy的,而不是:

int a = 42, b = 3, temp; 

temp = b; 
b = a; 
a = temp; 
// same as: 
memcpy(&temp, &b, sizeof a); 
memcpy(&b, &a, sizeof a); 
memcpy(&a, &temp, sizeof a); 

這也正是上述功能做什麼,因爲當你做,你不能使用賦值不知道對象的類型,和v oid是代表「未知」的類型。 (當用作函數返回類型時,它也意味着「沒有」。)


作爲一種好奇心,另外它避免了常見的情況malloc和不使用C99的VLAS版本:

void swap(void *a, void *b, size_t size) { 
    enum { threshold = 100 }; 
    if (size <= threshold) { 
    char temp[threshold]; 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 
    } 
    else { 
    void* temp = malloc(size); 
    assert(temp); // better error checking desired in non-example code 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 

    free(temp); 
    } 
} 
+1

正確的想法,但它是memcpy(dest,src,size); – 2010-02-09 21:43:33

+0

+1用於避免'alloca'的誘惑! – 2010-02-09 22:02:21

+0

@Earwicker:如果我要使用C89以外的東西,我寧願它是C99而不是alloca。:) – 2010-02-09 22:16:42

0

要改變裏面的指針並將它保持在外面,必須通過引用或雙指針來傳遞指針。

如果你的函數必須是這樣的:

void swap(void *a, void *b, size_t size); 

我想,你必須實現這樣的:

void * temp; 
temp = malloc(size); 
memcpy(temp,a,size); 
memcpy(a,b,size); 
memcpy(b,temp,size); 
free(temp); 
1

首先,注意裏面的任何改變指針函數不會傳播到函數外部。所以你將不得不移動內存。

要做到這一點,最簡單的方法是用memcpy - 棧,memcpy合適的尺寸從a進去,memcpyba,並且最後一個memcpy從臨時到b上分配的緩衝區。

0

爲了有任何實際效果,你需要做你提到的第二塊相當於:

void *temp; 
*temp = *a; 
*a = *b; 
*b = *temp; 

這裏的問題是,「無效」沒有大小,所以你不能分配'虛空',因爲他們的立場。您需要爲temp分配空間以指向,然後使用類似memcpy()的值複製值。

+0

cant deref void * – pm100 2010-02-09 21:44:36

+0

@ pm100 - 他在答案中實際解釋了這一點。 – 2010-02-09 21:46:00

+1

@ pm100:與編譯器不同,您需要注意代碼*和*註釋! – 2010-02-09 21:47:35

2

參數與局部變量類似,在函數開始執行之前將值複製到它們中。這個原型:

void swap(void *a, void *b, size_t size); 

意味着兩個地址複製到被稱爲ab新的變數。因此,如果您更改ab中存儲的內容,則在返回swap後,您所做的任何操作都不會有任何效果。

1

如果你正在編寫一個交換兩個整數的函數,給定了它們的指針,你交換指向的值的解決方案將工作。然而,考慮

struct { 
    int a; 
    int b; 
} a, b; 

swap(&a, &b, sizeof(a)); 

你需要想出一個辦法來交換而不他們實際上包含的任何知識傳遞的每個值的內容的情況。

3

要回答你的第一個問題,接下來讓我們看看一些值,看看發生了什麼:

void* a = 0x00001000; // some memory address 
void* b = 0x00002000; // another memory address 
/* Now we'll put in your code */ 
void* temp; // temp is garbage 
temp = a; // temp is now 0x00001000 
a = b; // a is now 0x00002000 
b = temp; // b is now 0x00001000 

因此,在這些語句的結束,指針的值被交換,那就是,無論a指着現在指向b,反之亦然。這些指針指向的未被修改,只是現在它們的內存地址被不同的指針保存。

要回答你的第二個問題,你不能取消引用void*。原因是void沒有大小,因此嘗試解除引用或分配給沒有大小的內容是無意義的。因此,void*是一種保證你可以指向東西,但你永遠不會知道什麼東西是沒有更多的信息(因此size參數到您的例程)。

從那裏,知道指針和指針指向的數據的大小,可以使用例如memcpy這樣的例程將指針指向的數據移動到另一個指針所指向的位置。

1

你很近。

的問題是:你是「交換」只有指針一個b這是在函數的局部變量。

我承擔的功能之外,你有一些變量,我們姑且稱之爲:

void *x = ...; 
void *y = ...; 

當你撥打:

swap(x, y, some_size); 

一個b指向相同的對象xy。現在,當你交換什麼一個b點過,Xÿ仍然指向他們指向哪裏之前。

要改變什麼內存Xÿ點,你將有一個指針傳遞給X變量,因此指針的指針:)

因爲你不能改變函數的聲明您只能交換x(和a)和y(和b)指向的內存的內容。一些解決方案是在其他答案:)通常memcpy是你想要的。

2

我有一個類似於我的C課程的問題。我覺得存儲器複製可能是最好的,但你也可以試試這個:

typedef unsigned char * ucp; 

    void swap(void *a, void *b, int size){ 
     ucp c=(ucp)a; 
     ucp d=(ucp)b; 
     for(int i=0; i<size; i++){ 
     int temp=(int)c[i]; 
    c[i]=(int)d[i]; 
    d[i]=temp; 
     } 

    } 

基本上這樣做是既投指針unsigned char類型指針類型。然後你增加指針,在無符號字符的情況下,每次增加一個字節。然後你在做的是基本上一次拷貝每個字節的內容到內存中。如果有人想糾正或澄清這一點,我也會很感激。

0

我們不必使用memcpy用於交換兩個指針,下面的代碼工作井(測試交換INT *與char *字符串):

void swap(void **p, void **q) 
{ 
    void *t = *p; 
    *p = *q; 
    *q = t; 
}