指针(拾遗)
指針是一種數據類型,和int,float......一樣的變量
指針就是存放地址值的一種數據類型,就是用來存放內存地址的地方
無論它里面有什么內容,指向了哪里,它都一定占了內存。
?
int a;
int b;
int* p; // 申明一個int指針p。
p = &a; // 看這兒,&a是什么?內存塊a的地址編號。這句話,就是讓p的值等于地址塊a的地址編號。*p就相當于a(按照官話就是p指向a了)。如*p=2;就等同于給a賦值為2.
p = &b; // 再看這里,看到變化了沒。p現在的值變了,變成了地址塊b的地址編號了。
?
另:指針有沒有占據自身的內存牽涉到了他能不能作為左值。在用指針的時候經常會遇到指針不能為左值的問題
下面是轉的,不理解在看看吧
32系統指針變量是4byte,我在xp下用vc6.0測試出4byte,tc是2byte為什么?
不同的計算機是不一樣的.
32位的是4個字節,也就是現在用的最多的(64位快了...),16位就是2個字節.
雖然是16位,不過他的尋址方式不只是用指針,系統還要配合段繼存器(16位系統當然也是16的的繼存器了)來尋址,合起來也就是4個字節了.
現在的32位跟16的差不多,不過由于WINDOWS系統所有的數據段都使用一個地址(人家可能認為32位夠用了吧),就不會涉及到段繼存器了.
當然象”zz003pm”說的地址轉換的問題我還不太清楚,可能是由硬件實現的,不記得了.
因為tc是16位的編譯器,最早就是運行在dos下的,在16位機上int都是2位的,因為指針變量的 sizeof 大小是系統相關的。一般就是4了,因為現在一般都是32 位的系統
指針大小應等同于地址總線的寬度
深入淺出 C語言指針 一
指針是什么? 是地址。這個大家都知道。但是理解得未必深刻。我們以一條條活生生的代碼來分析。
int *pointer;
聲明一個指針。 pointer是一個指向Int型的指針的變量。
而變量里面的值是一個內存地址(在大部分操作系統中不是物理地址,是經過地址映射后的虛擬地址,即邏輯地址)。
而這個pointer只在程序文件(.c,.cpp)里存在,當編譯成可執行文件后,它被替換成一個難看的符號,比如LLC012什么的。這點與java相反,所以C程序是沒有辦法反編譯的。
當運行一個C程序時,操作系統分配給LLC012一塊32位大小內存地址,以后你改變指針的值時,改變的就是這塊內存地址的值了。
?
| 菜鳥問與答(指針) |
| ? |
| ? |
| 1、什么是指針 指針是一種數據類型,與其它的數據類型不同的是指針是一種“用來存放地址值的”變量。舉一個簡單的例子: 如果定義了一個整型變量,根據整型變量的特點,它可以存放的數是整數。 如:int a; a=100; 這樣就把整型常量賦給了變量a。但是如果寫成這樣:a=123.33;就會出問題,最后輸出變量a的值結果是123?,F在說到指針,其實地址值也是一個整型數,如某某變量的地址值為36542,說明這個變量被分配在內存地址值為36542的地方。能不能這樣進行推理,既然地址值也是整型數,整型變量正好可以用來存放整型數,那不是一個整型變量可以用來存放地址的值嗎。程序寫成下面這樣: int a,b; a=&b; 很明顯,這樣寫是錯誤的。原因在于不能簡單地把地址理解為整型數。 應有這樣的對應關系: 地址值<--->指針; 整型數<--->int 型變量。 所以有這樣的說法:“指針就是地址”(指針就是存放地址值的一種數據類型) 下面是一段正確的程序: int a,*p; p=&a; /*把變量a的地址值賦給指針p*/ 2、什么是void指針 void的意思就是“無值”或“無類型”。void指針一般稱為“通用指針”或“泛指針”。之所以有這樣的名字是因為使用void指針可以很容易地把void指針轉換成其它數據類型的指針。例如在為一個指針分配內存空間的時候: int *p; p=(int *)malloc(......); 本來函數malloc的返回值是void類型,在這里通過在前面加上一個帶括號的int*就把void*類型轉換成了int*類型。 所以不能簡單的把void看成“無”的意思。void數據類型是一種很重要的數據類型。 3、指針可以相加減嗎 可以相互加減。但是一定要作有意義的運算。當二個指針指向同一個數組的時候,它們相加減是有意義的。如果二個指針分別指向二個不同的數組,那么指針之間的相加減就沒有什么意義。指向同一個數組時,其相加減的結果為二個指針之間的元素數目。 4、什么是NULL指針 NULL指針是不指向任何一個地址的指針。這樣的指針一般是允許的。當一個指針為NULL的時候,不要對它進行存取。 5、什么是“野”指針 野指針是不由程序員或操作者所能控制的指針。當在一個程序里面定義了一個指針而又沒有給這個指針一個具體地址指向的時候,這個指針會隨意地指向一個地址,這樣的指針就是一個野指針。如果這個地址后面的內存空間沒有什么重要的數據則不會造成不好的后果,但是一旦這里面存放了有用的數據,那么這些數據隨時都有被野指針存取的危險,如果這樣,數據就會被破壞,程序也會崩潰。所以在程序里面是一定要禁止任何野指針的存在。當定義了一個指針的時候,要馬上給這個指針分配一個內存地址的指向。這樣程序才不會因為指針而出現意外。 6、NULL的值是什么 NULL不是被定義為0就是被定義成(void *)0,這二種值基本上是一樣的。 如有這樣的語句: if(p==NULL) 或者寫成 if(p==0) 其作用是一樣。 7、什么是“內存泄漏” 當定義了一個指針的時候,立即要為這個指針分配一個內存空間。這只防止了野指針的產生。當一個指針使用完畢要立即釋放掉這個指針所占用的內存空間---這有二方面的意義: 1)避免了內存空間的泿費; 2)防止了內存泄漏。為什么會產生內存泄漏:如果沒有及時釋放掉指針所占用的內存空間,而在下次使用這個指針時又給這個指針分配了內存空間,這樣的次數一多,內存空間就慢慢被消耗掉了。所以形象地稱這種現象為內存泄漏。 如下面這樣一個程序: void *p; for(;;) p=malloc(20); /*這20個字節的內存空間是隨意指定的*/ 這樣的一個小程序,大家不要隨便運行它。你可以在集成環境中單步調試運行,可以看一下每步運行后的結果。可以看到,每一次循環都會“吃掉”20個字節的內存,無數次之后,再多的內存也慢慢地“泄漏”,最后沒有內存可用就死機。(與這個程序配合需要一段檢測整機總的內存容量的程序,以觀察內存總量的變化。這里雖然沒有這一段程序,但是看得到每次分配的內存地址值是不相同的) 8、near指針和far指針 在DOS下(實模式)地址是分段的,每一段的長度為64K字節,剛好是16位(二進制的十六位)。 near指針的長度是16位的,所以可指向的地址范圍是64K字節,通常說near指針的尋址范圍是64K。 far指針的長度是32位,含有一個16位的基地址和16位的偏移量,將基地址乘以16后再與偏移量相加,(所以實際上far指針是20位的長度。)即可得到far指針的1M字節的偏移量。所以far指針的尋址范圍是1M字節,超過了一個段64K的容量。例如一個far指針的段地址為0x7000,偏移量為0x1244,則該指針指向地址0x71224.如果一個far指針的段地址是0x7122,偏移量為0x0004,則該指針也指向地址0x71224。 如果沒有指定一個指針是near或far,那么默認是near。所以far指針要顯式指定。far指針工作起來要慢一些,因為每次訪問一個far指針時,都要將數據段或程序段的數據交換出來。另外,far指針的運算也比較反常,例如上面講到的far指針指向同一個地址,但是比較的結果卻不相同。 9、什么時候使用far指針 當使用小代碼或小數據存儲模式時,不能編譯一個有很多代碼或數據的程序。因為在64K的一個段中,不能放下所有的代碼與數據。為了解決這個問題,需要指定以far函數或far指針來使用這部分的空間(64K以外的空間)。許多庫函數就是顯式地指定為far函數的形式。far指針通常和farmalloc()這樣的內存分配函數一起使用?!?/span> |
| ? |
?
(int*)pointer = malloc(sizeof(int) * 5);
printf("%d",*(pointer + 1));
這段代碼中先申請5個int大小的內存空間,把這段內存空間的首地址付給pointer。然后打印出第2個int元素的值。
如果這里的pointer是char類型的,那么pointer+1指向的不是第2個Int,而是第一個int的中間部分。也就是說對于不同變量類型的指針來說,+1跨過的內存單元數是不同的。指針的類型也可以是自定義的結構的類型。
與java不同,C語言的函數是不允許以引用的方式傳值的,也就是說對于所有的C函數,傳入的參數都是一個復制的值。
比如這樣一個交換數值的函數
void switch(int a ,int b)
{
int c =a;
a = b;
b = c;
}
這個函數調用后實際上并沒有交換兩個參數的值,因為是傳值的,而非傳地址(引用)的。
那么我們如何實現累類似引用傳值的功能呢? 答案是,用指針。
void switch(int* a ,int* b)
{
int c =*a;
*a = *b;
*b = c;
}
從本質上說指針也是被復制后傳到函數體內的。
我們以上面這個函數為例分析一下
函數一 : 當調用 switch(intA,intB)時
假設 :
intA 地址 0X0000000A 值 1
intB 地址 0X0000000B 值 2
經過復制之后實際上傳入函數的是另外兩個。
a 地址 0X000000AA 值 1
b 地址 0X000000BB 值 2
當函數執行后,intA,intB的值沒變,他們從頭到尾都沒進入函數,進入的是他們的副本。變的是a , b的值(如下),但是函數執行結束后a , b都已經被丟棄了。沒有達到預期目的。
a 地址 0X000000AA 值 2
b 地址 0X000000BB 值 1
函數二 : 當調用 switch(*intA,*intB)時
假設 :
intA 地址 0X0000000A 值 0X00000A0A
intB 地址 0X0000000B 值 0X00000B0B
地址 0X00000A0A 值 1
地址 0X00000B0B 值 2
當函數執行時,先復制參數,結果如下
a 地址 0X000000AA 值 0X00000A0A
b 地址 0X000000BB 值 0X00000B0B
而地址0X00000A0A 和 0X00000B0A 的值沒有變化
傳入函數后用的都是指針變量的值,也就是說改變的是0X00000A0A 和0X00000B0B的值,而指針intA和intB的值沒有變化,始終指向0X00000A0A 和0X00000B0B 所以最終達到交換數值的預期效果。
問:請問 在C中 (TC3.0)一個指針變量 在內存中占幾個字節?那 如果 指針變量只占 2字節(tc3.0)
那它能指向的內存范圍是0-65535以內的地址 那其他的地址豈不是無法指到?
答:呵呵,指針指向的是邏輯地址。當構成實際地址的時候指針還要跟一定的段地址寄存器進行運算才能得出真實地地址。這些都是操作系統做的,你不需要關心這個。
// zd_20.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int main(int argc, char* argv[])
{
int *p;
char *c;
long int *q;
float *f;
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(c));
printf("%d\n",sizeof(q));
printf("%d\n",sizeof(f));
printf("Hello World!\n");
return 0;
}
VC下輸出為
4
4
4
4
TC下輸出為
2
2
2
2
原因:
一般來說
指針長度應該與OS的位數有關
32位操作系統應該為4個字節
以后64位操作系統應該為8個字節
但在編譯環境中
指針長度是由編譯環境來設置的
由于TC是DOS時代的產物
所以它還是2個字節
VC自然是4個字節
?
轉載于:https://www.cnblogs.com/cuihongyu3503319/archive/2012/01/09/2317222.html
總結
- 上一篇: 2011年使用率增长最快的十大Web技术
- 下一篇: TreeView复选框选择逻辑判断