C語言指針
前導程序

1 #include<stdio.h>
2
3
4
5 void change(int *); 6
7 int main() 8
9 { 10
11 int a=90; 12
13 change(&a); 14
15 printf("a=%d\n",a); 16
17 return 0; 18
19 } 20
21
22
23 void change(int *n) 24
25 { 26
27 *n=10; 28
29 } 30
31
一、基本知識點
Int a=10;
Int *p;//定義一個int類型的指針
P=&a;//指針變量p指向了變量a
*p=20;//使用指針不通過變量直接修改變量a的值為20
*p表示訪問指針變量p指向的存儲空間
指針一個作用:能夠根據一個地址值,訪問(取值 | 賦值)對應的存儲空間
指針變量p前面的int,表示指針的類型
①. Int *p;
②. *p=10;
兩個*的區別:前一個起標識作用,表明定義的p是一個指針,后者的*表示通過訪問p指向的地址空間
二、指針使用注意
①. Int *p;
double d=10.0;
p=&d;//不建議此種做法
②. Int *p;
p=200;//指針變量只能存儲地址
③. Int *p;
printf(“%d\n”,*p);//指針變量未經初始化,不要拿來間接訪問其他的存儲空間
④. Int *p=&a;但是不能寫成 int *p;*p=&a;這種寫法沒有任何的意義,可以認為*是和類型符一起使用的。
⑤. *是指針運算符,訪問指針指向的空間
三、指向指針的指針
Int a=10;
Int *p=&a;//指向int型的指針
Int **p1=&p;//指向指針的指針
Int ***p2=&p1;//三級指針
*p2相當於訪問p1;
**p2相當於訪問p;
***p2相當於訪問a;
*p1相當於訪問p;
一顆星一條線。
四、指針練習
編寫一個函數,計算a和b的和與差(一個函數返回兩個值)
提示:指針的作用之一:實現讓函數擁有多個返回值

1 #include<stdio.h>
2
3
4
5 int SumAndMinus(int n1,int n2,int *n3) 6
7 { 8
9 *n3=n1-n2; 10
11 return n1+n2; 12
13 } 14
15
16
17 int main() 18
19 { 20
21 int a=10; 22
23 int b=11; 24
25 int sum; 26
27 int minus; 28
29 sum=SumAndMinus(a,b,&minus); 30
31 printf("和=%d,差=%d\n",sum,minus); 32
33 }
五、有關指針的疑問
注意:任何類型的指針都占據8個字節的存儲空間,那么為什么還要為指針加上類型呢?
對下面一段代碼進行內存分析,可以證明指針類型不正確帶來的嚴重后果。
Int i=2;
Char c=1;
Int *p=&c;//本應該是char類型的,寫成了int類型
Printf(“c的值是%d\n”,*p);//打印結果為513,而非1
Printf(“c的值是%d\n”,c);//值為1
下面是上述代碼的結果的內存分析:
指針p訪問的本應該是1個字節空間的數據,此時因為指針的類型是int型的,因此程序自然的從指向的地址0x0a開始讀取了4個字節的數據,訪問的數據從1變成了513。
提示:明確了指針的數據類型,指針才能夠正確的訪問應該訪問的空間數據。
六、指針和數組
Int ages[5]={10,9,8,7,6};
遍歷數組
For(int i=0;i<5;i++)
Printf(“%d\n”,ages[i]);
使用指針遍歷數組
Int *p;
P=ages;//也可以寫成p=&ages[0];,指針變量p指向了數組的首元素
元素的地址:
第一個元素的地址p &ages[0]
第二個元素的地址p+1 &ages[1]
第三個元素的地址p+2 &ages[2]
元素的值
*p ages[0]
*(p+1) ages[1]
*(p+2) ages[2]
把指針當做數組來用:
For(int i=0;i<5;i++)
Printf(“%d\n”,*(p+i));
(1)數組元素的三種訪問形式:
①. 數組名[下標]
②. 指針變量名[下標]
③. *(p+1)
(2)指針變量的+1究竟是加多少?這取決於指針的類型,如果是char類型則加1個字節,如果是int類型的,則加4個字節。
(3)利用指針來接收一個數組,指針變量指向了數組的首元素。
Void change(int array[])等價於void change(int *array)。
前者存儲的雖然是數組元素的首地址,但是在傳遞時就已經變成指針了。
示例:
Void change(int *array)
{
//Printf(“%d\n”,array[2]);
Printf(“%d\n”,*(array+2));
}
Int main()
{
Int ages[5]={1,2,3,4,5};
Change(ages);
}
調用的結果為:數組的第三個元素3
若改給change(&ages[2]);則調用的結果為5,因為此時array指向的是ages[2],把ages[2]當做了array的首元素
七、指針和字符串
(一)基礎知識
下面兩行代碼有着本質的區別:
①. Char name[]=“it”;
②. Char *name2=“it”;//指針變量name2指向了字符串的首字符i
Char name[0]=‘y’;//改變第一個元素的值
Printf(“%s\n”,name);//打印結果為yt
*name2=‘y’;
Printf(“%s\n”,name2);//此時程序崩潰
這是因為,兩者一個是字符串變量,一個是字符串常量。C語言的數組元素存放於棧,里面的元素可以隨便修改,稱為字符串變量。而字符串常量存放於常量區,會緩存起來是不可更改的。
Char *name1=“it”;
Char *name2=“it”;
Printf(“%p %p”,name1,name2);//地址是一樣的,說明name1和name2指向的是同一個字符串。
掌握字符串定義的兩種方式:
①. 利用數組
特點:字符串里邊的字符是可以修改的,適用於內容需要經常修改時。
②. 利用指針
特點:其實是一個常量字符串,里面的字符不能修改,適用於字符串的內容不需要修改,且這個字符串經常被使用時。
(二)指針數組
整型數組:這個數組中存放的都是整型數組
指針數組:這個數組中存放的都是指針
Int ages[5];
Char *name[5]={“jack”,“rose”,“yang”};//字符串數組的常見寫法
對應於:
Char name2[3][10]={“jack”,“rose”,“yang”};
保存字符串數組的兩種方式:
①. 指針數組(字符串數組)
②. 二維字符數組(字符串數組)
如何輸入字符串?(使用數組——因其可變)
Int main()
{
Char name[20];
Printf(“請輸入姓名:\n”);
Scanf(“%s”,name);
Printf(“%s”,name);
}
八、返回指針的函數
程序示例:
#include<stdio.h>
Char *test();
Int main()
{
Char *name=test();
Printf(“name=%s\n”,name);
Return 0;
}
Char *test() //返回指針的函數
{
Return “rose”;
}
九、指向函數的指針
數組名即數組的地址,函數名即函數的地址。
假設有函數:
Void Test ()
{
Printf(“調用了test函數\n”);
}
Void (*p)(); //void指針變量指向的函數沒有返回值,()表示p指向的函數沒有形參
P=test; //有指針p,把指針p指向函數
有三種方式可以操縱函數:
①. 直接調用test();
②. 利用指針變量簡介調用 (*p)();
③. 簡化使用p()
練習:
假設有函數聲明為 int sum(int a,int b)
則相對應的指向該函數的指針應該定義為:int (*p)(int ,int);
把指針變量p指向函數:p=sum;
調用該函數的三種方式:
(1)int c=p(10,12);
(2)Int c=sum(10,12);
(3)Int c=(*p)(10,12);
假設函數聲明為:double haha(double a,char *b,int c);
則定義一個指向haha函數的指針應該為:double (*p)(double,char *,int)=haha;