日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

指针、数组、函数阶段小结

發布時間:2024/4/24 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 指针、数组、函数阶段小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引子:數據在內存中是如何存儲的,又是如何讀取的?內存編號就是內存的地址(內存中每個字節都有一個編號,即地址)

1.概念:

地址:內部存儲器的編號,稱為地址。如變量a的位置編號,變量b的位置都是指針。

指針變量:專門存放地址的變量稱為指針變量。

地址、指針、指針變量都稱為指針。

一、變量的地址(指針)和指向變量的地址變量(指針)

概念:

變量的指針: 就是變量的地址。

指針變量: 是用來存放地址的變量,普通變量是用來存放數據的,指針變量是存放地址的。

2.定義地址變量:

1)?格式:[ 存儲類型 ] ?數據類型 ??*指針變量名;

int i, j;

int * pointer1, *pointer2;

存儲類型是這個地址變量的存儲位置

數據類型指的是這個地址變量指向的目標變量類型,不代表本身的類型大小。

2)?指針變量的賦值:

方法一:

int ?a = 5; ?int *p = &a; //定義并初始化。

方法二:

int ?a = 5; int *p; ?p = &a;// ?先定義后賦值。

PS

定義時,int *p*是為了說明該p是地址變量,用來存放地址;

定義地址變量時必須指定數據類型,不同類型指針不可相互賦值;

指針變量的數據類型不表示變量的類型,是表示該變量指向的目標的數據類型,訪問內存時讀取的內存空間大小。

3.指針變量引用

*&符號

??* 定義指針變量/取地址對應的變量的內容(間接訪問)//i = 3直接,*p=3間接

??& 取變量的地址。

??

*&互為逆運算。自右向左

3)?引用

??對指針變量賦值

p = &a;

??引用地址變量指向的內容

printf( “a=%d\n”, ?*p );

??引用變量本身的內容(即存儲的地址)

printf(“%x\n”, ?p);

eg

int i = 188; int *p = &i;

p ?指針變量,內部存放的是目標的地址;

*p 目標,目標內存數據;

&p 指針變量的內存地址;

p = &i = &(*p)

i = *p = *(&i)

4.指針運算

指針運算就是地址運算,即指針變量中的地址作為運算量。

地址只能做算術、關系、賦值運算。

算術運算

px + n 代表指針向地址大的方向移動 n 個 數據。

移動后的地址量是: (px) + sizeof(px的類型) * n

px++ ?指針變量向地址大的方向移動一個數據。

? px - py 表示兩個相同類型指針間相差數據的個數,而不是一個地址量。

px - py的結果是 ?(px - py) /sizeof(數據類型)

px + py 的結果? 沒有任何意義

指針加發運算加的數值是增加地址本身類型的N倍大小(這在數組中訪問經常用到)

?

4)?關系運算

?

指針關系表示兩個指針在內存位置的高低關系。

不同數據區域間的指針,關系運算沒有意義。

指針和除0外的整數比較沒有意義,和0比較可以判定指針是否為空。(標準寫法為if (NULL == p) ).

5)?賦值運算

向指針變量傳遞一個地址值。這個值是地址常量或指針變量(同類型),不能是普通整數(0可以表示空值)

6)?const/void指針

const 表示的使變量常量化,即不可修改。

int ?const a = 9;

a = 10; //報錯,aconst修飾不可改變。

const 在遇到指針時會發生一些變化

const int a int const aconst可以在int的左右位置。

???int a = 9;

???int b = 12;

???const ?int ?*p = &a;?// const 修飾的是*p , ?pa 指向變量aint ?const ?*p ????= &a; ?//和上面效果相同, 都表示地址變量pa指向a,且*pa不可變

??*p ?= 10 ; // 通過p改變a的值,但*pconst類型,不可改變。

???p = &b;?//可以改變p的值,(即指向)

???*p = ?11;// 同樣不可以

???int *const q = &a; ?//const 修飾的是 q, 所以q是不能改變的,即不能改變q的指向

???*q = 111;

????q = &b; // q指向b,報錯。

?

void 型指針

???指針變量指向不確定數據類型的變量的時候,可以定義為void型指針,

因為void類型指針可以賦值給其他任意類型的指針,而其他類型不能相互賦值.

如:malloc函數

void * malloc(size_t size);

malloc 函數因為不知道分配空間的具體用途,所以返回void型地址。

?

7)?多級指針

指向地址變量的地址變量,稱為多級指針(畫圖表示)

定義一個二級指針

int *p = &a;

int **q = &p;

?

8)?小結:指針自增與自減

ü?p++(p+=1): 使p指向下一個元素

ü?*p++: ?++* 具有相同優先級且結合方向自右向左, 等價于*(p++), 先取*p的值,然后p再自加,指向下一個元素。

ü?*(p++) *(++p) 作用不同。 前者是先取*p的值,再使p自加。后者先使p自加,再取自加后指向的內容。

ü?++(*p): 表示將p指向的元素的值加1.

?

二、指針與數組

指針與一維數組

數組的指針是指數組在內存中的起始地址,即第一個數組元素的地址.

一維數組的數組名代表一維數組的指針(起始地址)

[ ] 又叫做變址運算符

a[i] <=> *(a+i) 在計算機內部實現的時候,數組下標都會轉化為地址。

?

若地址變量px的地址值等于數組指針x(指針變量px指向數組的首地址),則:

x[i]*(px+i)*(x+i) px[i]具有相同功能的功能:訪問數組第i+1個數組元素。

?

數組元素訪問過程中,數組地址與指針變量具有相同的訪問效果

不同:?地址變量是變量。

數組地址(數組名)是常量,不能自加或自減

地址變量與數組的賦值

? 1. ?int ?*p = &a[0];

2.??int *p;

p = &a[0];

?? 3. ?int *p = a;

小結:

1. p+ia + i就是a[i]的地址, 指向a數組的第i個元素。

2. *(p+i) *(a+i) 是取a[i]元素的值。

3. 指向數組的地址變量也可以帶下標 p[i]*(p+i)*(a+i) 等效。

?

9)?指針與數組常見操作

數組

指針表示

含義

array

&array[0]

?數組名是第一個元素的地址

*array

array[0]

?數組的第一個元素

array + i

&array[i]

?數組第i個元素的地址

*(array + i )

*(&array[i]) == array[i]

?數組第i個元素

*array + m

array[0] + m

?數組第一個元素加m

*array++

error

error

?

經典例子:

一維字符 指針數組ps[5] 里面存放著字符串首地址

char ?*ps[5] = {“beijing city”, ?“New York”, “London”, “Paris city”, “Moscow city”};

???????定義一個指針變量,并指向數組首地址;

???????char **pps = ps; 那么ps指向 指針數組的首地址

?

5.指針與二維數組

定義一個二維數組a,有34

int a[3][4] = { {1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23} };

a 是數組名, a數組包含3行,即3個元素,分別是a[0]a[1]a[2]。每個元素同樣是一個一維數組,包含4個元素,a[0][0], a[0][1], a[0][2], a[0][3].

a[0] 是一維數組名,代表的是第一行的第一個元素的首地址,a[0] = &a[0][0].

a[1] 是一維數組名, 代表的是第二行的第一個元素的首地址, a[1] = &a[1][0].

a[0][0] 是一個元素

&a[0][0] ==> a[0] 取一維數組的首地址,即一維數組名a[0](a[0] 為第一行首地址)

&a[0] ==> a a[0], a[1], a[2[ 三個元素中的首地址,即數組名a.

&a == &a 取數組a的地址,即取數組的位置。

?

a 指向? (指向第0行首地址) *(a+0) == a[0];

a+1 指向? (指向第一行的首地址) *(a+1) == a[1];

*(a+0) + 1 a[0][1]的地址, *(*(a+0) +) == ?a[0][1]

*(a+1) + 1 a[1][1]的地址, *(*(a+1) + 1) == a[1][1] == *(a[1] + 1)

PS

??對數組名取值就得到數組元素;

??對數組元素取址就得到當前數組地址;

??a[0][0] =(&a[0][0]) => a[0], 對第0行首元素取地址得到地址;

??a[0] ?=(&a[0]) => a, 3個元素的第0個元素取地址得到數組名。

??a ?=(&a) => ?&a, 對數組名取地址,得到數組地址。

思考:

??&a +1 指向? ?(指向下一個數組,增加一整個數組);

??a+1 ?指向? ??(指向下一行首地址, *(a+1) == a[1] );

??*(a+1) + 1 指向? (指向a[1][1]*(*(a+1) + 1) == a[1][1] );

注意點:

a + 1 表示的是第一行首地址, ?a表示是行數組的地址變化。

a[1] ?表示的是第一行0列的地址 &a[1][0]a[1] = * (a + 1); a表示的是當前行的首地址變化

?

二維數組的行地址、列地址

行地址:二維數組名是個特殊的地址,參與運算時以行為單位移動,因此被稱為是行地址。如int a[2][3], ?a代表的是第一行的首地址,a + 1代表第二行的首地址。

列數組:int *p = a

printf(“%d”, *(p+i) )p+i 相當于移動了i列, 因此指針p為列指針。

綜上:

???a+1a[0] + 1表示的地址值是相同的, 但含義是不同的, a+1 是序號為第一行的首地址, a[1] *(a+1)*a[1] + 1指向10列元素。

???二維數組名是指向行的,在行指針前面加上*, 就可以轉換為指向列的指針。

eg

aa+1是指向行的地址;

*a*(a+1)是指向列的指針。

反之,在列指針前面加上&,就可以轉換為行指針。

eg

a[0] 指向00列的列元素指針, &a[0] *(a + 0)

int ?main()

{ ??

???int ??a []={5,8,7,6,2,7,3};

???int y,*p=&a[1];

???y=(*--p)++;

???printf(%d ?,y); ?// 5

???printf(%d,a[0]); ?//6

?}

?

10)?指向元素的指針變量和指向數組的指針變量(數組指針)比較

ü?指向數組元素的指針變量定義和普通指針變量相同

?

?

ü?指向由m個元素組成的一維數組的指針變量:

???

對數組指針賦值:a為二維數組名:

p = a; p = &a[0];

int (*p)[4]4表示一維數組長度,且*p兩端的括號不可省略, 方括號的優先級高, int *p [4]p會先和[ ] 組成數組 p[4], 然后再和*組成 指針數組(地址數組)

p指向的是行的起始地址, *p 相當于p[0]

6.字符串與字符指針

C中沒有字符串數據類型。通常借助字符數組來存儲字符串。

字符指針可以存儲字符串的起始地址,即指針會指向字符串第一個字符。

字符串指針初始化,可直接把內存中字符串的首地址賦予指針變量。

eg

char *s = “Welcom!”; //相當于const char *s = “welcome!”。字符串常量是存放在常量區的,不可修改。

7.指針數組

指針數組即這個數組元素里存放的是地址(相同存儲類型和數據類型的地址集合)

說明形式:

<存儲類型> ?<數據類型> ?*<指針變量數組名> [<長度>]

int *p[2];

char ?*c[9];

11)?指針數組名含義:

表示這個數組的存儲首地址,即指針數組名為數組的地址。(和常規的數組相同,不同的是這個數組存儲地址)

指針數組中的元素就是地址,要取得元素對應的值,直接對數組元素取值即可,或對數組名**(p+i)取值。

?

指針數組元素就是地址,數組名代表數組的起始地址, 數組名是地址的地址,即二級指針。

指針數組與數組指針的比較:

數組指針:

???int (*p)[n] p是一個指針,指向整個一維數組,這個一維數組長度為np+1時,p增加整個數據的長度。

數組指針也稱為指向一維數組的指針, 或叫行指針。

指針數組:

???int *p[n], ?p是一個數組,這個數組元素是地址,p+1,指向下一個數組元素。

p = a屬于賦值錯誤,因為p是常量。只能對元素賦值a[0] = a, *p = a

?

?

三、函數

函數定義、聲明和調用

定義:

形式:

<數據類型> ?<函數名稱> (<形式參數說明>)

{

語句集;

return (<表達式>)

}

無參函數。 有參函數,空函數

參數類型:變量,指針,數組名,數組指針,函數指針。。。。

聲明:函數在聲明中可以省略形參,但這樣編譯器就不能檢查實參和形參是否匹配, 所以不建議省略。

?

?

?

?

8.函數傳參與返回值

??函數未調用時,形參沒有分配空間。調用時,系統為形參分配空間。調用結束后,所占內存單元被釋放。

??實參可以是常量、變量或表達式。max(a, a+b);

??函數定義時要指定數據類型。

??實參與形參的類型相同或兼容。

??C語言中,實參向形參傳遞參數是單向的,只能由實參傳遞給形參,反之不可以,在內存中,實參和形參占用的是不同的內存單元。

值傳遞與址傳遞

值傳遞

?

(分析值傳遞過程,值傳遞過程相當于隱含動作int a = x, int ?b = y)

?

址傳遞

?

典型strcpy實現

char * strcpy(char *dest, const char *source)

{

asssert(dest != NULL && source != NULL);

char * r = dest;

while ((*dest++ = *source++) != \0)

;

return dest;

}

?

12)?返回值

ü?函數的返回值由return語句返回,如:return ?zreturn (z)return (表達式)三種形式都可以,括號可以省略,保持簡潔。

ü?函數值在類型不指定時,系統按整型處理。

ü?函數定義類型和返回類型保持一致。

ü?void 定義的函數表示空類型;

9.函數調用

調用形式

??函數語句:printf(“”);

??函數表達式: a = read(buff, ?fd, n);

??函數參數: m = max(a, max(a, b));

??函數調用函數的幾點說明:

被調用函數必須是存在的庫函數或自定義函數;如果使用庫函數,要在文件開頭進行#include <> 進行頭文件包含,對函數進行聲明。

調用自定義函數時,被調用函數應該在調用函數前面,在主函數中進行被調用函數的聲明。

聲明可以函數聲明可以在主函數內部或在主函數前面,也可以在主函數前面進行函數定義。函數類型省略的情況下,系統默認是int.(思考:兩個函數相互調用怎么解決先后問題?)

?

總結

以上是生活随笔為你收集整理的指针、数组、函数阶段小结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。