簡體   English   中英

取消引用指向任意地址的指針會導致分段錯誤

[英]Dereferencing pointer to arbitrary address gives Segmentation fault

我為指針編寫了一個簡單的 C 代碼。 根據我的理解,指針是一個變量,它保存另一個變量的地址。 例如:

 int x = 25; // address - 1024
 int *ptr = &x;
 printf("%d", *ptr); // *ptr will give value at address of x i.e, 25 at 1024 address.

但是,當我嘗試下面的代碼時,我遇到了分段錯誤

#include "stdio.h"
int main()
{
    int *ptr = 25;
    printf("%d", *ptr);
    return 0;
}

這有什么問題? 為什么指針變量不能返回地址 25 的值? 我不應該能夠讀取該地址的字節嗎?

除非您在具有特定已知 memory 位置的嵌入式系統上運行,否則您不能將任意值分配給期望能夠成功取消引用它的指針。

C 標准的第 6.5.3.2p4 節對間接運算符*做了以下說明:

一元*運算符表示間接。 如果操作數指向 function,則結果是 function 指示符; 如果它指向 object,則結果是指定 object 的左值。 如果操作數的類型為“pointer to type”,則結果的類型為“type”。 如果已為指針分配了無效值,則一元*運算符的行為未定義。

As mentioned in the passage above, the C standard only allows for pointers to point to known objects or to dynamically allocated memory (or NULL ), not arbitrary memory locations. 某些實現可能在特定情況下允許這樣做,但一般情況下不允許這樣做。

盡管根據 C 標准未定義程序的行為,但您的代碼實際上是正確的,因為它完全按照您的意圖進行。 它試圖從 memory 地址 25 讀取並打印該地址的值。

然而,在大多數現代操作系統中,例如 Windows 和 Linux,程序使用虛擬 memory而不是物理 ZCD69B7.367F08CD8218 因此,您很可能嘗試訪問未映射到物理 memory 地址的虛擬 memory 地址。 訪問未映射的 memory 位置是非法的,會導致分段錯誤。

Since the memory address 0 (which is written in C as NULL ) is normally reserved to specify an invalid memory address, most modern operating systems never map the first few kilobytes of virtual memory addresses to physical memory. 這樣,當一個無效的 NULL 指針被取消引用時,就會發生分段錯誤(這很好,因為它更容易檢測錯誤)。

由於這個原因,您可以合理地確定地址 25(非常接近地址 0)也從未映射到物理 memory,因此如果您嘗試訪問該地址將導致分段錯誤。

但是,您程序的虛擬 memory 地址空間中的大多數其他地址很可能存在相同的問題。 由於操作系統會盡可能將物理 memory 保存到物理 memory 地址空間中,因此不會比必要的更多。 因此,在大多數情況下,試圖猜測有效的 memory 地址會失敗。

如果您想探索您的進程的虛擬地址空間以找到您可以讀取而不會發生分段錯誤的 memory 地址,您可以使用操作系統提供的相應 API。 在 Windows 上,您可以使用 function VirtualQuery 在 Linux 上,您可以讀取偽文件系統/proc/self/maps ISO C 標准本身不提供確定虛擬 memory 地址空間布局的任何方法,因為這是特定於操作系統的。

If you want to explore the virtual memory address layout of other running processes, then you can use the VirtualQueryEx function on Windows and read /proc/[pid]/maps on Linux. However, since other processes have a separate virtual memory address space, you can't access their memory directly, but must use the ReadProcessMemory and WriteProcessMemory functions on Windows and use /proc/[pid]/mem on Linux.

免責聲明:當然,我不建議亂搞其他進程的 memory,除非你確切地知道自己在做什么。

但是,作為程序員,您通常不想探索虛擬 memory 地址空間。 相反,您通常使用由操作系統分配給您的程序的 memory。 如果你想讓操作系統給你一些 memory 來玩,你可以隨意讀取和寫入(即沒有分段錯誤),那么你可以聲明一個大的字符數組(字節)作為全局變量,例如char buffer[1024]; . 將較大的 arrays 聲明為局部變量時要小心,因為這可能會導致堆棧溢出 或者,您可以向操作系統詢問動態分配的 memory,例如使用malloc function。

您應該考慮編譯器發出的所有警告。

這個說法

int *ptr = 25;

是不正確的。 您正在嘗試將 integer 作為 memory 的地址分配給指針。 因此在這個聲明中

printf("%d", *ptr);

嘗試訪問不屬於您的程序的地址 25 處的 memory。

你的意思是以下

#include "stdio.h"

int main( void )
{
    int x = 25;

    int *ptr = &x;

    printf("%d", *ptr);

    return 0;
}

或者

#include "stdio.h"
#include <stdlib.h>


int main( void )
{
    int *ptr = malloc( sizeof( int ) );

    *ptr = 25;

    printf("%d", *ptr);

    free( ptr );

    return 0;
}

暫無
暫無

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

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