當前位置:首頁 » 編程語言 » c語言指針越界
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

c語言指針越界

發布時間: 2023-01-06 14:51:07

Ⅰ 為什麼c語言檢查數組訪問越界會這么難

C語言中數組和內存管理,是安全性和性能之間矛盾關系的重要部分。

我曾提到要討論性能和安全性之間的矛盾。這個矛盾的一個重要部分就是因為C語言中數組和內存管理的本質特徵導致的。

理論上,數組是一個簡單的數據結構:當你需要訪問其中的一個元素時,只需要給出該元素的索引位置,就能對該元素進行讀或者寫操作。這句話中也隱含了
一個問題,那就是你需要訪問一個元素時,都需要提供一個索引位置。使用索引位置來找元素通常是一個代價很高的計算,尤其是當元素的大小不是2的整數次冪
時: 在諸如表達式++a[i], 在地址遞增的過程中,其計算地址的代價可以輕松超過5倍於a[i]的地址的代價。

在至少50年的時間里,編譯器開發人員一直在努力讓訪問數組元素變得更快。其中很大一部分的工作都圍繞想下面這種循環進行:
for (size_t i = 0; i < n; ++i)
c[i] = a[i] + b[i];

這段代碼在每次循環迭代中,都需要通過計算將三個索引地址轉換成對應的內存位置中,這種計算也帶入了一些開銷。 許多編譯器都通過將循環重寫為如下代碼的方式來實現高效計算。在這段代碼中,我們假設Pointer類型是可以指向a,b,c三個數組中某個元素的指針。
Pointer ap = &a[0], bp = &b[0], cp = &c[0], aend = ap + n;
while (ap < aend) {
*cp++ = *ap++ + *bp++;

}

這段轉換後的代碼將三個數組索引計算操作轉換成了三個地址加操作,這樣加速顯著。不過,這個簡單的轉換操作看起來容易,做起來卻很復雜,
因為編譯器需要能夠確認在這個for循環體中沒有對i值本身的修改。 上面的例子可以很直觀的看到i不會被改變,不過在實際的代碼中,往往要困難很多。

C語言與在它之前的編程語言相比,一個非常重要的不同就是C能提供給程序員一些直接優化代碼的機會,而不是簡單的依賴編譯器去做優化。C語言通過將數組和指針的概念統一化,使得程序員可以自己做大部分的數組索引計算,而在C語言之前,這些工作只能通過編譯器去做。

用手動計算索引取代自動計算是一種進步,這個聽起來有點怪怪的。但是在實際編程中,可能很多程序員都寧願手工優化代碼,而不是依賴編譯器自動優化,因為無法確定編譯器到底對代碼做了什麼。這也可能是吸引C程序員使用指針而不是索引來訪問數組元素的原因之一。

除了在很多情況下會更快外,指針相比數組還有另外一個很大的優勢:可以只用指向數組中特定元素的一個指針來識別數組中的元素。比如,假設我們想寫一

個函數來對數組中某個區域內的元素做操作。如果沒有指針,我們需要三個參數來確定這個區域:數組名稱,區域開始索引,區域結束索引。而如果使用指針的話,
只要兩個參數就足夠了。

此外,不管是動態分配的內存,還是其他內存地址,都可以統一使用指針。例如,在malloc庫函數返回一個指向動態內存的指針後,我們可以用這個指

針創建任何我們需要的數據結構。一旦我們在這塊動態分配的內存中創建了這些數據結構之後,我們就能使用指向這些數據結構某個部分的指針來讓其他函數可以直
接訪問這一部分數據。 相應的,這些函數也無需知道他們將使用的內存到底是什麼性質的。

使用指針是方便了很多,但是也要付出代價的。相比於使用索引變數引用數組元素的表示形式,使用指針的表示形式將會引入三種潛在危害。

第一,因為指向數組元素的指針和數組本身是完全獨立的。
因此,在數組不存在或者內存釋放之後,指針仍然有可能存在。比如,我們將數組元素的地址
&a[0]保存到指針ap中,我們同時也引入了在a不存在的時候,使用*ap的風險。這種風險在完全使用數組加索引的形式中是不存在的,因為一旦
數組a消失了,我們也無法引用他的元素。

第二,指針運算的可行性。
如果我們使用一對指針指向一個數組區間的兩端,那麼我們就一定能找到其中間元素的位置,因為可以直接使用數學運算得到。但
是這種指針的數學運算也同時引入了很多製造不可用地址的可能性,而且這種通過數學運算得到的不可用地址, 相比簡單的一些針對整數的數學運算來說,
更難檢測到。

最後,使用指針來表示範圍,不僅僅需要指針本身存在且可用,還需要指針指向的內存是可用的內存
。上面代碼中的aend變數就是一個典型例子。我們創
建了一個aend變數,並用它指向循環的上界。但是如果我們想試圖對*aend取值,結果將是未定義的。這類指針被稱為off-the-end指針。這類
指針的存在,也讓驗證C語言是否存在越界錯誤變得非常困難。

Ⅱ C語言的越界問題

  1. C語言是不檢查下表越界的,因此越界出來結果太正常了,你和書上一樣是因為你從-1到6到賦值了,編譯器的實現就是安數組首位坐標+-指針而已。如果你輸出-3呢,應該就是隨機了。

  2. 為什麼arr【5】和arr【6】應該一樣?

  3. 給你看看我用VC++6.0在Win32位上運行結果:


Ⅲ C語言指針問題

首先,你提到的所有p應該是一個類型,也就是
int *p
即,整型指針類型,該類型與一維整型數組等效,即int []
然後一個個來
第一個,只有用在定義的時候才是對的,
int *p=a;意思是定義int*類型的p,初始化為a。等效於int *p;p=a;
第二個,先p+5,然後取值,等效於p[5],在p=a下,也就是a[5],這里其實是越界的,知道是這個意思就好
第三個,先取值,在值加2,p=a時,*p為a[0],這個就是a[0]+2
第四個和第五個類似,如果p=a,那麼四五完全等同,都是a[2]的地址
最後一個,對a[5]先取地址再取值,最終還是a[5],這個和第二個是等價的,當然,也一樣是越界

Ⅳ C語言指針越界問題,大神指教!!!

*p是指向int類型的指針,a為數組首地址,這些理解都是對的,

但是,p沒有被初始化啊,你能直接是用沒有被初始化的變數嘛,那肯定是不行的啊.

所以正確的做法先給p綁定堆內存就可以這樣寫了.

#include<iostream>
usingnamespacestd;
intmain()
{

int**p=newint*;
intArray[10]={1,2,3,4,5,6};
*p=Array;
cout<<(*p)[1]<<endl;

system("pause");
return0;
}
編譯完全通過.這里不貼出來了.點我頭像進群.

Ⅳ c語言越界是什麼意思

書中所說的越界是指如果z很大,大到int類型存不下(超過2^32-1), 就會發生越界溢出,(即內存不夠存放z)此時z成為負數,導致計算出錯。而模的乘積又等於乘積的模,所以每次乘法的結果都會小於1000,既滿足了結果正確又不會發生int存不下

Ⅵ 什麼是指針越界,有何後果

)應該特別注意程序的書寫格式,讓它的形式反映出其內在的意義結構。 程序是最復雜的東西(雖然你開始寫的程序很簡單,但它們會逐漸變得復雜起來),是需要用智力去把握的智力產品。良好的格式能使程序結構一目瞭然,幫助你和別人理解它,幫助你的思維,也幫助你發現程序中不正常的地方,使程序中的錯誤更容易被發現。 人們常用的格式形式是:邏輯上屬於同一個層次的互相對齊;邏輯上屬於內部層次的推到下一個對齊位置。請參考本課程的教科書或《C程序設計語言》(The C Programming Language,Brian W. Kernighan & Dennis M. Rirchie,清華大學出版社,大學計算機教育叢書(影印版,英文),1996。) 利用集成開發環境(IDE)或者其他程序編輯器的功能,可以很方便地維護好程序的良好格式。請注意下面這幾個鍵,在寫程序中應該經常用到它們:Enter鍵(換一行),Tab鍵(將輸入游標移到下一個對齊位置——進入新的一個層次),Backspace鍵(回到前一個對齊位置——退到外面的一個層次)。 -------------------------------------------------------------------------------- 2)用最規范的、最清晰的、最容易理解的方式寫程序。注意人們在用C語言寫程序的習慣寫法,例如教科書中解決類似問題時所使用的寫法,《C程序設計語言》一書中有許多極好的程序實例。在這里有一個關於程序模式的相關網頁,裡面也列出了一些常用的模式。 C語言是一個非常靈活的語言,你可能在這里用許多非常隱晦的方式寫程序,但這樣寫出的程序只能是作為一種玩意兒,就像謎語或者智力游戲。這些東西可以用於消磨時間,但通常與實際無緣。在我們的C語言討論組里提到過這種東西。 -------------------------------------------------------------------------------- 3)在編程中,應仔細研究編譯程序給出的錯誤信息和警告信息,弄清楚每條信息的確切根源並予以解決。特別是,不要忽略那些警告信息,許多警告信息源自隱含的嚴重錯誤。我們有許多辦法去欺騙編譯程序,使它不能發現我們程序中的錯誤,但這樣做最終受到傷害的只能是自己。 -------------------------------------------------------------------------------- C語言的運算符很多,優先順序定義也不盡合理,很難完全記清楚,因此要特別注意。需要時查一查(不要怕麻煩,相關網頁有運算符表),或者直接按照自己的需要加上幾個括弧。 -------------------------------------------------------------------------------- scanf("%d %d", i++, a[i]); m = n * n++; -------------------------------------------------------------------------------- 6)總保證一個函數的定義點和它的所有使用點都能看到同一個完整的函數原型說明。 -------------------------------------------------------------------------------- 7)總注意檢查數組的界限和字元串(也以數組的方式存放)的結束。C語言內部根本不檢查數組下標表達式的取值是否在合法范圍內,也不檢查指向數組元素的指針是不是移出了數組的合法區域。寫程序的人需要自己保證對數組使用的合法性。越界訪問可能造成災難性的後果。 例:在寫處理數組的函數時一般應該有一個范圍參數;處理字元串時總檢查是否遇到空字元'\0'。

Ⅶ C語言指針越界問題。

strchr函數就在在字元串中查找指定字元,返回其地址。
這個函數本身就已經把結束符號0,計入遍歷查找范圍,所以沒有把0作為結束位置,所以無所謂。
但字元串最好最後多留一位放0,不然代碼長了,傳參多了,就弄不清了。

Ⅷ C語言指針的問題:請問下C語言前輩們,是不是訪問越界造成的calloc創建失敗或者是指針訪問違規

#define FILE_PATH_IN "C:\\DllTool.dll"
#define NEW_FILE_PATH_OUT "C:\\DllTool_new.dll"

PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS32 pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;

FILE *pFile = NULL;
LPVOID pFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
LPVOID pNewBuffer = NULL;
FILE *pNewFile = NULL;

size_t dwFileSize = 0;
size_t dwSize = 0;
DWORD i = 0;

//讀取文件
pFile = fopen(FILE_PATH_IN, "rb");
fseek(pFile, 0L, SEEK_END);
dwFileSize = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
pFileBuffer = calloc(dwFileSize, sizeof(char));
if (pFileBuffer == NULL)
{
printf("申請pFileBuffer空間失敗!\n");
return 0;
}
dwSize = fread(pFileBuffer, sizeof(char), dwFileSize, pFile);

//拉伸
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + sizeof(pNTHeader->Signature));
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

pImageBuffer = calloc(pOptionHeader->SizeOfImage, sizeof(char));
if (pImageBuffer == NULL)
{
printf("申請pImageBuffer空間失敗!\n");
return 0;
}
memcpy(pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);
for (i=0; i<pPEHeader->NumberOfSections; i++)
{
PIMAGE_SECTION_HEADER pTempSec = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + i * IMAGE_SIZEOF_SECTION_HEADER);
memcpy((void*)((DWORD)pImageBuffer + pTempSec->VirtualAddress), \
(void*)((DWORD)pFileBuffer + pTempSec->PointerToRawData), pTempSec->SizeOfRawData);
}
//就是這里,下面這個pNewBuffer空間申請失敗,指針為NULL。我調試到上面這個循環出了問題,但不知道怎麼解決,原來就一句:pSectionHeader++ 就解決的事件,但都不行,請高手們幫幫忙!!!謝謝了!!!
//壓縮
pNewBuffer = calloc(dwSize, sizeof(char));
if (pNewBuffer == NULL)
{
printf("申請pNewBuffer空間失敗!\n");
return 0;
}
memcpy(pNewBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);

//就是上面,我已經標注了,本人C語言算不上精通,請高手們不吝賜教,幫幫忙!!!謝謝了!!!收起
已經找到問題所在了,我換成其它DLL也沒問題,是我寫的這個DLL文件導出函數名使用了def自定名,但我在聲明中又使用了extern "C",生成的DLL文件本身存在一點問題,所以在復制內容時,出問題了,看到此問題的大俠們,謝謝了,給大家造成困擾了,這個指針沒有問題,循環內雖然pSection++最後指向最後一個節區數據,但是i已經使其跳出循環,沒有任何問題!給大家造成困擾,實在對不起,有時代碼看不出問題,其它要從其它方面查詢,換個其它同樣的文件應該測試一下,唉!