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