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

c語言指針章節目錄

發布時間: 2022-11-07 07:33:45

c語言的指針是什麼

第一章。指針的概念

指針是一個特殊的變數,它裡面存儲的數值被解釋成為內存里的一個地址。要搞清一個指針需要搞清指針的四方面的內容:指針的類型,指針

所指向的類型,指針的值或者叫指針所指向的內存區,還有指針本身所佔據的內存區。讓我們分別說明。

先聲明幾個指針放著做例子:

例一:

(1)int *ptr;

(2)char *ptr;

(3)int **ptr;

(4)int (*ptr)[3];

(5)int *(*ptr)[4];

如果看不懂後幾個例子的話,請參閱我前段時間貼出的文章 < <如何理解c和c++的復雜類型聲明>>。

1。 指針的類型。

從語法的角度看,你只要把指針聲明語句里的指針名字去掉,剩下的部分就是這個指針的類型。這是指針本身所具有的類型。讓我們看看例一

中各個指針的類型:

(1)int *ptr; //指針的類型是int *

(2)char *ptr; //指針的類型是char *

(3)int **ptr; //指針的類型是 int **

(4)int (*ptr)[3]; //指針的類型是 int(*)[3]

(5)int *(*ptr)[4]; //指針的類型是 int *(*)[4]

怎麼樣?找出指針的類型的方法是不是很簡單?

2。指針所指向的類型。

當你通過指針來訪問指針所指向的內存區時,指針所指向的類型決定了編譯器將把那片內存區里的內容當做什麼來看待。

從語法上看,你只須把指針聲明語句中的指針名字和名字左邊的指針聲明符*去掉,剩下的就是指針所指向的類型。例如:

(1)int *ptr; //指針所指向的類型是int

(2)char *ptr; //指針所指向的的類型是char

(3)int **ptr; //指針所指向的的類型是 int *

(4)int (*ptr)[3]; //指針所指向的的類型是 int()[3]

(5)int *(*ptr)[4]; //指針所指向的的類型是 int *()[4]

在指針的算術運算中,指針所指向的類型有很大的作用。

指針的類型(即指針本身的類型)和指針所指向的類型是兩個概念。當你對C越來越熟悉時,你會發現,把與指針攪和在一起的「類型」這個概念

分成「指針的類型」和「指針所指向的類型」兩個概念,是精通指針的關鍵點之一。我看了不少書,發現有些寫得差的書中,就把指針的這兩

個概念攪在一起了,所以看起書來前後矛盾,越看越糊塗。

3。 指針的值,或者叫指針所指向的內存區或地址。

指針的值是指針本身存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數值。在32位程序里,所有類型的指針的值都是一個32

位整數,因為32位程序里內存地址全都是32位長。

指針所指向的內存區就是從指針的值所代表的那個內存地址開始,長度為sizeof(指針所指向的類型)的一片內存區。以後,我們說一個指針的

值是XX,就相當於說該指針指向了以XX為首地址的一片內存區域;我們說一個指針指向了某塊內存區域,就相當於說該指針的值是這塊內存區

域的首地址。

指針所指向的內存區和指針所指向的類型是兩個完全不同的概念。在例一中,指針所指向的類型已經有了,但由於指針還未初始化,所以它所

指向的內存區是不存在的,或者說是無意義的。

以後,每遇到一個指針,都應該問問:這個指針的類型是什麼?指針指向的類型是什麼?該指針指向了哪裡?

4。 指針本身所佔據的內存區。

指針本身佔了多大的內存?你只要用函數sizeof(指針的類型)測一下就知道了。在32位平台里,指針本身占據了4個位元組的長度。

指針本身占據的內存這個概念在判斷一個指針表達式是否是左值時很有用。

第二章。指針的算術運算

指針可以加上或減去一個整數。指針的這種運算的意義和通常的數值的加減運算的意義是不一樣的。例如:

例二:

1。 char a[20];

2。 int *ptr=a;

...

...

3。 ptr++;

在上例中,指針ptr的類型是int*,它指向的類型是int,它被初始化為指向整形變數a。接下來的第3句中,指針ptr被加了1,編譯器是這樣處理

的:它把指針ptr的值加上了sizeof(int),在32位程序中,是被加上了4。由於地址是用位元組做單位的,故ptr所指向的地址由原來的變數a的地

址向高地址方向增加了4個位元組。

由於char類型的長度是一個位元組,所以,原來ptr是指向數組a的第0號單元開始的四個位元組,此時指向了數組a中從第4號單元開始的四個位元組。

我們可以用一個指針和一個循環來遍歷一個數組,看例子:

例三:

int array[20];

int *ptr=array;

...

//此處略去為整型數組賦值的代碼。

...

for(i=0;i <20;i++)

{

(*ptr)++;

ptr++;

}

這個例子將整型數組中各個單元的值加1。由於每次循環都將指針ptr加1,所以每次循環都能訪問數組的下一個單元。再看例子:

例四:

1。 char a[20];

2。 int *ptr=a;

...

...

3。 ptr+=5;

在這個例子中,ptr被加上了5,編譯器是這樣處理的:將指針ptr的值加上5乘sizeof(int),在32位程序中就是加上了5乘4=20。由於地址的單

位是位元組,故現在的ptr所指向的地址比起加5後的ptr所指向的地址來說,向高地址方向移動了20個位元組。在這個例子中,沒加5前的ptr指向數

組a的第0號單元開始的四個位元組,加5後,ptr已經指向了數組a的合法范圍之外了。雖然這種情況在應用上會出問題,但在語法上卻是可以的。

這也體現出了指針的靈活性。

如果上例中,ptr是被減去5,那麼處理過程大同小異,只不過ptr的值是被減去5乘sizeof(int),新的ptr指向的地址將比原來的 ptr所指向的地

址向低地址方向移動了20個位元組。

總結一下,一個指針ptrold加上一個整數n後,結果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold

所指向的類型也相同。ptrnew的值將比ptrold的值增加了n乘sizeof(ptrold所指向的類型)個位元組。就是說,ptrnew所指向的內存區將比ptrold

所指向的內存區向高地址方向移動了n乘sizeof(ptrold所指向的類型)個位元組。一個指針ptrold減去一個整數n後,結果是一個新的指針ptrnew

,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold所指向的類型也相同。ptrnew的值將比ptrold的值減少了n乘sizeof

(ptrold所指向的類型)個位元組,就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向低地址方向移動了n乘 sizeof(ptrold所指向的類

型)個位元組。

第三章。運算符&和*

這里&是取地址運算符,*是...書上叫做「間接運算符」。&a的運算結果是一個指針,指針的類型是a的類型加個*,指針所指向的類型是a的類

型,指針所指向的地址嘛,那就是a的地址。*p的運算結果就五花八門了。總之*p的結果是p所指向的東西,這個東西有這些特點:它的類型是p

指向的類型,它所佔用的地址是p所指向的地址。

例五:

int a=12;

int b;

int *p;

int **ptr;

p=&a;//&a的結果是一個指針,類型是int*,指向的類型是int,指向的地址是a的地址。

*p=24;//*p的結果,在這里它的類型是int,它所佔用的地址是p所指向的地址,顯然,*p就是變數a。

ptr=&p;//&p的結果是個指針,該指針的類型是p的類型加個*,在這里是int**。該指針所指向的類型是p的類型,這里是int*。該指針所指向的

地址就是指針p自己的地址。

*ptr=&b;//*ptr是個指針,&b的結果也是個指針,且這兩個指針的類型和所指向的類型是一樣的,所以?amp;b來給*ptr賦值就是毫無問題的了



**ptr=34;//*ptr的結果是ptr所指向的東西,在這里是一個指針,對這個指針再做一次*運算,結果就是一個int類型的變數。

第四章。指針表達式。

一個表達式的最後結果如果是一個指針,那麼這個表達式就叫指針表達式。下面是一些指針表達式的例子:

例六:

int a,b;

int array[10];

int *pa;

pa=&a;//&a是一個指針表達式。

int **ptr=&pa;//&pa也是一個指針表達式。

*ptr=&b;//*ptr和&b都是指針表達式。

pa=array;

pa++;//這也是指針表達式。

例七:

char *arr[20];

char **parr=arr;//如果把arr看作指針的話,arr也是指針表達式

char *str;

str=*parr;//*parr是指針表達式

str=*(parr+1);//*(parr+1)是指針表達式

str=*(parr+2);//*(parr+2)是指針表達式

由於指針表達式的結果是一個指針,所以指針表達式也具有指針所具有的四個要素:指針的類型,指針所指向的類型,指針指向的內存區,指

針自身占據的內存。

好了,當一個指針表達式的結果指針已經明確地具有了指針自身占據的內存的話,這個指針表達式就是一個左值,否則就不是一個左值。 在例

七中,&a不是一個左值,因為它還沒有占據明確的內存。*ptr是一個左值,因為*ptr這個指針已經占據了內存,其實*ptr就是指針 pa,既然pa

已經在內存中有了自己的位置,那麼*ptr當然也有了自己的位置。

第五章。數組和指針的關系

如果對聲明數組的語句不太明白的話,請參閱我前段時間貼出的文章 < <如何理解c和c++的復雜類型聲明>>。 數組的數組名其實可以看作一個

指針。看下例:

例八:

int array[10]={0,1,2,3,4,5,6,7,8,9},value;

...

...

value=array[0];//也可寫成:value=*array;

value=array[3];//也可寫成:value=*(array+3);

value=array[4];//也可寫成:value=*(array+4);

上例中,一般而言數組名array代表數組本身,類型是int [10],但如果把array看做指針的話,它指向數組的第0個單元,類型是int *,所指

向的類型是數組單元的類型即int。因此*array等於0就一點也不奇怪了。同理,array+3是一個指向數組第3個單元的指針,所以* (array+3)等

於3。其它依此類推。

例九:

char *str[3]={

"Hello,this is a sample!",

"Hi,good morning.",

"Hello world"

};

char s[80];

strcpy(s,str[0]);//也可寫成strcpy(s,*str);

strcpy(s,str[1]);//也可寫成strcpy(s,*(str+1));

strcpy(s,str[2]);//也可寫成strcpy(s,*(str+2));

上例中,str是一個三單元的數組,該數組的每個單元都是一個指針,這些指針各指向一個字元串。把指針數組名str當作一個指針的話,它指

向數組的第0號單元,它的類型是char**,它指向的類型是char *。

*str也是一個指針,它的類型是char*,它所指向的類型是char,它指向的地址是字元串"Hello,this is a sample!"的第一個字元的地址,

即'H'的地址。 str+1也是一個指針,它指向數組的第1號單元,它的類型是char**,它指向的類型是char *。

*(str+1)也是一個指針,它的類型是char*,它所指向的類型是char,它指向"Hi,good morning."的第一個字元'H',等等。

下面總結一下數組的數組名的問題。聲明了一個數組TYPE array[n],則數組名稱array就有了兩重含義:第一,它代表整個數組,它的類型是

TYPE [n];第二,它是一個指針,該指針的類型是TYPE*,該指針指向的類型是TYPE,也就是數組單元的類型,該指針指向的內存區就是數組第

0號單元,該指針自己佔有單獨的內存區,注意它和數組第0號單元占據的內存區是不同的。該指針的值是不能修改的,即類似array++的表達式

是錯誤的。

在不同的表達式中數組名array可以扮演不同的角色。

在表達式sizeof(array)中,數組名array代表數組本身,故這時sizeof函數測出的是整個數組的大小。

在表達式*array中,array扮演的是指針,因此這個表達式的結果就是數組第0號單元的值。sizeof(*array)測出的是數組單元的大小。

表達式array+n(其中n=0,1,2,....。)中,array扮演的是指針,故array+n的結果是一個指針,它的類型是TYPE*,它指向的類型是TYPE,

它指向數組第n號單元。故sizeof(array+n)測出的是指針類型的大小。

例十:

int array[10];

int (*ptr)[10];

ptr=&array;

上例中ptr是一個指針,它的類型是int (*)[10],他指向的類型是int [10],我們用整個數組的首地址來初始化它。在語句ptr=&array中,

array代表數組本身。

本節中提到了函數sizeof(),那麼我來問一問,sizeof(指針名稱)測出的究竟是指針自身類型的大小呢還是指針所指向的類型的大小?答案是

前者。例如:

int (*ptr)[10];

則在32位程序中,有:

sizeof(int(*)[10])==4

sizeof(int [10])==40

sizeof(ptr)==4

實際上,sizeof(對象)測出的都是對象自身的類型的大小,而不是別的什麼類型的大小。

第六章。指針和結構類型的關系

可以聲明一個指向結構類型對象的指針。

例十一:

struct MyStruct

{

int a;

int b;

int c;

}

MyStruct ss={20,30,40};//聲明了結構對象ss,並把ss的三個成員初始化為20,30和40。

MyStruct *ptr=&ss;//聲明了一個指向結構對象ss的指針。它的類型是

MyStruct*,它指向的類型是MyStruct。

int *pstr=(int*)&ss;//聲明了一個指向結構對象ss的指針。但是它的類型和它指向的類型和ptr是不同的。

請問怎樣通過指針ptr來訪問ss的三個成員變數?

答案:

ptr->a;

ptr->b;

ptr->c;

又請問怎樣通過指針pstr來訪問ss的三個成員變數?

答案:

*pstr;//訪問了ss的成員a。

*(pstr+1);//訪問了ss的成員b。

*(pstr+2)//訪問了ss的成員c。

呵呵,雖然我在我的MSVC++6.0上調式過上述代碼,但是要知道,這樣使用pstr來訪問結構成員是不正規的,為了說明為什麼不正規,讓我們看

看怎樣通過指針來訪問數組的各個單元:

例十二:

int array[3]={35,56,37};

int *pa=array;

通過指針pa訪問數組array的三個單元的方法是:

*pa;//訪問了第0號單元

*(pa+1);//訪問了第1號單元

*(pa+2);//訪問了第2號單元

從格式上看倒是與通過指針訪問結構成員的不正規方法的格式一樣。

所有的C/C++編譯器在排列數組的單元時,總是把各個數組單元存放在連續的存儲區里,單元和單元之間沒有空隙。但在存放結構對象的各個成

員時,在某種編譯環境下,可能會需要字對齊或雙字對齊或者是別的什麼對齊,需要在相鄰兩個成員之間加若干個「填充位元組」,這就導致各

個成員之間可能會有若干個位元組的空隙。

所以,在例十二中,即使*pstr訪問到了結構對象ss的第一個成員變數a,也不能保證*(pstr+1)就一定能訪問到結構成員b。因為成員a和成員b

之間可能會有若干填充位元組,說不定*(pstr+1)就正好訪問到了這些填充位元組呢。這也證明了指針的靈活性。要是你的目的就是想看看各個結構

成員之間到底有沒有填充位元組,嘿,這倒是個不錯的方法。

通過指針訪問結構成員的正確方法應該是象例十二中使用指針ptr的方法。

第七章。指針和函數的關系

可以把一個指針聲明成為一個指向函數的指針。

int fun1(char*,int);

int (*pfun1)(char*,int);

pfun1=fun1;

....

....

int a=(*pfun1)("abcdefg",7);//通過函數指針調用函數。

可以把指針作為函數的形參。在函數調用語句中,可以用指針表達式來作為實參。
例十三:

int fun(char*);

int a;

char str[]="abcdefghijklmn";

a=fun(str);

...

...

int fun(char*s)

{

int num=0;

for(int i=0;i <strlen(s);i++)

{

num+=*s;s++;

}

return num;

}

這個例子中的函數fun統計一個字元串中各個字元的ASCII碼值之和。前面說了,數組的名字也是一個指針。在函數調用中,當把str作為實參傳

遞給形參s後,實際是把str的值傳遞給了s,s所指向的地址就和str所指向的地址一致,但是str和s各自佔用各自的存儲空間。在函數體內對s

進行自加1運算,並不意味著同時對str進行了自加1運算。

第八章。指針類型轉換

當我們初始化一個指針或給一個指針賦值時,賦值號的左邊是一個指針,賦值號的右邊是一個指針表達式。在我們前面所舉的例子中,絕大多

數情況下,指針的類型和指針表達式的類型是一樣的,指針所指向的類型和指針表達式所指向的類型是一樣的。

例十四:

1。 float f=12.3;

2。 float *fptr=&f;

3。 int *p;

在上面的例子中,假如我們想讓指針p指向實數f,應該怎麼搞?是用下面的語句嗎?

p=&f;

不對。因為指針p的類型是int*,它指向的類型是int。表達式&f的結果是一個指針,指針的類型是float*,它指向的類型是 float。兩者不一致

,直接賦值的方法是不行的。至少在我的MSVC++6.0上,對指針的賦值語句要求賦值號兩邊的類型一致,所指向的類型也一致,其它的編譯器上

我沒試過,大家可以試試。為了實現我們的目的,需要進行「強制類型轉換」:

p=(int*)&f;

如果有一個指針p,我們需要把它的類型和所指向的類型改為TYEP*和TYPE,那麼語法格式是:

(TYPE*)p;

這樣強制類型轉換的結果是一個新指針,該新指針的類型是TYPE*,它指向的類型是TYPE,它指向的地址就是原指針指向的地址。而原來的指針

p的一切屬性都沒有被修改。

一個函數如果使用了指針作為形參,那麼在函數調用語句的實參和形參的結合過程中,也會發生指針類型的轉換。

例十五:

void fun(char*);

int a=125,b;

fun((char*)&a);

...

...

void fun(char*s)

{

char c;

c=*(s+3);*(s+3)=*(s+0);*(s+0)=c;

c=*(s+2);*(s+2)=*(s+1);*(s+1)=c;

}

注意這是一個32位程序,故int類型佔了四個位元組,char類型佔一個位元組。函數fun的作用是把一個整數的四個位元組的順序來個顛倒。注意到了

嗎?在函數調用語句中,實?amp;a的結果是一個指針,它的類型是int *,它指向的類型是int。形參這個指針的類型是char*,它指向的類型是

char。這樣,在實參和形參的結合過程中,我們必須進行一次從int*類型到char*類型的轉換。結合這個例子,我們可以這樣來想像編譯器進行

轉換的過程:編譯器先構造一個臨時指針 char*temp,然後執行temp=(char*)&a,最後再把temp的值傳遞給s。所以最後的結果是:s的類型是

char*,它指向的類型是char,它指向的地址就是a的首地址。

我們已經知道,指針的值就是指針指向的地址,在32位程序中,指針的值其實是一個32位整數。那可不可以把一個整數當作指針的值直接賦給

指針呢?就象下面的語句:

unsigned int a;

TYPE *ptr;//TYPE是int,char或結構類型等等類型。

...

...

a=20345686;

ptr=20345686;//我們的目的是要使指針ptr指向地址20345686(十進制)

ptr=a;//我們的目的是要使指針ptr指向地址20345686(十進制)

編譯一下吧。結果發現後面兩條語句全是錯的。那麼我們的目的就不能達到了嗎?不,還有辦法:

unsigned int a;

TYPE *ptr;//TYPE是int,char或結構類型等等類型。

...

...

a=某個數,這個數必須代表一個合法的地址;

ptr=(TYPE*)a;//呵呵,這就可以了。

嚴格說來這里的(TYPE*)和指針類型轉換中的(TYPE*)還不一樣。這里的(TYPE*)的意思是把無符號整數a的值當作一個地址來看待。

上面強調了a的值必須代表一個合法的地址,否則的話,在你使用ptr的時候,就會出現非法操作錯誤。

想想能不能反過來,把指針指向的地址即指針的值當作一個整數取出來。完全可以。下面的例子演示了把一個指針的值當作一個整數取出來,

然後再把這個整數當作一個地址賦給一個指針:

例十六:

int a=123,b;

int *ptr=&a;

char *str;

b=(int)ptr;//把指針ptr的值當作一個整數取出來。

str=(char*)b;//把這個整數的值當作一個地址賦給指針str。

好了,現在我們已經知道了,可以把指針的值當作一個整數取出來,也可以把一個整數值當作地址賦給一個指針。

第九章。指針的安全問題

看下面的例子:

例十七:

char s='a';

int *ptr;

ptr=(int*)&s;

*ptr=1298;

指針ptr是一個int*類型的指針,它指向的類型是int。它指向的地址就是s的首地址。在32位程序中,s佔一個位元組,int類型佔四個位元組。最後

一條語句不但改變了s所佔的一個位元組,還把和s相臨的高地址方向的三個位元組也改變了。這三個位元組是干什麼的?只有編譯程序知道,而寫程

序的人是不太可能知道的。也許這三個位元組里存儲了非常重要的數據,也許這三個位元組里正好是程序的一條代碼,而由於你對指針的馬虎應用

,這三個位元組的值被改變了!這會造成崩潰性的錯誤。讓我們再來看一例:

例十八:

1。 char a;

2。 int *ptr=&a;

...

...

3。 ptr++;

4。 *ptr=115;

該例子完全可以通過編譯,並能執行。但是看到沒有?第3句對指針ptr進行自加1運算後,ptr指向了和整形變數a相鄰的高地址方向的一塊存儲

區。這塊存儲區里是什麼?我們不知道。有可能它是一個非常重要的數據,甚至可能是一條代碼。而第4句竟然往這片存儲區里寫入一個數據!

這是嚴重的錯誤。所以在使用指針時,程序員心裡必須非常清楚:我的指針究竟指向了哪裡。

在用指針訪問數組的時候,也要注意不要超出數組的低端和高端界限,否則也會造成類似的錯誤。

在指針的強制類型轉換:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的類型)大於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的

存儲區時是安全的。如果sizeof(ptr2的類型)小於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的存儲區時是不安全的。至於

為什麼,讀者結合例十七來想一想,應該會明白的。

請寫出以下程序的運行結果:

#include <stdio.h>
int *p;
pp(int a,int *b);
main()
{
int a=1,b=2,c=3;
p=&b;
pp(a+c,&b);
printf("(1)%d%d%dn",a,b,*p);
}
pp(int a,int *b)
{int c=4;
*p=*b+c;
a=*p-c;
printf("(2)%d%d%dn",a,*b,*p);
}

Ⅱ C語言目錄有什麼

第1章 C語言基礎知識

1.1 C語言概述
1.1.1 C程序的結構
1.1.2 C程序的上機步驟
1.2 C語言的基本數據類型
1.2.1 標識符
1.2.2 常量
1.2.3 變數
1.3 基本輸入/輸出函數
1.3.1 格式化輸出函數
1.3.2 格式化輸入函數
1.3.3 字元輸入/輸出函數
1.4 運算符和表達式
1.4.1 算術運算符與算術表達式
1.4.2 賦值運算符與賦值表達式
1.4.3 逗號運算符與逗號表達式
1.4.4 簡單的位運算與位表達式
1.4.5 運算符的優先順序
1.5 類型轉換
1.5.1 隱式類型轉換
1.5.2 顯式類型轉換
1.6 C程序展示
本章小結
習題
第2章 演算法
2.1 演算法的概念
2.2 利用計算機求解問題的一般過程
2.3 演算法的描述
2.3.1 用自然語言描述演算法
2.3.2 用流程圖描述演算法
2.3.3 用N-S流程圖描述演算法
2.3.4 用偽代碼描述演算法
2.3.5 用計算機語言描述演算法
2.4 演算法舉例
本章小結
習題
第3章 C程序的控制結構
3.1 分支結構
3.1.1 關系表達式和邏輯表達式
3.1.2 if語句
3.1.3 條件表達式
3.1.4 switch語句
3.2 循環結構
3.2.1 while語句
3.2.2 do…while語句
3.2.3 for語句
3.2.4 break語句和continue語句
3.2.5 循環的嵌套
3.3 綜合應用
本章小結
習題
第4章 數組與指針
4.1 數組
4.1.1 一維數組
4.1.2 二維數組
4.1.3 字元數組
4.2 指針
4.2.1 指針變數的定義與相關運算
4.2.2 指針與一維數組
4.2.3 指針與二維數組
4.2.4 指針數組
4.2.5 指針與字元串
4.3 動態內存分配
4.4 數組與指針綜合應用
4.4.1 單詞統計
4.4.2 排序
4.4.3 查找
4.4.4 進制轉換
4.4.5 二維數組應用
本章小結
習題
第5章 函數
5.1 函數概述
5.1.1 函數的定義
5.1.2 函數的聲明和調用
5.2 函數參數的傳遞方式
5.2.1 值傳遞方式
5.2.2 地址傳遞方式
5.3 函數的嵌套與遞歸
5.3.1 函數的嵌套調用
5.3.2 函數的遞歸調用
5.4 變數的作用域與存儲類型
5.4.1 變數的作用域
5.4.2 變數的存儲類型
5.5 內部函數和外部函數
5.5.1 內部函數
5.5.2 外部函數
5.6 編譯預處理
5.6.1 宏定義
5.6.2 文件包含
5.6.3 條件編譯
5.7 標准函數簡介
5.7.1 字元串處理函數
5.7.2 字元處理函數
5.7.3 動態地址分配函數
5.7.4 數學函數
5.7.5 數據類型轉換函數
5.7.6 其他函數
5.8 函數綜合應用案例
5.8.1 字元串處理函數應用
5.8.2 函數指針應用
5.8.3 遞歸演算法應用
本章小結
習題
第6章 結構體與共用體
6.1 結構體類型
6.1.1 結構體類型的定義和使用
6.1.2 指向結構體類型數據的指針
6.2 共用體與枚舉類型
6.2.1 共用體
6.2.2 枚舉類型
6.3 鏈表
6.4 結構體綜合應用
6.4.1 學生成績查詢
6.4.2 個人通訊錄
本章小結
習題
第7章 文件操作
7.1 文件概述
7.1.1 文件的概念
7.1.2 文件類型指針
7.1.3 文件的操作
7.2 文件的打開和關閉
7.2.1 文件打開函數
7.2.2 文件關閉函數
7.3 文件的順序讀/寫
7.3.1 字元讀/寫函數
7.3.2 字元串讀/寫函數
7.3.3 格式化讀/寫函數
7.3.4 二進制文件讀/寫函數
7.4 文件的隨機讀/寫
7.5 文件狀態檢查函數
7.5.1 文件讀/寫結束檢查函數
7.5.2 文件出錯檢查函數
7.5.3 文件出錯復位函數
本章小結
習題
第8章 C語言課程設計
8.1 C語言課程設計實施方案
8.2 C語言課程設計任務書1
8.3 C語言課程設計任務書2
8.4 C語言課程設計任務書3
8.5 C語言課程設計任務書4
8.6 C語言課程設計任務書5
附錄A 常用字元與ASCII(十進制)對照表
附錄B C語言課程設計模板
參考文獻

Ⅲ C語言的文件的位置指針

網上給你找的,你看看哈。注意形象化的概念。
-----------------------------
在學習文件定位函數之前,需要了解一下文件位置指針的概念。文件位置指針只是一個形象化的概念,在C語言中用文件位置指針來表示文件當前讀或寫的數據在文件中的位置。當通過fopen函數打開文件時,可以認為文件位置指針總是指向文件的開頭、第一個數據之前。

當文件位置指針指向文件末尾時,表示文件結束。當進行讀操作時,總是從文件位置指針所指的位置開始,去讀其後的數據,然後位置指針移到尚未讀的數據之前,以備指示下一次的讀(或寫)操作。當進行寫操作時,總是從文件位置指針所指位置去寫,然後移到剛寫入的數據之後,以備指示下一次輸出的起始位置。

「文件指針」和「文件位置指針」是兩個不同的概念。

文件指針是指在程序中定義的FILE類型的變數,通過fopen函數調用給文件指針賦值,使文件指針和某個文件建立聯系(這種聯系實際上是通過fopen函數說明使用文件的方式),C語言中通過文件指針實現對文件的各種操作。

摘自:東北大學出版社李一波編著《新概念C語言》
--------------------------------------

Ⅳ c語言中指針那一章,定義二維數組a[5][6],(*p)[6],&a和a有什麼區別能不能*p=a 求答案……

a[5][6]
你會發現,a, *a, &a的值是相同的,介意義完全不同
首先這個數組是5行6列, 首先要明白a是一個地址,而且是第一列的地址
a+1是第二列的地址,a+2是第三列的地址....
*a是第一列第一個元素的地址,*a+1第一列第二個元素的地址...
&a是整個二維數組的地址,&a+1是內存中緊跟a[5][6]這塊區域的地址

(*p)[6]
這里的p的效果等於a,也是第一列的地址
*p=a
*p是第一行第一個元素的地址,a 是第一行的地址
兩者代表的意義不是一個等級,編譯會出錯
而且這樣賦值沒有意義

Ⅳ c語言關於指針的求解

int x[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, *p1;

(A) x[3]// x[3]=3 數組從0開始,3其實是第四個
(B) p1 = x + 3, *p1++ //先執行p1=x+3,也就是指向x[3],因為p1定義成指針。*p1++ 這時候先執行再加,這表達式仍然是3
(C) p1 = x + 2, *(p1++) //p=x+2 ,x數組的地址加2,也就是指向x[2],x=2,這時候p++同時也是先執行後加,所以取出x[2]的值,所以等於2
(D) p1 = x + 2, *++p1//同樣,p1指向x[2],但++是先加再執行*取值,所以++p指向x[3],取出來的值就是3
答案是 C

Ⅵ C語言,關潭浩強的指針一章

我記得當時我讀大一的時候,老師也這么說的,考試不考。不過我還是自學了。其實也沒有很難,理清內存存儲原理就行了。假設我們把進超市的儲物櫃當成內存。那麼儲物櫃的編號就是內存地址,儲物櫃裡面放的東西,就是內存中放的值。
我們平時定義
int
a=6;就相當於系統先找個空的儲物櫃(譬如編號是1002),給它起個小名叫a,然後把6放進去。
&a(這個貌似是取地址,即指針,C好久沒用了),取到的值就是1002。
這是一個很簡單的例子,有時候指針指向的不是一個櫃子,而是一片區域,譬如第一排的櫃子(假如從1001-1010),而指針只記錄一個
入口地址
,即1001

這個就是後面所說的數組指針,函數指針等。
其實學理科主要學的一個原理。聯系實際多思考思考。

Ⅶ c語言中的指針應該怎麼理解

這是我收錄的指針講義

第一章。指針的概念

指針是一個特殊的變數,它裡面存儲的數值被解釋成為內存里的一個地址。

要搞清一個指針需要搞清指針的四方面的內容:指針的類型,指針所指向的 類型,指針的值或者叫指針所指向的內存區,還有指針本身所佔據的內存區。讓 我們分別說明。
先聲明幾個指針放著做例子:
例一:
(1)int *ptr;
(2)char *ptr;
(3)int **ptr;
(4)int (*ptr)[3];
(5)int *(*ptr)[4];

1。 指針的類型。
從語法的角度看,你只要把指針聲明語句里的指針名字去掉,剩下的部分就是這個指針的類型。這是指針本身所具有的類型。讓我們看看例一中各個指針的 類型:
(1)int *ptr; //指針的類型是int *
(2)char *ptr; //指針的類型是char *
(3)int **ptr; //指針的類型是 int **
(4)int (*ptr)[3]; //指針的類型是 int(*)[3]
(5)int *(*ptr)[4]; //指針的類型是 int *(*)[4]
怎麼樣?找出指針的類型的方法是不是很簡單?

2。指針所指向的類型。
當你通過指針來訪問指針所指向的內存區時,指針所指向的類型決定了編譯 器將把那片內存區里的內容當做什麼來看待。
從語法上看,你只須把指針聲明語句中的指針名字和名字左邊的指針聲明符 *去掉,剩下的就是指針所指向的類型。例如:
(1)int *ptr; //指針所指向的類型是int
(2)char *ptr; //指針所指向的的類型是char
(3)int **ptr; //指針所指向的的類型是 int *
(4)int (*ptr)[3]; //指針所指向的的類型是 int()[3]
(5)int *(*ptr)[4]; //指針所指向的的類型是 int *()[4]
在指針的算術運算中,指針所指向的類型有很大的作用。
指針的類型(即指針本身的類型)和指針所指向的類型是兩個概念。當你對C越 來越熟悉時,你會發現,把與指針攪和在一起的"類型"這個概念分成"指針的 類型"和"指針所指向的類型"兩個概念,是精通指針的關鍵點之一。我看了不 少書,發現有些寫得差的書中,就把指針的這兩個概念攪在一起了,所以看起書來前後矛盾,越看越糊塗。

3。 指針的值,或者叫指針所指向的內存區或地址。
指針的值是指針本身存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數值。在32位程序里,所有類型的指針的值都是一個32位整數,因為32位程序里內存地址全都是32位長。
指針所指向的內存區就是從指針的值所代表的那個內存地址開始,長度為sizeof(指針所指向的類型)的一片內存區。以後,我們說一個指針的值是XX,就相當於說該指針指向了以XX為首地址的一片內存區域;我們說一個指針指向了某塊
內存區域,就相當於說該指針的值是這塊內存區域的首地址。
指針所指向的內存區和指針所指向的類型是兩個完全不同的概念。在例一中,指針所指向的類型已經有了,但由於指針還未初始化,所以它所指向的內存區是不存在的,或者說是無意義的。
以後,每遇到一個指針,都應該問問:這個指針的類型是什麼?指針指向的類型是什麼?該指針指向了哪裡?
4。 指針本身所佔據的內存區。
指針本身佔了多大的內存?你只要用函數sizeof(指針的類型)測一下就知道了。在32位平台里,指針本身占據了4個位元組的長度。
指針本身占據的內存這個概念在判斷一個指針表達式是否是左值時很有用。

第二章。指針的算術運算

指針可以加上或減去一個整數。指針的這種運算的意義和通常的數值的加減運算的意義是不一樣的。例如:
例二:
1。 char a[20];
2。 int *ptr=a;
...
...
3。 ptr++;
在上例中,指針ptr的類型是int*,它指向的類型是int,它被初始化為指向整 形變數a。接下來的第3句中,指針ptr被加了1,編譯器是這樣處理的:它把指針ptr的值加上了sizeof(int),在32位程序中,是被加上了4。由於地址是用位元組做單位的,故ptr所指向的地址由原來的變數a的地址向高地址方向增加了4個位元組。
由於char類型的長度是一個位元組,所以,原來ptr是指向數組a的第0號單元開始的四個位元組,此時指向了數組a中從第4號單元開始的四個位元組。
我們可以用一個指針和一個循環來遍歷一個數組,看例子:
例三:
int array[20];
int *ptr=array;
...
//此處略去為整型數組賦值的代碼。
...
for(i=0;i<20;i++)
{
(*ptr)++;
ptr++;
}
這個例子將整型數組中各個單元的值加1。由於每次循環都將指針ptr加1,所
以每次循環都能訪問數組的下一個單元。
再看例子:
例四:
1。 char a[20];
2。 int *ptr=a;
...
...
3。 ptr+=5;
在這個例子中,ptr被加上了5,編譯器是這樣處理的:將指針ptr的值加上5 乘sizeof(int),在32位程序中就是加上了5乘4=20。由於地址的單位是位元組,故現在的ptr所指向的地址比起加5後的ptr所指向的地址來說,向高地址方向移動了20個位元組。在這個例子中,沒加5前的ptr指向數組a的第0號單元開始的四個位元組,加5後,ptr已經指向了數組a的合法范圍之外了。雖然這種情況在應用上會出問題,但在語法上卻是可以的。這也體現出了指針的靈活性。
如果上例中,ptr是被減去5,那麼處理過程大同小異,只不過ptr的值是被減去5乘sizeof(int),新的ptr指向的地址將比原來的ptr所指向的地址向低地址方向移動了20個位元組。

總結一下,一個指針ptrold加上一個整數n後,結果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold所指向的類型也相同。ptrnew的值將比ptrold的值增加了n乘sizeof(ptrold所指向的類型)個位元組。就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向高地址方向移動了n乘sizeof(ptrold所指向的類型)個位元組。
一個指針ptrold減去一個整數n後,結果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold所指向的類型也相同。ptrnew的值將比ptrold的值減少了n乘sizeof(ptrold所指向的類型)個位元組,就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向低地址方向移動了n乘sizeof(ptrold所指向的類型)個位元組。

第三章。運算?amp;和*

這里&是取地址運算符,*是...書上叫做"間接運算符"。
&a的運算結果是一個指針,指針的類型是a的類型加個*,指針所指向的類型是a的類型,指針所指向的地址嘛,那就是a的地址。
*p的運算結果就五花八門了。總之*p的結果是p所指向的東西,這個東西有這些特點:它的類型是p指向的類型,它所佔用的地址是p所指向的地址。
例五:
int a=12;
int b;
int *p;
int **ptr;
p=&a;//&a的結果是一個指針,類型是int*,指向的類型是int,指向的地址 是a的地址。
*p=24;//*p的結果,在這里它的類型是int,它所佔用的地址是p所指向的地 址,顯然,*p就是變數a。
ptr=&p;//&p的結果是個指針,該指針的類型是p的類型加個*,在這里是int
**。該指針所指向的類型是p的類型,這里是int*。該指針所指向的地址就是指針p自己的地址。
*ptr=&b;//*ptr是個指針,&b的結果也是個指針,且這兩個指針的類型和所 指向的類型是一樣的,所以用&b來給*ptr賦值就是毫無問題的了。
**ptr=34;//*ptr的結果是ptr所指向的東西,在這里是一個指針,對這個指
針再做一次*運算,結果就是一個int類型的變數。

第四章。指針表達式。

一個表達式的最後結果如果是一個指針,那麼這個表達式就叫指針表達式。
下面是一些指針表達式的例子:
例六:
int a,b;
int array[10];
int *pa;
pa=&a;//&a是一個指針表達式。
int **ptr=&pa;//&pa也是一個指針表達式。
*ptr=&b;//*ptr和&b都是指針表達式。
pa=array;
pa++;//這也是指針表達式。
例七:
char *arr[20];
char **parr=arr;//如果把arr看作指針的話,arr也是指針表達式
char *str;
str=*parr;//*parr是指針表達式
str=*(parr+1);//*(parr+1)是指針表達式
str=*(parr+2);//*(parr+2)是指針表達式

由於指針表達式的結果是一個指針,所以指針表達式也具有指針所具有的四個要素:指針的類型,指針所指向的類型,指針指向的內存區,指針自身占據的內存。
好了,當一個指針表達式的結果指針已經明確地具有了指針自身占據的內存的話,這個指針表達式就是一個左值,否則就不是一個左值。
在例七中,&a不是一個左值,因為它還沒有占據明確的內存。*ptr是一個左值,因為*ptr這個指針已經占據了內存,其實*ptr就是指針pa,既然pa已經在內存中有了自己的位置,那麼*ptr當然也有了自己的位置。

第五章。數組和指針的關系

如果對聲明數組的語句不太明白的話,請參閱我前段時間貼出的文?lt;>。
數組的數組名其實可以看作一個指針。看下例:
例八:
int array[10]={0,1,2,3,4,5,6,7,8,9},value;
...
...
value=array[0];//也可寫成:value=*array;
value=array[3];//也可寫成:value=*(array+3);
value=array[4];//也可寫成:value=*(array+4);
上例中,一般而言數組名array代表數組本身,類型是int [10],但如果把a
rray看做指針的話,它指向數組的第0個單元,類型是int *,所指向的類型是數組單元的類型即int。因此*array等於0就一點也不奇怪了。同理,array+3是一個指向數組第3個單元的指針,所以*(array+3)等於3。其它依此類推。
例九:
char *str[3]={
"Hello,this is a sample!",
"Hi,good morning.",
"Hello world"
};
char s[80];
strcpy(s,str[0]);//也可寫成strcpy(s,*str);
strcpy(s,str[1]);//也可寫成strcpy(s,*(str+1));
strcpy(s,str[2]);//也可寫成strcpy(s,*(str+2));
上例中,str是一個三單元的數組,該數組的每個單元都是一個指針,這些指針各指向一個字元串。把指針數組名str當作一個指針的話,它指向數組的第0號單元,它的類型是char**,它指向的類型是char *。
*str也是一個指針,它的類型是char*,它所指向的類型是char,它指向的地址是字元串"Hello,this is a sample!"的第一個字元的地址,即』H』的地址。
str+1也是一個指針,它指向數組的第1號單元,它的類型是char**,它指向的類型是char *。
*(str+1)也是一個指針,它的類型是char*,它所指向的類型是char,它指向"Hi,good morning."的第一個字元』H』,等等。

下面總結一下數組的數組名的問題。聲明了一個數組TYPE array[n],則數組名稱array就有了兩重含義:第一,它代表整個數組,它的類型是TYPE [n];第二,它是一個指針,該指針的類型是TYPE*,該指針指向的類型是TYPE,也就是數組單元的類型,該指針指向的內存區就是數組第0號單元,該指針自己佔有單獨的內存區,注意它和數組第0號單元占據的內存區是不同的。該指針的值是不能修改的,即類似array++的表達式是錯誤的。
在不同的表達式中數組名array可以扮演不同的角色。
在表達式sizeof(array)中,數組名array代表數組本身,故這時sizeof函數
測出的是整個數組的大小。
在表達式*array中,array扮演的是指針,因此這個表達式的結果就是數組第0號單元的值。sizeof(*array)測出的是數組單元的大小。
表達式array+n(其中n=0,1,2,....。)中,array扮演的是指針,故arr
ay+n的結果是一個指針,它的類型是TYPE*,它指向的類型是TYPE,它指向數組第n號單元。故sizeof(array+n)測出的是指針類型的大小。
例十:
int array[10];
int (*ptr)[10];
ptr=&array;
上例中ptr是一個指針,它的類型是int (*)[10],他指向的類型是int [10]
,我們用整個數組的首地址來初始化它。在語句ptr=&array中,array代表數組本身。

本節中提到了函數sizeof(),那麼我來問一問,sizeof(指針名稱)測出的究
竟是指針自身類型的大小呢還是指針所指向的類型的大小?答案是前者。例如:

int (*ptr)[10];
則在32位程序中,有:
sizeof(int(*)[10])==4
sizeof(int [10])==40
sizeof(ptr)==4
實際上,sizeof(對象)測出的都是對象自身的類型的大小,而不是別的什麼類型的大小。

第六章。指針和結構類型的關系

可以聲明一個指向結構類型對象的指針。
例十一:
struct MyStruct
{
int a;
int b;
int c;
}
MyStruct ss={20,30,40};//聲明了結構對象ss,並把ss的三個成員初始
化為20,30和40。
MyStruct *ptr=&ss;//聲明了一個指向結構對象ss的指針。它的類型是
MyStruct*,它指向的類型是MyStruct。
int *pstr=(int*)&ss;//聲明了一個指向結構對象ss的指針。但是它的
類型和它指向的類型和ptr是不同的。

請問怎樣通過指針ptr來訪問ss的三個成員變數?
答案:
ptr->a;
ptr->b;
ptr->c;
又請問怎樣通過指針pstr來訪問ss的三個成員變數?
答案:
*pstr;//訪問了ss的成員a。
*(pstr+1);//訪問了ss的成員b。
*(pstr+2)//訪問了ss的成員c。
呵呵,雖然我在我的MSVC++6.0上調式過上述代碼,但是要知道,這樣使用p
str來訪問結構成員是不正規的,為了說明為什麼不正規,讓我們看看怎樣通過指
針來訪問數組的各個單元:
例十二:
int array[3]={35,56,37};
int *pa=array;
通過指針pa訪問數組array的三個單元的方法是:
*pa;//訪問了第0號單元
*(pa+1);//訪問了第1號單元
*(pa+2);//訪問了第2號單元
從格式上看倒是與通過指針訪問結構成員的不正規方法的格式一樣。
所有的C/C++編譯器在排列數組的單元時,總是把各個數組單元存放在連續的存儲區里,單元和單元之間沒有空隙。但在存放結構對象的各個成員時,在某種編譯環境下,可能會需要字對齊或雙字對齊或者是別的什麼對齊,需要在相鄰兩個成員之間加若干?quot;填充位元組",這就導致各個成員之間可能會有若干個位元組的空隙。
所以,在例十二中,即使*pstr訪問到了結構對象ss的第一個成員變數a,也不能保證*(pstr+1)就一定能訪問到結構成員b。因為成員a和成員b之間可能會有若干填充位元組,說不定*(pstr+1)就正好訪問到了這些填充位元組呢。這也證明了指針的靈活性。要是你的目的就是想看看各個結構成員之間到底有沒有填充位元組,
嘿,這倒是個不錯的方法。
通過指針訪問結構成員的正確方法應該是象例十二中使用指針ptr的方法。

第七章。指針和函數的關系

可以把一個指針聲明成為一個指向函數的指針。
int fun1(char*,int);
int (*pfun1)(char*,int);
pfun1=fun1;
....
....
int a=(*pfun1)("abcdefg",7);//通過函數指針調用函數。
可以把指針作為函數的形參。在函數調用語句中,可以用指針表達式來作為
實參。
例十三:
int fun(char*);
int a;
char str[]="abcdefghijklmn";
a=fun(str);
...
...
int fun(char*s)
{
int num=0;
for(int i=0;i
{
num+=*s;s++;
}
return num;
)
這個例子中的函數fun統計一個字元串中各個字元的ASCII碼值之和。前面說了,數組的名字也是一個指針。在函數調用中,當把str作為實參傳遞給形參s後,實際是把str的值傳遞給了s,s所指向的地址就和str所指向的地址一致,但是str和s各自佔用各自的存儲空間。在函數體內對s進行自加1運算,並不意味著同時對str進行了自加1運算。

第八章。指針類型轉換

當我們初始化一個指針或給一個指針賦值時,賦值號的左邊是一個指針,賦值號的右邊是一個指針表達式。在我們前面所舉的例子中,絕大多數情況下,指針的類型和指針表達式的類型是一樣的,指針所指向的類型和指針表達式所指向的類型是一樣的。
例十四:
1。 float f=12.3;
2。 float *fptr=&f;
3。 int *p;
在上面的例子中,假如我們想讓指針p指向實數f,應該怎麼搞?是用下面的語句嗎?
p=&f;
不對。因為指針p的類型是int*,它指向的類型是int。表達式&f的結果是一
個指針,指針的類型是float*,它指向的類型是float。兩者不一致,直接賦值的方法是不行的。至少在我的MSVC++6.0上,對指針的賦值語句要求賦值號兩邊的類型一致,所指向的類型也一致,其它的編譯器上我沒試過,大家可以試試。為了實現我們的目的,需要進行"強制類型轉換":
p=(int*)&f; 如果有一個指針p,我們需要把它的類型和所指向的類型改為TYEP*和TYPE,
那麼語法格式是:
(TYPE*)p;
這樣強制類型轉換的結果是一個新指針,該新指針的類型是TYPE*,它指向的類型是TYPE,它指向的地址就是原指針指向的地址。而原來的指針p的一切屬性都沒有被修改。

一個函數如果使用了指針作為形參,那麼在函數調用語句的實參和形參的結合過程中,也會發生指針類型的轉換。
例十五:
void fun(char*);
int a=125,b;
fun((char*)&a);
...
...
void fun(char*s)
{
char c;
c=*(s+3);*(s+3)=*(s+0);*(s+0)=c;
c=*(s+2);*(s+2)=*(s+1);*(s+1)=c;
}
}
注意這是一個32位程序,故int類型佔了四個位元組,char類型佔一個位元組。函數fun的作用是把一個整數的四個位元組的順序來個顛倒。注意到了嗎?在函數調用語句中,實參&a的結果是一個指針,它的類型是int *,它指向的類型是int。形參這個指針的類型是char*,它指向的類型是char。這樣,在實參和形參的結合過程中,我們必須進行一次從int*類型到char*類型的轉換。結合這個例子,我們可以這樣來想像編譯器進行轉換的過程:編譯器先構造一個臨時指針 char*temp,然後執行temp=(char*)&a,最後再把temp的值傳遞給s。所以最後的結果是:s的類型是char*,它指向的類型是char,它指向的地址就是a的首地址。

我們已經知道,指針的值就是指針指向的地址,在32位程序中,指針的值其實是一個32位整數。那可不可以把一個整數當作指針的值直接賦給指針呢?就象下面的語句:
unsigned int a;
TYPE *ptr;//TYPE是int,char或結構類型等等類型。
...
...
a=20345686;
ptr=20345686;//我們的目的是要使指針ptr指向地址20345686(十進制

ptr=a;//我們的目的是要使指針ptr指向地址20345686(十進制)
編譯一下吧。結果發現後面兩條語句全是錯的。那麼我們的目的就不能達到了嗎?不,還有辦法:
unsigned int a;
TYPE *ptr;//TYPE是int,char或結構類型等等類型。
...
...
a=某個數,這個數必須代表一個合法的地址;
ptr=(TYPE*)a;//呵呵,這就可以了。
嚴格說來這里的(TYPE*)和指針類型轉換中的(TYPE*)還不一樣。這里的(TYPE*)的意思是把無符號整數a的值當作一個地址來看待。
上面強調了a的值必須代表一個合法的地址,否則的話,在你使用ptr的時候,就會出現非法操作錯誤。

想想能不能反過來,把指針指向的地址即指針的值當作一個整數取出來。完全可以。下面的例子演示了把一個指針的值當作一個整數取出來,然後再把這個整數當作一個地址賦給一個指針:
例十六:
int a=123,b;
int *ptr=&a;
char *str;
b=(int)ptr;//把指針ptr的值當作一個整數取出來。
str=(char*)b;//把這個整數的值當作一個地址賦給指針str。

好了,現在我們已經知道了,可以把指針的值當作一個整數取出來,也可以把一個整數值當作地址賦給一個指針。

第九章。指針的安全問題

看下面的例子:
例十七:
char s=』a』;
int *ptr;
ptr=(int*)&s;
*ptr=1298;
指針ptr是一個int*類型的指針,它指向的類型是int。它指向的地址就是s的首地址。在32位程序中,s佔一個位元組,int類型佔四個位元組。最後一條語句不但改變了s所佔的一個位元組,還把和s相臨的高地址方向的三個位元組也改變了。這三個位元組是干什麼的?只有編譯程序知道,而寫程序的人是不太可能知道的。也許這三個位元組里存儲了非常重要的數據,也許這三個位元組里正好是程序的一條代碼,而由於你對指針的馬虎應用,這三個位元組的值被改變了!這會造成崩潰性的錯誤。
讓我們再來看一例:
例十八:
1。 char a;
2。 int *ptr=&a;
...
...
3。 ptr++;
4。 *ptr=115;
該例子完全可以通過編譯,並能執行。但是看到沒有?第3句對指針ptr進行自加1運算後,ptr指向了和整形變數a相鄰的高地址方向的一塊存儲區。這塊存儲區里是什麼?我們不知道。有可能它是一個非常重要的數據,甚至可能是一條代碼。而第4句竟然往這片存儲區里寫入一個數據!這是嚴重的錯誤。所以在使用指針時,程序員心裡必須非常清楚:我的指針究竟指向了哪裡。
在用指針訪問數組的時候,也要注意不要超出數組的低端和高端界限,否則也會造成類似的錯誤。
在指針的強制類型轉換:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的類型)大
於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的存儲區時是安全的。如果sizeof(ptr2的類型)小於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的存儲區時是不安全的。至於為什麼,讀者結合例十七來想一想,應該會明白的。

如果對你有所幫助,請記得採納最佳答案,謝謝

Ⅷ c語言中,指針能二次賦值咩


指針變數只是存放指向存儲數據的空間的地址, 它本身並不存放實際的數據
指針就像是一本書的目錄, 如第五章在38頁, 它只是指引你到哪裡去找到第5章, 並不管第5章裡面到底寫的什麼內容, 如果編寫目錄的時候錯了,或者前面又加了章節, 目錄就要改變, 第五章在49頁, 相當於給指針賦了新值.

Ⅸ 怎樣使用C語言列出某個目錄下的文件

C語言本身沒有提供象dir_list()這樣的函數來列出某個目錄下所有的文件。不過,利用C語言的幾個目錄函數,你可以自己編寫一個dir_list()函數。 首先,頭文件dos.h定義了一個find_t結構,它可以描述DOS下的文件信息,包括文件名、時間、日期、大小和屬性。其次,C編譯程序庫中有_dos_findfirst()和_dos_findnext()這樣兩個函數,利用它們可以找到某個目錄下符合查找要求的第一個或下一個文件。 dos_findfirst()函數有三個參數,第一個參數指明要查找的文件名,例如你可以用「*.*」指明要查找某個目錄下的所有文件。第二個參數指明要查找的文件屬性,例如你可以指明只查找隱含文件或子目錄。第三個參數是指向一個find_t變數的指針,查找到的文件的有關信息將存放到該變數中。 dos_findnext()函數在相應的目錄中繼續查找由_dos_findfirst()函數的第一個參數指明的文件。_dos_findnext()函數只有一個參數,它同樣是指向一個find_t變數的指針,查找到剛文件的有關信息同樣將存放到該變數中。 利用上述兩個函數和find_t結構,你就可以遍歷磁碟上的某個目錄,並列出該目錄下所有的文件,請看下例: #include <stdio.h> #include <direct.h> #include <dos.h> #include <malloc.h> #include <memory.h> #include <string.h> typedef struct find_t FILE_BLOCK void main(void); void main(void){FILE_BLOCK f-block; /* Define the find_t structure variable * / int ret_code; / * Define a variable to store the return codes * / / * Use the "*.*" file mask and the 0xFF attribute mask to list all files in the directory, including system files, hidden files, and subdirectory names. * / ret_code = _dos_findfirst(" *. * ", 0xFF, &f_block); /* The _dos_findfirst() function returns a 0 when it is successful and has found a valid filename in the directory. * / while (ret_code == 0){/* Print the file's name * / printf(" %-12s\n, f_block, name); / * Use the -dos_findnext() function to look

Ⅹ 有關C語言中指針的理解

第1題,應該說是這樣吧,好像指針除了保存某個變數的地址外,好像沒看到指針還能表示什麼
第2題,指針變數肯定有值,它的值就是一個地址。
比如int i=1; int *p=&i;那麼指針變數p的值就是i的地址,你可以直接輸出p就得到的是p的值,而*p表示的是地址中的值,也就是指針p所指向的地址(這里是i的地址)里的值,就是1。而指針p本身也有地址,也就是&p,其中&運算符的作用就是求地址的意思,當然也可以把這個地址賦給另一個指針,接收指針地址的指針,被稱為雙重指針,也就是int **p1=&p;這樣的指針,同樣p1也有值,同時有也有址,p1的值就是指針變數p的地址,因此*p1就是指的&p1的地址,也就是p,然後**p就表示的是p所指向的地址的值,也就是i的值1了。