簡體   English   中英

指針初始化給出了分段錯誤

[英]Pointer initialisation gives segmentation fault

我寫了一個C程序如下:

情況1

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

*a=11;

a=&b;/* store address of b in pointer variable*/

它在運行程序時出現分段錯誤。

我更改了代碼如下:

案例2

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

a=&b;/* store address of b in pointer variable*/

*a=11;

現在它工作正常。

如果有人知道請解釋為什么它在CASE 1中給出了分段錯誤。

CASE .1

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

*a=11;//Not valid means you are not owner of the address where a now pointing it is unknown and accessing this will segfault/

a=&b;/* store address of b in pointer variable*/

這將是分段錯誤,因為您使用的地址不是有效地址,並且您存儲的是非法的11。

                               b
      +-------+            +--------+
      |       +            |   11   |
      |Unknown|            |        |
      +---+---+            +---+----+
          |                    |
          |                    |
          +                    +
          a                    a
CASE .2

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

a=&b;/* store address of b in pointer variable*/

*a=11;

現在它的工作正常,因為b的地址是有效的,你存儲11是合法的。

以上情況也不是指針聲明的正確方法

  int *a  = NUll;
  a = malloc(sizeof(int));
  *a=5;
  free(a);//must

要么

 int *a  = NUll;
 int b;
 a = &b;
 *a=5;

這將很多次刪除分段錯誤,很難找到。

int *a; // a pointer variable that can hold a memory address of a integer value.

在案例1中,

  *a = 10; // here you have asigned 10 to unknown memory address;

它顯示分段錯誤,因為將值分配給未定義的內存地址。 未定義的行為。

在案例2中,

a=&b; // assigning a proper memory address to a.
*a=11;// assigning value to that address

考慮這個例子:

#include<stdio.h>
int main()
{
   int *a,b=10;
   printf("\n%d",b);
   a=&b;
   *a=100;
   printf("-->%d",b);
}

Output: 10-->100

這就是它的工作原理。

         b        // name
     ----------
     +   10   +   // value
     ---------- 
        4000      // address 

假設b的內存位置是4000。

a=&b => a=4000;
*a=100 => *(4000)=100 => valueat(4000) => 100

操作后看起來像這樣。

         b        // name
     ----------
     +  100   +   // value
     ---------- 
        4000      // address 

一行:您正在取消引用未初始化指針的第一個代碼,它表現出未定義的行為,而在第二個代碼中,您將取消引用初始化指針,該指針將允許訪問該地址的值。

一點解釋:

首先,你需要認識到,一個指針只不過是一個整數,一個與*var我們告訴我們將要使用的變量的內容編譯器var (其中的整數)作為地址在該地址來獲取價值。 如果有類似的**var我們告訴編譯器我們將首先使用變量var的存儲值來獲取地址處的值,並再次使用此獲取的值作為地址並獲取存儲在其中的值。

因此,在您的第一個聲明中它是:

           +----------+        +----------+
           |  garbage |        |  garbage |
           +----------+        +----------+
           |    a     |        |    b     |
           +----------+        +----------+
           |  addr1   |        |  addr2   |
           +----------+        +----------+

然后嘗試使用存儲在a的值作為地址。 a包含垃圾,它可以是任何值,但您無權訪問任何地址位置。 因此,下一刻,當你做*a會在使用儲值a作為地址。 因為存儲的值可以是任何東西,任何事情都可能發生。

如果您有權訪問該位置,則代碼將繼續執行而不會出現分段錯誤。 如果地址恰好是來自堆簿保留結構的地址,或者代碼從堆或堆棧分配的其他內存區域,那么當你執行*a = 10 ,它將在該位置用10擦除現有值。 這可能會導致未定義的行為,因為現在您已經更改了某些內容而不了解具有內存實際權限的上下文。 如果您沒有內存權限,則只會出現分段錯誤。 這稱為取消引用未初始化的指針。

你做下一個語句a = &b剛剛分配的地址ba 這沒有用,因為前一行已取消引用未初始化的指針。

下一個代碼在第三個語句之后你有這樣的東西:

           +----------+        +----------+
           |  addr2   |---+    |  garbage |
           +----------+   |    +----------+
           |    a     |   +--> |    b     |
           +----------+        +----------+
           |  addr1   |        |  addr2   |
           +----------+        +----------+

第三個語句將b的地址分配給a 在此之前, a未被解除引用,因此在初始化之前存儲在a的垃圾值從不用作地址。 現在,當你將你的知識的有效地址轉換成a ,解引用a現在就可以訪問到的值由指向a

擴展答案,你需要注意,即使你已經為指針分配了一個有效的地址,你必須確保在取消引用指針時指針所指向的地址的生命周期沒有到期。 例如,返回局部變量。

int foo (void)
{
  int a = 50;
  return &a;  //Address is valid
}//After this `a' is destroyed (lifetime finishes), accessing this address
 //results in undefined behaviour

int main (void)
{
  int *v = foo ();
  *v = 50; //Incorrect, contents of `v' has expired lifetime.
  return 0;
}

在從堆訪問釋放的內存位置的情況下也是如此。

int main (void)
{
  char *a = malloc (1);
  *a = 'A'; //Works fine, because we have allocated memory
  free (a); //Freeing allocated memory
  *a = 'B'; //Undefined behaviour, we have already freed 
            //memory, it's not for us now.
  return 0;
}

在第一種情況下,您已經聲明了一個指針,但是您沒有指定它必須指向的地址,因此指針將包含一個屬於系統中另一個進程的地址(或者它將包含一個垃圾值,它根本不是地址,或者它將包含一個不能作為存儲器地址的空值,因此操作系統發送信號以防止無效的存儲器操作,因此發生分段故障。

在第二種情況下,您要將必須更新的變量的地址分配給指針並存儲值,這是正確的操作方式,因此沒有分段錯誤。

int a存儲隨機整數值。 所以說* a,你可能正在訪問一個超出范圍或無效的內存位置。 所以這是一個段錯誤。

暫無
暫無

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

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