簡體   English   中英

在 C 中取消引用和將變量的地址分配給指針變量有什么區別?

[英]What is the difference between derefencing and assigning the address of a variable to pointer variable in C?

看下面兩個代碼!

int main() {
    int a = 12;
    int *p;
    *p = a;
}

和這個代碼,

int main() {
    int a = 12;
    int *p;
    p = &a;
}

在第一段代碼中將指針解引用為 this *p = a ,在第二段代碼中,變量a的地址被設置為指針變量。

我的問題是這兩段代碼有什么區別?

在你的第一段代碼中:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

你有未定義行為嚴重的情況,因為你正在試圖做的是價值分配aint變量p目前點。 但是, p尚未分配“地址”,因此它將具有任意且無效的值! 某些編譯器可能會將p初始化為零(或NULL ),但這仍然是無效地址(在大多數系統上)。

您的第二個代碼片段是“健全的”,但就目前而言,實際上並沒有實現任何目標:

int main() {
    int a = 12;
    int *p;
    p = &a;
}

在這里,您正在為指針變量p分配一個值(即地址); 在這種情況下, p現在指向a變量(即,它的值是地址a )。

因此,如果您附加這樣的代碼(在第二個代碼段的末尾):

*p = 42;

然后打印出來的值a ,你會看到它的值已經從最初賦予改變1242

隨時要求進一步澄清和/或解釋。

聲明*pa是在內存中保留一些空間,用於第一種情況下的指針,第二種情況下a是什么(一個int )。

在這兩種情況下,如果您不將任何內容放入其中,則不會初始化它們的值。 這並不意味着其中沒有任何內容,因為這是不可能的。 這意味着它們的值是不確定的,有點“隨機”; 加載程序只是在請求時將代碼/數據放入內存中,而p占用的空間和a占用的空間都是加載時內存的任何內容(也可能是編譯時,但無論如何,未定)。

所以,你需要做一個大的風險*p = a在1的情況下,既然你問了processeur采取字節“內部” a並將它們存儲的地方p點處。 可能在您的數據段的范圍內,在堆棧中,不會立即導致問題/崩潰的某個地方,但很有可能,這可能不行!

這就是為什么說這個問題會導致“未定義行為”(UB)。

第一個不好:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

這意味着:將變量a的值放入指針p指向的位置。 但是p點是什么? 可能什么都沒有(NULL)或任何隨機地址。 在最好的情況下,它可能會導致執行錯誤,如訪問沖突或分段錯誤。 在最壞的情況下,它可以覆蓋完全未知變量的任何現有值,從而導致很難調查的問題。

第二個沒問題。

int main() {
    int a = 12;
    int *p;
    p = &a;
}

這意味着:獲取指向(現有)變量a指針並將其分配給指針p 所以,這將正常工作。

當您初始化一個指針時,您可以使用 *p 訪問指向變量的指針值而不是指向變量的地址,但不可能影響這樣的值(使用 *p=a)。 因為你試圖影響一個沒有變量地址的值。

第二個代碼是正確使用 p = &a

在 C 中取消引用和將變量的地址分配給指針變量有什么區別?

后者是前者的前提。 它們是實現指針取消引用的好處的單獨步驟。


為了解釋它們之間的區別,我們必須分別看看這些家伙是什么:


  • 什么是取消引用指針?

首先我們需要看看引用是什么。 引用是對象的標識符。 我們可以說“變量a代表12的值”。 - 因此, a是對12值的引用。

對象的標識符是對存儲在其中的值的引用。

指針也是如此。 指針就像通常的對象一樣,它們在內部存儲一個值,因此它們引用其中存儲的值。

“取消引用”是當我們“禁用”與其中的常用值的這種連接並使用p的標識符來訪問/引用與p存儲的值不同的值時。

“解引用的指針”是指簡單地,可以使用指針來訪問存儲在另一個對象,FE的值12a通過它自己的標識符而不是a

要取消引用指針, *取消引用運算符需要位於指針變量之前,例如*p


  • 什么是將變量的地址分配給指針?

我們正在實現“什么是取消引用指針?”中所述的事情,通過給指針一個另一個對象的地址作為它的值,就像我們給一個普通變量賦值一樣。

但與通常的對象初始化/賦值相反,為此我們需要使用&符號運算符,在變量之前,指針應指向其值,指針之前的*取消引用運算符必須省略,例如:

  p = &a;

Therafter,指針“指向”到存儲所需值的地址。


正確解引用指針的步驟:

首先要做的是聲明一個指針,例如:

 int *p;

在這種情況下,我們聲明了一個p的指針變量,它指向一個int類型的對象。


第二步是使用int類型對象的地址值初始化指針:

 int a = 12;
 p = &a;       //Here we assign the address of `a` to p, not the value of 12.

注意:如果你想要一個對象的地址值,就像一個普通的變量,你需要在對象之前使用&的一元運算符。


如果你已經完成了這些步驟,你最終能夠通過使用*操作符,在指針對象之前訪問指針指向的對象的值:

     *p = a;

我的問題是這兩段代碼有什么區別?

區別很簡單,第一段代碼:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

通過取消引用指針來尋址對象是無效的。 如果之前沒有進行過指針引用的引用,則不能為指針的解引用賦值。

因此,您的假設是:

在第一段代碼中,我將指針取消引用為 *p = a...

是不正確的。

在這種情況下,您根本無法使用*p = a以正確的方式解除對指針的引用,因為指針p沒有任何引用,您可以正確地解除對指針的引用。

實際上,您正在將帶有*p = a語句的a值分配到您記憶中的必殺技中。

通常,編譯器永遠不會通過沒有錯誤傳遞此。

如果他這樣做了,而您以后想要使用該值,您認為您已經通過使用指針正確分配了該值,例如printf("%d",*p)您應該得到Segmentation fault (core dumped)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM