引言:C語言裏,指針就是它的靈魂,是它能如此高效的原因,同時也是C語言學習的難點;最近在B站看完翁愷老師關於指針和數組的視頻,我感覺醍醐灌頂,很多模糊難辨的細節問題有了自己的理解。這裏想寫下來作爲總結和記錄,水平有限,懇請指正。
- 一、基本概念總結
1、C指針(變量的房間號):是一個值爲內存地址的變量。
- 地址運算符:&,取地址運算
int a = 1;
ptr = &a; - 地址運算符:*,取值運算符
b = *ptr;
注:&和 *爲互逆運算符。
char stuName ,name;//定義字符型變量stuName,name
char *pStu ; //定義指向字符型變量的指針變量pStu
char *pNew;//定義指向字符型變量的指針變量pNew
pStu = &stuName;//取變量stuName地址賦值給指針變量pStu
pNew = pStu;//把指針變量pStu賦值該pNew
name = *pNew;//把pNew指向的內存單元的值賦給name
2、數組(存放數據的容器)
- 所有元素具有相同的數據類型;
- 一旦創建,不能改變大小;
- 數組中的元素在內存中是連續依次排列的。
數組元素本身不能被賦值(可以初始化)
如:int ar[] ={1,2,3,4,3,};//引用時下標從零開始,0–n-1;
也可以採用遍歷:
for (i=0; i<length; i++){
b[i] =a [i];
}
二維數組
int a[3][5]; //l理解爲一個三行五列的矩陣
初始化:
int a[3][5] = {
{0,1,2,3,4},
{2,3,4,5,6},
{4,5,6,7,8},
};
或者遍歷:
for(i=0; i<3;i++){
for(j=0;j<5;j++){
a[i][j] = i*j;
}
}
注:
- 列數必須給出,行數可由編譯器來數(a[][5]是合法的);
- 每一個{}由逗號分隔;
- 最後的逗號可以存在;
- 如果省略,表示補零;
二、深入理解指針和數組
1、指針與數組本質聯繫
數組中 &a = a = a[0]; 數組的存儲地址由第一個存儲單元a[0]的地址確定,這三個式子意思都一樣,表示a[0]的地址。
所以 :
a + 2 = = &a[2];
*(a+2) == &a[2];
函數參數表中的數組實際上就是指針;
sizeof(a)== sizeof(int*);
因此,以下四種函數原型是等價的:
int sum(int *ar, int n);
int sum(int *,int );
int sum(int ar[], int n);
int sum(int[],int );
所以:
int int a[10];
int *p = a; //無需&操作
- 但是數組的單元表達的是變量,需要用&取地址:
a == &a[0]; - []運算符可以對數組做,也可以對指針做:
p[0] 等價於a[0]; - *運算符可以對指針做,也可以對數組做:
*a = 25; - 數組變量是const的指針,所以不能被賦值:
int a[] 等價於 int *const a;
2、指針與const
(1)指針是const:表示一旦得到了某個變量的地址,不能再指向其他變量:
int *const q = &i;//q是const
*q = 26;//OK
q++;//ERROR
//可以這麼理解:指針本身是隻讀的const不能變,而它指向的變量可以變
(2)所指是const:表示不能通過這個指針去修改那個變量:
const int *p = &i;
*p = 26;//ERROR
i = 26;//OK
p = &j;//OK
//可以認爲*p是const,但指針本身可以變,變量i本身可以變
總結:判斷哪個被const了的標誌是const在*前還是後面
const * --所指的東西不能被修改
*const–指針不能被改變。
三、指針作爲函數參數的巧妙用途
作爲函數的參數:
void f(int *p);
在被調用時得到了某個變量的地址:
int i = 0;
f(&i);//該函數可以通過指針訪問
具體應用場景:
- 函數返回多個值,某些值只能通過指針返回;
- 傳入參數實際是需要保存帶回的結果的變量;
- 函數返回運算的狀態,結果通過指針返回;
- 常用套路是讓函數返回特殊的不屬於有效範圍內的值表示出錯:-1或0;
以下是實踐函數:
/* 指針練習1,指針概念的辨析 */
#include<stdio.h>
void f(int *p); //函數原型,void表示函數沒有返回值,如果是()內的void表示函數不帶參數
void g(int k); //用來對照指針變量的
int main(void){
int i = 6;
printf("&i = %p\n",&i); //%p是以十六位的指針地址形式輸出
f(&i); //由於函數參數爲指針變量,調用時&i爲取變量i的地址
g(i);
return 0;
}
void f(int *p){
printf("p = %p\n",p);
printf("*p = %d\n",*p); //*p爲取指針所指向地址的值,即取值
*p = 26 ; //改變*p的值,看i本身變不變==實際上i會變,因爲*p作爲一個整體代表了i,可以把它看成一個int變量
}
void g(int k){
printf("k = %d\n",k);
}
/* 指針練習2,指針一些具體的使用 */
#include<stdio.h>
void swap(int *pa,int *pb);
int main(void)
{
int a = 5;
int b = 6;
swap(&a,&b);
printf("a = %d,b = %d",a,b);
return 0;
}
void swap(int *pa,int *pb) //使用指針來操作交換函數swap()
{
int t = *pa;
*pa = *pb;
*pb = t;
}
/* 指針練習3 ,用一個函數找出數組中最大數和最小數 */
#include<stdio.h>
void minmax(int a[], int len, int *max, int *min );
int main(void)
{
int a[] = {1,2,9,10,45,70,1,76,87,8,};
int min, max;
minmax(a, sizeof(a)/sizeof(a[0]), &max, &min);
printf("min = %d,max = %d",min,max);
return 0;
}
/*函數返回多個值時,某些值只能通過指針返回(其實該函數並沒有返回值,
但是通過指針的特性,直接找到所要操作變量的地址,然後改變裏面的值,這裏可以類比爲返回值*/
//傳入的參數實際上是需要保存的帶結果的變量
void minmax( int a[], int len, int *max, int *min)
{
int i;
*max = *min = a[0];
for( i=0; i<len; i++ ){
if(a[i]<*min){
*min = a[i];
}
if(a[i]>*max){
*max = a[i];
}
}
}
到此結尾了,我這裏的多爲筆記總結,要深入理解還是要自己敲幾行試試。