程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++判斷char*的指向

C++判斷char*的指向

編輯:C++入門知識

char *a = "Peter";
char b[] = "Peter";
char *c = new char[6];
strcpy_s(c, 6, "Peter");

 

這裡a指向常量區

b指向棧區

c指向堆區

 

如果我們有這樣一個函數

void show(char *temp)
{
//
//
//
}

我們如何判斷根據過來的temp的將這些區分出來呢?

1.我們可以首先將指向常量區的a區分出來

因為它所指向的地方是不可以修改的

判斷是否可以修改

a.使用函數IsBadReadPtr

函數原型如下

BOOL WINAPI IsBadWritePtr(
  _In_  LPVOID lp,
  _In_  UINT_PTR ucb
);

lp:第一個字節的內存塊的指針。

ucb:指定的大小,單位為字節的內存塊。如果此參數為零,則返回值為零。

MSDN上部分的解釋如下

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366716(v=vs.85).aspx

Verifies that the calling process has write access to the specified range of memory.

Important  This function is obsolete and should not be used. Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. For more information, see Remarks on this page.

翻譯(自己翻譯的):

驗證調用的進程是否可以寫入指定范圍的內存

主要的:這個函數是廢棄的,不應該被使用,不管它的名字,它不保證這個指向內存中的指針是合法的和這段內存是可以安全使用的,對於更多的信息,可以查看這頁的評論

 

示例:

bool  isConst(void* pAddress, DWORD dwSize)
{
    if (IsBadWritePtr(pAddress, dwSize))
        return true;
    return false;
}

int main()
{
    char *a = "Peter";
    char b[] = "Peter";
    char *c = new char[6];
    strcpy_s(c, 6, "Peter");
    cout << isConst(a,strlen(a))<< endl;
    cout << isConst(b, strlen(a)) << endl;
    cout << isConst(c, strlen(a)) << endl;

    system("pause");
}

結果

SIZE_T WINAPI VirtualQuery( _In_opt_  LPCVOID lpAddress, _Out_     PMEMORY_BASIC_INFORMATION lpBuffer, _In_      SIZE_T dwLength );

lpAddress:查詢內存的地址。

lpBuffer:指向MEMORY_BASIC_INFORMATION結構的指針,用於接收內存信息。

dwLength:MEMORY_BASIC_INFORMATION結構的大小。

MSDN上部分的解釋如下

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366902(v=vs.85).aspx

Retrieves information about a range of pages in the virtual address space of the calling process.

檢索對於調用進程的虛擬內存中的頁的信息

 

用於接收的內存信息的MEMORY_BASIC_INFORMATION結構體定義如下

typedef struct _MEMORY_BASIC_INFORMATION {
  PVOID  BaseAddress;
  PVOID  AllocationBase;
  DWORD  AllocationProtect;
  SIZE_T RegionSize;
  DWORD  State;
  DWORD  Protect;
  DWORD  Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

BaseAddress:保留區域的基地址
AllocationBase:分配的基地址

AllocationProtect:初次保留時所設置的保護屬性
RegionSize:區域大小
State:狀態(提交、保留或空閒)
Protect: 當前訪問保護屬性
Type:頁面類型

詳細請見MSDN

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
 
示例
bool  isConst(void* pAddress)
{
    _MEMORY_BASIC_INFORMATION mi = { 0 };
    VirtualQuery(pAddress, &mi, sizeof(mi));
    if (mi.Protect == PAGE_READONLY)
    {
        return true;
    }
    return false;
}

int main()
{
    char *a = "Peter";
    char b[] = "Peter";
    char *c = new char[6];
    strcpy_s(c, 6, "Peter");
    cout << isConst(a)<< endl;
    cout << isConst(b) << endl;
    cout << isConst(c) << endl;
    
    system("pause");
}

結果

判斷是否位於棧上

參考了http://www.cppblog.com/weiym/archive/2012/05/12/174634.html

我們可以在函數內建一個位於棧的對象,然後獲得棧空間的初始地址,以及棧的最末尾的地址,就可以判斷一個東西是不是為與棧上了

VirtualQuery中用於接收內存信息_MEMORY_BASIC_INFORMATION結構體中有如下成員

BaseAddress:保留區域的基地址
RegionSize:區域大小


代碼示例

bool IsObjectOnStack(void* pObject)
{
    int nStackValue(0);

    MEMORY_BASIC_INFORMATION mi = { 0 };
    DWORD dwRet = VirtualQuery(&nStackValue, &mi, sizeof(mi));
    if (dwRet > 0)
    {
        return pObject >= mi.BaseAddress
            && (DWORD)pObject < (DWORD)mi.BaseAddress + mi.RegionSize;
    }

    return FALSE;
}

int main()
{
    char *a = "Peter";
    char b[] = "Peter";
    char *c = new char[6];
    strcpy_s(c, 6, "Peter");
    cout << IsObjectOnStack(a) << endl;
    cout << IsObjectOnStack(b) << endl;
    cout << IsObjectOnStack(c) << endl;
    
    system("pause");
}

運行結果

image

 

解釋:nStackValue是一個位於棧上的對象

我們針對它使用 VirtualQuery獲得相關的內存信息mi

mi.BaseAddress是棧的初始地址

(DWORD)mi.BaseAddress + mi.RegionSize是棧的最末尾的地址

我們只要判斷地址是不是在這二者之間,就可以判斷是不是位於棧上了

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved