C03指針


一 、 指針是什麼?

1.指針是C語言中非常重要的數據類型,如果你說C語言中除了指針,其他你都學得很好,那你乾脆說沒學過C語言。
2.指針和內存聯繫很緊密。
2.1.一個bit就是一個二進制位。一個字節=8bit
3.關於內存相關(baidu)
3.1.編譯時分配內存 : 編譯時是不分配內存的。
此時只是根據聲明時的類型進行佔位,到以後程序執行時分配內存纔會正確。
所以聲明是給編譯器看的,聰明的編譯器能根據聲明幫你識別錯誤。
3.2.運行時分配內存 :這是對的,運行時程序是必須調到“內存”的。
因爲CPU(其中有多個寄存器)只與內存打交道的。
程序在進入實際內存之前要首先分配物理內存。
3.3.編譯過程: 只能簡單說一下,因爲如果要詳細的話,就是一本書了《編譯原理》。
編譯器能夠識別語法,數據類型等等。
然後逐行逐句檢查編譯成二進制數據的obj文件,然後再由鏈接程序將其鏈接成一個EXE文件。
此時的程序是以EXE文件的形式存放在磁盤上。
3.4.運行過程: 當執行這個EXE文件以後,此程序就被加載到內存中,成爲進程。
此時一開始程序會初始化一些全局對象,然後找到入口函數(main()或者WinMain()),就開始按程序的執行語句開始執行。
此時需要的內存只能在程序的堆上進行動態增加/釋放了。
4.通常的機器都有一系列連續編號或編制的存儲單元,通過這些存儲單元可以單個進行操縱,可以以連續成組的方式操縱。

不同類型所佔用的存儲空間如下圖
這裏寫圖片描述


二 、 指針有什麼用?

指針是一種保存地址的變量,在C語言中,指針常常是表達某個計算的唯一途徑,另外指針通常可以生成更高效、更緊湊的代碼。

三 、 指針怎麼用?

  1. 定義的格式
    • 類名標識符 *指針變量名;
    • int *p;//聲明
  2. 先定義後賦值
    • 簡單取值
      int a = 10;
      int *p;
      p = &a;
      printf(“%d”, *p);
    • 簡單改值
      *p = 9;
  3. 定義的同時賦值
    int a = 10;
    int *p = &a;
  4. 清空指針
    • p = 0;
    • p = NULL;

四 、 使用指針要注意什麼?

1.指針只能指向某種特定類型的數據,也就是說,每個指針都必須指向某種特定的數據類型 
2.地址運算符&只能應用於內存中的對象,即變量與數組元素,它不能作用於表達式、常量或register類的變量
3.一元運算符*是間接尋址或間接引用運算符。當它作用於指針時,將訪問指針所指向的對象那

五 、 指針應用代碼舉例

  • 例1 指針聲明與引用
    int x=1,y=2,z[10];
    int *ip;//ip是一個指向整型int的指針
    ip=&x;//ip指向x
    y=*ip;//y現在的值是1
    *ip=0;//x現在的值是0
    ip=&z[0];//ip現在指向z[0]

  • 例2 指針與函數參數:交換兩個次序顛倒的主元素

*由於C語言是以傳值的方式將參數值傳遞給被調用函數,因此,別調用函數不能直接修改主調函數中變最的值。
如:

    void swap(int x,int y)
    {
        int temp;
        tmep = x;
        x = y;
        y = temp;
    }

則下列語句無法達到目的。

     swap(a,b);

*這時,可以使主調程序將指向所要交換的變量的指針傳遞給被調用函數 即

     swap(&a,&b);

函數定義如下

void swap(int *px,int *py)
    {
        int temp;
        tmep = *px;
        *px = *py;
        *py = temp;
    }//可以達到目標

  • 例3 指針與數組
// 初始化數組
int numbers[5] = {1,2,3,4,5};

// 標準數組表示法
int *ptr1 = numbers;
int val1 = numbers[0];

// 數組表示法取地址
int *ptr2 = &numbers[0];
int val2 = *(&numbers[0]);

// 指針加偏移表示法
int *ptr3 = numbers + 0;
int val3 = *(numbers + 0);

// 輸出指針中的地址
printf("*ptr1 = %p\n", (void *)ptr1); //結果:0x7fff6be1de60
printf("*ptr2 = %p\n", (void *)ptr2); //結果:0x7fff6be1de60
printf("*ptr3 = %p\n", (void *)ptr3); //結果:0x7fff6be1de60

// 輸出地址指向的int值
printf("val1 = %d\n", val1); //結果:1
printf("val2 = %d\n", val1); //結果:1
printf("val3 = %d\n", val1);//結果:1
//所有值都是相同的

  • 例4 地址算術運算
// 初始化數組
intnumbers[5] = {1,2,3,4,5};
inti = 0;

// 用數組表示法輸出元素
for(i = 0; i < 5; i++ ) {
  intvalue = numbers[i];
  printf("numbers[%d] = %d\n", i, value);
}

// 用指針加偏移輸出元素
for(i = 0; i < 5; i++ ) {
  intvalue = *(numbers + i);
  printf("*(numbers + %d) = %d\n", i, value);
}

// 僅用一個指針輸出元素
int*ptr = numbers;
for(i = 0; i < 5; i++ ) {
  intvalue = *ptr++;
  printf("%d, *ptr++ = %d\n", i, value);
}
/*結果:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
*(numbers + 0) = 1
*(numbers + 1) = 2
*(numbers + 2) = 3
*(numbers + 3) = 4
*(numbers + 4) = 5
0, *ptr++ = 1
1, *ptr++ = 2
2, *ptr++ = 3
3, *ptr++ = 4
4, *ptr++ = 5
//所有過程得到了相同的結果*/

  • 例5 字符指針與函數:複製字符串
//用數組實現
void strcpy(char *s, char *t)
{
    int i;
    i = 0;
    while ((s[i] = t[i]) != '\0')
    i++;
}
//用指針實現
void strcpy(char *s, char *t)
{
    int i;
    i = 0;
    while ((*s = *t) != '\0') {
    s++;
    t++;
    }
}

  • 例6 指針數組以及指向指針的指針
int main()
{
    int a[5]={1,3,5,7};
    int *n[4]={&a[0],&a[1],&a[2],&a[3]};//指針數組
    int **p,i;//**p爲指向指針的指針
    p=n;
    for(i=0;i<4;i++)
      { 
        printf("%d\t",**p);p++; 
      }
    return 0;
}

結果:1 3 5 7


  • 例7 指向函數的指針:比較大小
#include <stdio.h>
#include <stdlib.h>

 int main()
{
    int max(int,int);
    int (*p)(int,int);//定義函數指針
    int a,b,c;
    p = max;//指向函數
    scanf("%d,%d",&a,&b);
    c = (*p)(a,b);//用指針調用函數
    printf("a=%d,b=%d,max=%d\n",a,b,c);
    return0;
}

int max(int x,int y)
{
    int z;
    if(x>y) 
        z = x;
    else 
        z = y;
    return(z);
}

六 、指針總結

- **主題 1:指針** 

1.將地址形象化地稱爲“指針”。意思是通過它能找到以它爲地址的內存單元。
2.而地址指向內存單元
3.在程序中一般通過變量名來引用變量的值,因爲通過變量名能找到相應存儲單元的地址。
4.所有含有變量的語句,都是通過變量先找到其值,再去操作的。這種直接按變量名進行的訪問,叫直接訪問。
5.間接訪問:將變量i的地址存放在另一個變量中,然後通過該變量來找到變量i的地址,從而訪問i變量。
6.指向就是通過地址來體現的。
7.一個變量的地址就是叫做該變量的“指針”。
8.一個專門用來存放另一個變量的地址(即指針)則稱它爲指針變量。於是指針變量的值是地址。地址對應一個數,變量對應一個名。
9.指針變量,用來指向另一個對象(如變量,數組,函數等)。

- **主題 2:定義指針** 

1.定義指針變量:int * p;基類型 指針運算符 變量名
2.關於基類型
2.1.不同類型的數據在內存中所佔的字節數和存放方式是不同的。就是說類型控制了數據在內存佔的字節數
2.2.當取數據時,知道地址,然後還知道數據所佔的字節數,才能準確把要的數據去出來。不然後有可能取多或取少。
2.3.類型和地址共同決定了數據位置信息。
2.4.於是指針移動一個位置,就是移動了其對應類型佔用字節數,整型就是跨4個字節,字符就是跨1個字節,跳到了第二個變量的地址。
2.5.整型:4個字節 字符型:1個字節
2.6.一個變量的指針有兩個方面:表示地址;指向類型 比如 int * p; p是一個指向整型數據的指針變量。

- **主題 3:引用指針**

1.引用指針變量
1.1.給指針賦值 p=&a;
1.2.引用地址
2.指針變量作爲函數參數
2.1.作用是將一個變量的地址傳送到另一個函數中
3.通過指針引用數組
4.數組的指針和數組元素的指針不同的
4.1.指針變量指向一個數組元素:int *p=&a[0];
5.現在引用數組元素:1)下標法2)指針法
6.使用指針法能使目標程序質量高(佔內存少,運行速度快)。
7.在C語言,數組名代表數組中首元素的地址,所以數組名可以直接賦給指針變量。
8.在引用數組元素時指針的運算。
9.在引用數組元素時指針的運算。
9.1在指針指向數組元素時,可以對指針進行以下運算:1)加減一個整數2)自加自減3)同數組指針相減
10.通過指針引用數組元素
1)下標法2)指針法 *(a+i)
10.1)a[i]
10.2)通過數組名和元素序號計算數組元素地址,找出元素的值。 *(a+i)
10.3)用指針變量指向數組元素
for(p=a;p<(a+10);p++)
  printf("%d",*p);

11.注意
111.在使用指針變量指向數組元素時,應切實保證指向數組中有效的元素
11.2.指向數組的指針變量也可以帶下標,但是必須弄清楚該指針變量的當前值是什麼?
11.3.*p++:++和*同優先級 結合方向是自右向左。將先引用p的值,實現*p的運算,然後再使p自增1.
12.用數組名作函數參數
12.1.C語言調用函數時虛實結合的方法都是採用“值傳遞”方式,當用變量名作爲函數參數時傳遞的是變量的值,
當用數組名作爲函數參數時,由於數組名代表的是數組首元素地址,因此傳遞的值是地址,所以要求形參爲指針變量。
12.2.在C語言中用下標法和指針法都可以訪問一個數組,用下標法表示比較直觀,便於理解。因此許多人願意用數組名
作形參。
13.形參數組名實際上是一個指針變量,並不是真正地開闢一個數組空間。
14.如果有一個實參數組,想要在函數中改變此數組的元素的值,實參與形參的對應關係如下:實質是地址傳遞
14.1.形參和實參都用數組名
14.2.實參用數組名,形參用指針變量
14.3實參形參都用指針變量
14.4.實參是指針變量,形參是數組名

15.通過指針引用多維數組
15.1多維數組元素的地址
16.關於a[i]性質說明
16.1.從形式上看是a數組中序號爲i的元素。
16.2.當a是一維數組名,則代表a數組序號爲i的元素的存儲單元,這時它是有物理地址的,是佔存儲單元的
16.3.當a是二維數組,則它是一維數組名,只是一個地址,並不代表某一元素的值(如同一維數組名只是一個指針常量一樣)。

-**主題4:指向函數的 指針**

1.返回指針的函數
指針也是C語言中的一種數據類型,因此一個函數的返回值肯定可以是指針類型的
返回指針的函數的一般形式爲:類型名 * 函數名(參數列表) 
2.指向函數的指針:  爲什麼指針可以指向一個函數?
2.1.函數作爲一段程序,在內存中也要佔據部分存儲空間,它也有一個起始地址,即函數的入口地址。
函數有自己的地址,那就好辦了,我們的指針變量就是用來存儲地址的。因此,可以利用一個指針指向一個函數。
其中,函數名就代表着函數的地址。
2.2.指向函數的指針的定義:定義的一般形式:函數的返回值類型 (*指針變量名)(形參1, 形參2, ...);
3. 使用注意
3.1由於這類指針變量存儲的是一個函數的入口地址,所以對它們作加減運算(比如p++)是無意義的
3.2指向函數的指針變量主要有兩個用途:1)調用函數2)將函數作爲參數在函數間傳遞 
發佈了36 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章