c 程式設計 指標 - 國立中興大學hwtseng/visualcpp_slide/point.pdf · 課程大綱...

41
C 程式設計指標

Upload: others

Post on 30-Jan-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

  • C 程式設計—指標

  • 課程大綱

    C語言簡介基本資料型態, 變數, 基本輸入輸出控制敘述-選擇控制與重覆控制陣列

    函式

    指標

    字元與字串

    結構

    檔案處理

  • 本次上課大綱

    指標與記憶體位址

    指標運算

    函式的傳指標呼叫

    指標和陣列

    指標與函式

    多重指標

    main函式的引數串列與回傳值動態記憶體配置

  • 什麼是指標(pointer)

    指標一種變數

    儲存記憶體位置

    儲存在該記憶體中的可能是字元, 整數,指標本身變數的位置

    程式可以間接取得該指標所指位址的變數值

    指標節省記憶體空間

    減少不必要的搬動

    使用不當的話, 造成系統或程式嚴重的錯誤

  • 存取記憶體內容

  • 宣告指標變數 (1)

    指標的宣告方式與變數的宣告方式相同, 只不過指標在變數前面多加一個 *

    資料型態 *指標變數名稱int *int_ptr;char *ch_ptr;float *float_ptr;double *double_ptr;

  • 宣告指標變數 (2)

    int i=3;int *ptr;ptr=&i;

    1012

    3

    1000

    1004

    1008

    1012

    ptr是一個指向整數型態的指標, 內容為該整數的位址

    i是一個整數, 內容為3, 與*ptr的值一樣

    記憶體位址

  • 取址運算子與指標運算子(1)

    &是取址運算子用來取得該變數在記憶體的位址

    &變數名稱

    int i=3;int *ptr;ptr=&i;

    1012

    3

    1000

    1004

    1008

    1012

    記憶體位址 ptr是一個整數指標

    *ptr取得該指標的內容值

    &i取得該整數在記憶體中的位址

    i是一個整數

  • 取址運算子與指標運算子(2)

    *是指標運算子用來取得指標所指向位址的內容值

    *指標變數名稱

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

    *p=50

    記憶體位址 記憶體位址

    1012

    50

    1012

    ??

    10001000

    10041004

    10081008

    10121012

  • 練習時間

    每一種資料型態的指標變數在32位元的作業系統環境中都佔用4個bytes,因為指標變數存放的是記憶體位址

    比較輸出指標的位址與值.

  • 指標運算 (1)

    指定運算錯誤:int *p=10; 正確:

    int x=10;int *p=&x;Int *p = (int *)10;

    加減運算

    比較運算

    差值運算

    變數

    int x = 10;

    指標變數

    int *x = (int *)10;

    x 10 *x10&x x

  • 指標運算 (2)

    加減運算

    只能加常數值

    將指標變數內容『加1』依據指標指向的資料型態所佔用的記憶體單位大小,來決定移動多少個位址(加1代表加1個單位),以便指向正確的下一筆同樣資料類型的資料。

    例子

    int *p,*q;

    p=p+q; /* 不合法 */

  • 指標運算 (3)

    比較運算

    相同型態的指標變數可以做比較運算,藉由比較運算,我們可以得知記憶體位址的先後關係

    較早配置記憶體的變數位於較高的記憶體位址

    例子

  • 指標運算 (4)

    差值運算

    兩個相同資料型態的指標變數可以做減法運算

    代表兩個記憶體位址之間的可存放多少個該資料型態的資料

    例子

  • 傳址呼叫 (1)

    傳值呼叫

    call by value

    傳址呼叫

    call by address

  • 1 /* Fig. 7.6: fig07_06.c 2 Cube a variable using call-by-value */ 3 #include 4

    5 int cubeByValue( int n ); /* prototype */ 6

    7 int main() 8 { 9 int number = 5; /* initialize number */ 10

    11 printf( "The original value of number is %d", number ); 12 13 /* pass number by value to cubeByValue */ 14 number = cubeByValue( number ); 15

    16 printf( "\nThe new value of number is %d\n", number ); 17

    18 return 0; /* indicates successful termination */ 19

    20 } /* end main */ 21

    22 /* calculate and return cube of integer argument */ 23 int cubeByValue( int n ) 24 { 25 return n * n * n; /* cube local variable n and return result */ 26 27 } /* end function cubeByValue */

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • The original value of number is 5The new value of number is 125

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • int main()

    {

    int number = 5;

    number=cubeByValue(number);

    }

    int cubeByValue( int n )

    {

    return n * n * n;

    }

    number

    5

    n

    Before main calls cubeByValue :

    undefined

    After cubeByValue receives the call:

    int main()

    {

    int number = 5;

    number = cubeByValue( number );

    }

    int cubeByValue( int n )

    {

    return n * n * n;

    }

    number

    5

    n

    5

    After cubeByValue cubes parameter n and before

    125

    int cubeByValue( int n )

    {

    return n * n * n;

    }

    int main()

    {

    int number = 5;

    number = cubeByValue( number );

    }

    n

    cubeByValue returns to main :

    5

    number

    5

    Analysis of a typical call-by-value. (Part 1 of 2.)

  • 125

    int main()

    {

    int number = 5;

    number = cubeByValue( number );

    }

    int cubeByValue( int n ){

    return n * n * n;

    }

    number

    5

    n

    After cubeByValue returns to main and before assigning the result to number :

    undefined

    125125

    int main()

    {

    int number = 5;

    number = cubeByValue( number );

    }

    int cubeByValue( int n )

    {

    return n * n * n;

    }

    number

    125

    n

    After main completes the assignment to number :

    undefined

    Analysis of a typical call-by-value. (Part 2 of 2.)

  • 1 /* Fig. 7.7: fig07_07.c 2 Cube a variable using call-by-reference with a pointer argument */ 3

    4 #include 5

    6 void cubeByReference( int *nPtr ); /* prototype */ 7

    8 int main() 9 { 10 int number = 5; /* initialize number */ 11

    12 printf( "The original value of number is %d", number ); 13 14 /* pass address of number to cubeByReference */ 15 cubeByReference( &number ); 16

    17 printf( "\nThe new value of number is %d\n", number ); 18

    19 return 0; /* indicates successful termination */ 20

    21 } /* end main */ 22

    23 /* calculate cube of *nPtr; modifies variable number in main */ 24 void cubeByReference( int *nPtr ) 25 { 26 *nPtr = *nPtr * *nPtr * *nPtr; /* cube *nPtr */ 27 } /* end function cubeByReference */

    傳入變數位址

    將變數改為指標型態

    傳入型態為指標

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • The original value of number is 5The new value of number is 125

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • void cubeByReference( int *nPtr ){

    *nPtr = *nPtr * *nPtr * *nPtr;

    }

    int main()

    {

    int number = 5;

    cubeByReference( &number );

    }

    void cubeByReference( int *nPtr ){

    *nPtr = *nPtr * *nPtr * *nPtr;

    }

    int main()

    {

    int number = 5;

    cubeByReference( &number );

    }

    number

    5

    nPtr

    number

    5

    nPtr

    Before main calls cubeByReference :

    After cubeByReference receives the call and before *nPtr is cubed:

    undefined

    call establishes this pointer

    125

    void cubeByReference( int *nPtr ){

    *nPtr = *nPtr * *nPtr * *nPtr;

    }

    int main()

    {

    int number = 5;

    cubeByReference( &number );

    }

    number

    125

    nPtr

    After *nPtr is cubed and before program control returns to main :

    called function modifies caller’s variable

    Analysis of a typical call-by-reference with a pointer argument.

  • 練習時間#include

    void swap(int *,int *);

    int main(){

    int i,j;

    i=1,j=2;swap(&i,&j);printf("%d %d",i,j);

    }

    void swap(int *p,int *q){

    int temp;

    temp=*p,*p=*q;*q=temp;}

    SWAP

  • 傳址呼叫 (2)

    傳值呼叫 傳址呼叫

  • 指標與陣列

    int array[10]; 我們以陣列名為array代表陣列的起始位址, 以array+1表示下一個位址.

    當宣告指標時, int *ptr; 則以ptr代表其位址, 以ptr+1代表下一個位址.

    陣列其實也是指標的一種應用.

  • 1 /* Fig. 7.20: fig07_20.cpp 2 Using subscripting and pointer notations with arrays */ 3

    4 #include 5

    6 int main() 7 { 8 int b[] = { 10, 20, 30, 40 }; /* initialize array b */ 9 int *bPtr = b; /* set bPtr to point to array b */ 10 int i; /* counter */ 11 int offset; /* counter */ 12

    13 /* output array b using array subscript notation */ 14 printf( "Array b printed with:\nArray subscript notation\n" ); 15

    16 /* loop through array b */ 17 for ( i = 0; i < 4; i++ ) { 18 printf( "b[ %d ] = %d\n", i, b[ i ] ); 19 } /* end for */ 20

    21 /* output array b using array name and pointer/offset notation */ 22 printf( "\nPointer/offset notation where\n" 23 "the pointer is the array name\n" ); 24

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • 25 /* loop through array b */ 26 for ( offset = 0; offset < 4; offset++ ) { 27 printf( "*( b + %d ) = %d\n", offset, *( b + offset ) ); 28 } /* end for */ 29

    30 /* output array b using bPtr and array subscript notation */ 31 printf( "\nPointer subscript notation\n" ); 32

    33 /* loop through array b */ 34 for ( i = 0; i < 4; i++ ) { 35 printf( "bPtr[ %d ] = %d\n", i, bPtr[ i ] ); 36 } /* end for */ 37

    38 /* output array b using bPtr and pointer/offset notation */ 39 printf( "\nPointer/offset notation\n" ); 40

    41 /* loop through array b */ 42 for ( offset = 0; offset < 4; offset++ ) { 43 printf( "*( bPtr + %d ) = %d\n", offset, *( bPtr + offset ) ); 44 } /* end for */ 45

    46 return 0; /* indicates successful termination */ 47

    48 } /* end main */

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • Program Output

    Array b printed with:Array subscript notationb[ 0 ] = 10b[ 1 ] = 20b[ 2 ] = 30b[ 3 ] = 40

    Pointer/offset notation wherethe pointer is the array name*( b + 0 ) = 10*( b + 1 ) = 20*( b + 2 ) = 30*( b + 3 ) = 40

    Pointer subscript notationbPtr[ 0 ] = 10bPtr[ 1 ] = 20bPtr[ 2 ] = 30bPtr[ 3 ] = 40

    Pointer/offset notation*( bPtr + 0 ) = 10*( bPtr + 1 ) = 20*( bPtr + 2 ) = 30*( bPtr + 3 ) = 40

    Copyright 1992-2004 by Deitel & Associates, Inc. and Pearson Edition Inc. All right Reserved.

  • 練習時間

    陣列其實也是指標的一種應用.如果用array++會怎樣?

    使用指標控制陣列.如果用ptr++會怎樣?

  • 指標與二維陣列

    例子

    int array[3][4], *ptr;ptr=(int *)array;array[1][2] 跟 ptr[3*1+2]的比較

    (*(array+1))[1]跟*((array+1)[1])的比較

    多重指標與二維陣列

    例子

  • 指標陣列

    陣列裡面所包含的元素都是指標.指標陣列型態

    int *int_ptr[10]; // 整數指標陣列float *float_ptr[10];double *double_ptr[10];char *str[10];

    例子:

  • 指標與函數

    函數的名稱與陣列的名稱一樣, 都代表著起始位址, 同時也是一個指標的常數, 因此函數指標可做如下的宣告:

    void (*func)(void);

    例子:傳回整數的指標函數:如果把程式中第9行的 *func(i) 變成 func(i)的話, 會怎樣?

  • 指標的指標 (1)

    int * ptr; /* 指標 */int ** ptr; /* 指向指標的指標 */int *** ptr; /* 三層指標變數 */

    ptr *ptr **ptr位址 位址 整數值

    雙重指標

  • 指標的指標 (2)

  • 指標的指標 (3)

    使用多重指標(指標的指標)將九九乘法表的乘法結果儲存在9*9的二維整數陣列,並將陣列的資料列印出來

    陣列表示法 指標表示法

    array[i][j] *(*(array+i)+j)

  • 問題:

    請問下列程式的執行結果

    #include #include int main(){

    int x[5]={2,4,6,8,10},*p,**pp;p=x;pp=&p;printf("%d\n",*(p));p++;printf("%d\n",**pp);system("pause");return 0;

    }

  • main()的argc與argv

    定義方式一

    int main(int argc,char *argv[])定義方式二:

    int main(int argc,char argv[][]) /* 使用二維字元陣列(字串陣列) */定義方式三:

    int main(int argc,char **argv) /* 使用指標的指標 */

    argc表示命令列中參數字串的個數.

    argv表示指向命令列中所有參數字串的指標.

    例子

  • 動態記憶體配置

    使用在某些陣列大小無法於事先決定的情況

    C語言不能宣告一個陣列大小為變數的陣列需要用多少記憶體空間,就向系統要多少記憶體空間

    於執行過程中配置一個適當大小的記憶體空間給指標,接著藉由這個指標來存取分配到的記憶體空間內的資料

  • 配置記憶體函式-malloc( )

    標頭檔:

    #include #include 語法:void *malloc(size_t size);功能:動態配置記憶體

    範例char *ptr;

    ptr = (char *)malloc(sizeof(char)*9);

  • 釋放記憶體函式-free( )

    標頭檔:

    #include #include 語法:void free(void *ptr);功能:釋放記憶體

    範例:

    Free(ptr);

    我們透過malloc函式取得的記憶體,可以於不需再使用的狀況下,透過free函式將之歸還給系統

  • 今天學到了什麼

    什麼是指標

    如何使用指標運算

    如何使用函式的傳指標呼叫

    如何使用指標和陣列

    如何使用指標與函式

    如何使用多重指標

    如何使用main函式的引數串列與回傳值如何使用動態記憶體配置