C語言指針初步認識
==============
指針初步
==============
指針初步
1.數據的存儲
1》數據在內存中是如何存儲的
2》數據存儲的地址和大小
3.指針的定義和使用
1》如何定義指針
2》如何使用指針
4.指針指向數組,p++的含義
1》指針指向數組的含義
2》理解p++
5.泛指針、空指針、野指針
6.const關鍵字
一、認識指針
地址:內存每個字節都有一個數字的編號,稱為地址。
指針:指針是一個變量,用來裝地址。
//指針是地址變量。地址是指針的常量。
int * p;
//創建了一個指針的變量
//指針是p,不是*p. 類型 int *
int a;
//一個變量是內存中的空間,a占4個字節,a的地址是a第一個字節的地址。
p=&a;
//&a表達式的值,是a的地址,即a第一個字節的地址
printf(“%ld %ld %ld\n”,sizeof(p),sizeof(int *),sizeof(*p));
printf(“%p\n”,p);
printf(“%lx\n”,p);
//當一個指針p,裝了變量a的地址,稱為p指向a。
int a;
int *p = &a;
char b;
char * q=&b;
問:int *指針多少字節,char * 指針又是多少字節?
32位系統地址都是4字節,64位系統地址是8字節。指針無論指向什么類型的變量,大小和地址相同。
二、認識*p
int a=5;
int * p=&a;
*p=6;
//對p取*,意思是,找到地址為p的值的字節,取4字節,得到一個空間,就是a。
*&a=8;
printf(“%d\n”,a);
p:找到(尋址)地址為p的值的字節,取p個字節,得到一個內存空間,其實就是p指向的變量空間。
*&a<——->a
練習:
1》聲明整型變量a,存儲數字5,用相應指針指向a,通過指針將a修改成6.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
int a = 5;
int b=5;
//在內存中開辟了一個4字節空間,這個空間的名稱是a,存儲了一個5的常量
int * p = &a;
//指針p中存放了a的地址,我們稱為p指向了a p——》a
p = &b;
* p = 6;
//*p,找到p指向的變量的第一個字節的地址,并取指向變量類型的字節數,形成一塊空間,這個空間就是變量 b
//*p *p == *&a p== &a *p==a
printf("%d\n",b);
//
//p是指針,它存放了a的地址,a有4個字節,即有4個地址,尋到指針p只存放a的第一個字節的地址。
printf("%lu,%lu\n",sizeof(p),sizeof(int *));
}
return 0;
}
三、為什么使用指針?
int a =5;
int b=6;
swap(a,b);
swap2(&a,&b);
printf(“a5:%d b6:%d\n”,a,b);
void swap(int a,int b)
{
int t=a;
a=b;
b=t;
}
void swap2(int *p,int *q)
{
int t =* p;
*p =*q;
*q =t;
}
指針就是為了跨棧訪問,訪問不再當前棧里的數據。
C/C++
一個由C/C++編譯的程序占用的內存分為以下幾個部分
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數名,局部變量的名等。其操作方式類似于數據結構中的棧。
2、堆區(heap)— 由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似于鏈表。
3、靜態區(static)—全局變量和局部靜態變量的存儲是放在一塊的。程序結束后由系統釋放。
4、文字常量區—常量字符串就是放在這里的,程序結束后由系統釋放 。
如果想,封裝一個函數,修改變量的值,形參必須是指向這個變量的指針,實參是這個變量的地址。
練習:
1》編寫函數,交換兩個變量。
2》編寫函數,求三個變量的最大值,求完之后,將三個變量清0.
3》編寫函數,修改一個變量,將變量的值,改為現有值的三次方。
四、指針和數組
1.指針加1
指針加1,加一個*p的字節數,加一個p指向變量的字節數。
int a;
int * p= &a;
printf(“%p\n”,p);
printf(“%p\n”,p+1);
int a[5]={1,2,3,4,5};
//用一個指向int的指針,指向這個數組的第一個元素。
int * p=&a[0];
*(p+1)=8;
printf(“%d\n”,a[1]);
2.數組名是數組的首元素地址
計算機并不知道數組有多長,只知道數組的首元素地址。
3.數組的傳參
//數組傳參后會蛻化成指針。
int a[5]={1,2,3,4,5};
//數組傳參,傳入數組的名字,也就是a[0]的地址。
//數組傳參,用指向第一個元素的指針來接收。
printArray(a,5);
void printfArray(int *p,int n)
{ //只要傳參正確,在main函數中怎樣使用數組,在本函數中怎樣使用數組。
for(int i=0;i<n;i++){
printf(“%d “,p[i]);
}
[注]數組傳參,傳入數組首元素地址(如同傳入數組每個元素的地址),用指向數組元素的指針來接收。
使用指向數組首元素的指針,和使用數組本身是一樣的。
數組傳參,都是傳入元素的地址,所以能夠在函數中修改數組的元素。
數組名是首元素地址常量
指針是變量,可以裝首元素的地址。
練習:
1》編寫函數,將任意長整型數組,逆序。
五、泛型指針和空指針
泛型指針:void * p;可以存儲任何變量的地址,沒有類型的限制,也可以和任何指針進行彼此賦值。
如:int *p;
void *q=p;
p=q;
//泛型指針不能進行加減,不能取*。無法取*q的字節數。
空指針:如果一個指針不初始化,只能認為指針指向不能預測的地方,稱為野指針。如果使用了野指針,會產生不能預知的錯誤。因此,應將不能及時初始化的指針暫時賦成NULL,當明確了指向對象時,再去指向那個對象。如果發生在指向對象前就訪問了,地崩潰。
int *p;
*p=5;
int *p=NULL;
//為了防止野指針錯誤不明顯,如果一個指針創建時,沒有現成的變量來初始化。將p初始化為NULL(空指針),NULL代表0x00。計算機不會分配0x00這個地址給任何字節。百分百崩潰。
六、const關鍵字
const int a=5;
//const修飾變量a,使a不能被修改
int b,c;
const int * p=&b; //int const *p=&b;
//const 修飾指針
//const在*前,稱為*前const,所以修飾的是*p而不是p。
//*p不能改,p可以改。
p=&c;
//p指向誰,不能通過p修改誰。
c=5;
//可以改c,只是不能通過*p來修改c
int * const q=&b;
//*后const,修飾q,q不能改,*q可以改。
int a[5]={1,2,3,4,5};
printArray(a,5);
//可以遍歷打印數組,但不能改數組元素的值
void printArray(const int * p,int n)
{
*p=6; //不能改
}
//*后const幾乎沒有應用,只是C面試很容易考。
練習:
1》編寫函數,求任意長整型數組的平均數,返回。
2》編寫函數,求任意長整型數組中第二大的數。
指針案列代碼
指針
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
int a = 5;
int b=5;
//在內存中開辟了一個4字節空間,這個空間的名稱是a,存儲了一個5的常量
int * p = &a;
//指針p中存放了a的地址,我們稱為p指向了a p——》a
p = &b;
* p = 6;
//*p,找到p指向的變量的第一個字節的地址,并取指向變量類型的字節數,形成一塊空間,這個空間就是變量 b
//*p *p == *&a p== &a *p==a
printf("%d\n",b);
//
//p是指針,它存放了a的地址,a有4個字節,即有4個地址,尋到指針p只存放a的第一個字節的地址。
printf("%lu,%lu\n",sizeof(p),sizeof(int *));
}
return 0;
}
指針的作用
#import <Foundation/Foundation.h>
void swap(int a,int b);
void mySwap(int * p,int * q);
//1》編寫函數,交換兩個變量。
//2》編寫函數,求三個變量的最大值,求完之后,將三個變量清0.
void myMax(int * p,int * q,int * k);
//3》編寫函數,修改一個變量,將變量的值,改為現有值的三次方。
void myPow(int *p);
int main(int argc, const char * argv[])
{
@autoreleasepool {
// int a=5,b=6;
// printf("a=%d\tb=%d\n",a,b);
// swap(a, b);
// printf("a=%d\tb=%d\n",a,b);
// mySwap(&a, &b);
// printf("a=%d\tb=%d\n",a,b);
// int a,b,c;
// printf("請輸入三個整數:");
// scanf("%d%d%d",&a,&b,&c);
// myMax(&a, &b, &c);
// printf("a=%d b=%d c=%d\n",a,b,c);
int a;
printf("請輸入一個整數:");
scanf("%d",&a);
myPow(&a);
printf("%d\n",a);
}
return 0;
}
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
void mySwap(int * p,int * q){
int t = *p;
*p=*q;
*q=t;
}
void myMax(int * p,int * q,int * k){
int max;
if (*p>*q) {
max=*p;
}else{
max= *q;
}
if (max<*k) {
max=*k;
}
printf("最大值是:%d\n",max);
*p=*q=*k=0;
}
void myPow(int *p){
*p*=*p**p;
}