Introduction to the C Programming Language

Slides:



Advertisements
Similar presentations
While 迴圈 - 不知重複執行次數
Advertisements

电子成绩单项目实现.
“八皇后”问题 崔萌萌 吕金华.
第8章 指针 ● 8.1 指针简介 ● 8.2 指针变量的操作 ● 8.3 数组与指针 ● 8.4 二维数组与指针 ●本章小结 ●本章练习.
数据结构与算法 数据结构与算法实验
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
Linked List Operations
Introduction to the C Programming Language
高级语言程序设计 主讲人:陈玉华.
第一章 C语言概述.
選擇排序法 通訊一甲 B 楊穎穆.
資料大樓 --談指標與陣列 綠園.
C的發展史 C程式初體驗 C程式設計基本注意事項 上機實習課程
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
Introduction to the C Programming Language
C 程式設計— 指標.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
C 程式設計— 指標 台大資訊工程學系 資訊系統訓練班.
Introduction to the C Programming Language
Introduction to the C Programming Language
STRUCTURE 授課:ANT 日期:2010/5/12.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
Introduction to the C Programming Language
Object-Oriented Programming in C++ 第一章 C++的初步知识
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
程式設計 博碩文化出版發行.
第7章 编译预处理 本章要求: 本章重点: 本章难点: 掌握用#define定义无参数宏和带有参数宏定义和调用方法;
Introduction to the C Programming Language
高级语言程序设计 张长海 软件自动化研究室 Tel:
第八章 使用指针.
計數式重複敘述 for 迴圈 P
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
Introduction to the C Programming Language
第十章 指针.
第7章 陣列與指標 7-1 陣列的基礎 7-2 一維陣列的處理 7-3 二維與多維陣列的處理 7-4 陣列的函數參數
Struct結構 迴圈
自我參考結構 (self-reference – 1)
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
C语言概述 第一章.
C++语言程序设计 第六章 数组 指针与字符串.
C语言复习3----指针.
第八章 指標 (Pointer).
指標
輸出與輸入(I/O).
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
C语言程序设计 李祥 QQ:
第九章 指针.
第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性.
第二章 类型、对象、运算符和表达式.
Introduction to the C Programming Language
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
本节内容 函数嵌套调用的内存布局 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
Introduction to the C Programming Language
第七章  数 组.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
第三章 高级函数特性.
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
Introduction to the C Programming Language
Introduction to the C Programming Language
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第一次上機考參考答案 僅供參考,同學可自行再想更好的方法..
變數與資料型態  綠園.
資料!你家住哪裏? --談指標 綠園.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
Introduction to the C Programming Language
函式庫補充資料 1.
隨機函數.
Presentation transcript:

Introduction to the C Programming Language 指標 (Pointer)

指 標 (Pointer) 指標概述 指標的宣告與定義 指標與函數 指標與陣列 指向指標的指標—雙重指標

為什麼要用指標? 可使函數在傳遞陣列或字串時更有效率。 較複雜的資料結構須要指標才能將資料串在一起。 Ex. Linked list, binary tree. 有些函數必須利用指標來傳達記憶體的訊息。 malloc( ):記憶體配置函數 fopen( ):檔案開啟函數

指標概述 C語言提供一種存取變數的特殊方式--指標(pointer),透過指標,可以不必用到變數的名稱,卻可以存取到變數的內容. 指標其實只是一種特殊的變數,用來存放變數在記憶體中的位址. 利用指標變數,可以把變數在記憶體內的位址存入指標中,可利用指標先找到該變數的位址,再由該位址取出位址內所儲存的變數值.這種依位址來取值的特殊方式,稱之為“間接定址取值法” 指標ptr存放了變數a的位址,也就是指標ptr指向變數a。 變數內容 5 FDD4 FDD2 FDD4 FDD6 FDD8 指標好比告訴你:某位同學的學號,由此學號就可以找到他/她的姓名。 一般變數 a 指標變數 ptr ( 圖一 : 指標與變數在記憶體中的情形 )

指標的宣告與定義 指標變數宣告格式 例一: int *ptr ; /* 宣告指向整數的指標變數ptr ,它所存放的 資料型態 *指標變數 ; (1) 在變數的前面加上指標符號「*」,即是將變數宣告 成指標變數。 (2) 指標變數之前的資料型態,則是代表指標所指向之變 數的型態。 例一: int *ptr ; /* 宣告指向整數的指標變數ptr ,它所存放的 位址必須是一個整數變數的位址。 */ 資料型態 *指標變數 ;

指標的宣告與定義 法1--- int *ptr ; /* 宣告指向整數的指標變數ptr */ int num=20 ; /*宣告整數變數num,並設值為20 */ ptr = &num ; /*把指標ptr設為變數num的位址, 把ptr指向num */ 法2--- int num=20; int *ptr = # ptr指向整數變數num 20 1408 1400 變數num 指標變數ptr 指標變數ptr的位址 變數num的位址

指標變數的使用 指標變數使用方式 位址運算子「 &」 : 用來取得變數的記憶體位址 位址取值運算子「 *」 : 用來取得指標所指向變數的內容 int num=20 ; 變數num 20 &num可取出變數num的位址,即 1400 1400 變數num的位址 int num=20; int *ptr=# 20 1408 1400 變數num 指標變數ptr 指標變數ptr的位址 變數num的位址 *ptr可取出ptr所指向之變數num的值(num的值為20)

指標變數的宣告 範例一:指標變數的宣告 Output: num=20,&num=ffd6 #include<stdio.h> #include<stdlib.h> int main(void) { int *ptr,num=20; /*宣告變數num與指標變數ptr */ ptr=&num; /*將num位址設給指標ptr存放 */ printf(“num=%d, &num=%x\n”,num,&num); printf(“*ptr=%d,ptr=%x,&ptr=%x\n”,*ptr,ptr,&ptr); system(“pause”); return 0; } Output: num=20,&num=ffd6 *ptr=20,ptr=ffd6,&ptr=ffd4

指標的宣告與定義 範例二: 比較輸出指標的位址與值  Output: a=20, *ptr=20, b=20 #include<stdio.h> void main() { int *ptr; int a,b; a=20; ptr=&a; /* 將 ptr 指向變數 a 的位址 */ b=*ptr; /* 將 b設定為 ptr 所指位址的內容值 */ printf(“a=%d,*ptr=%d , b=%d\n", a,*ptr , b ); printf(“ptr=%x , &a=%x\n", ptr , &a ); }  Output: a=20, *ptr=20, b=20 ptr=ffd6 ,&a=ffd6

指標所佔的空間大小 #include<stdio.h> #include<stdlib.h> int main(void) { int *ptri; /*宣告指向整數的變數ptri*/ char *ptrc; /*宣告指向字元的變數ptrc*/ printf("size of ptri = %d\n",sizeof(ptri)); printf("size of ptrc = %d\n",sizeof(ptrc)); printf("size of *ptri = %d\n",sizeof(*ptri)); printf("size of *ptrc = %d\n",sizeof(*ptrc)); system("pause"); return 0; }

指標所佔的空間大小(續) 在TC中,compile配置給指標變數的空間都是2bytes。 Output:

課堂練習 #include <stdio.h> #include <stdlib.h> int main(void) { int a=5,b=10; int *ptr1,*ptr2; ptr1=&a; /* 將ptr1設為a的位址 */ ptr2=&b; /* 將ptr2設為b的位址 */ *ptr1=7; /* 將ptr1指向的內容設為7 */ *ptr2=32; /* 將ptr2指向的內容設為32 */ a=17; /* 設定a為17 */ ptr1=ptr2; /* 設定ptr1=ptr2 */ *ptr1=9; /* 將ptr1指向的內容設為9 */ ptr1=&a; /* 將ptr1設為a的位址 */ a=64; /* 設定a為64 */ *ptr2=*ptr1+5; /* 將ptr2指向的內容設為*ptr1+5*/ ptr2=&a; /* 將ptr2設為a的位址 */ printf("a=%2d, b=%2d, *ptr1=%2d, *ptr2=%2d\n",a,b,*ptr1,*ptr2); printf("ptr1=%p, ptr2=%p\n",ptr1,ptr2); system("pause"); return 0; }

課堂練習 Output: 請試著寫出以下四個變數記憶體空間之值的變化: ptr1 ptr2 a b FADA FBDE FFDE FFDG 5 10 FFDG FFDE FFDE 7 17 64 32 9 69

指標與函數 在函數中,若是想傳回某個結果給原呼叫函數,可利用return敘述,但當程式需要傳遞兩個以上的值時,就無法利用return敘述,此時可利用“指標”解決函數間傳遞多個回傳值的問題. 宣告函數原型範例 : int func ( int * , char * ) ; /* 將指標當成參數,傳入函數 */ 函數定義中接收參數部分,假設接收的變數名稱為 ptr1及 ptr2,記得在變數名稱前要加指標符號 * int func ( int * ptr1 , char * ptr2 ) ;

傳入pointer值(變數位址即為pointer的值) 指標與函數之範例1 範例六:設計一個傳值函式noswap(),及一個傳址函式swap() #include<stdio.h> void noswap(int, int); void swap(int *, int *); main() { int x=2,y=3; printf("The original values are: x=%d , y=%d \n" , x , y ); noswap(x,y); printf(“(call by value: x=%d , y=%d \n", x , y ); swap(&x,&y); printf(“(call by address: x=%d , y=%d \n", x , y ); } 傳入pointer值(變數位址即為pointer的值)

指標與函數之範例1 接上頁(範例六) void noswap ( int a , int b ) /* call by value */ { int t; t=a; a=b; b=t; } void swap ( int *a , int *b) /* call by address* / t=*a; *a=*b; *b=t;

指標與函數之範例2 #include <stdio.h> #include <stdlib.h> void rect(int,int,int *,int *); /* 函數rect()的原型 */ int main(void) { int a=5,b=8; /*矩形的長與寬*/ int area=0,peri=0; /*矩形的面積與邊長*/ rect(a, b, &area, &peri); /* 呼叫rect(),計算面積及周長 */ printf("area=%d,total length=%d\n",area,peri); system("pause"); return 0; } void rect(int x, int y, int *p1, int *p2) *p1=x*y; *p2=2*(x+y);

範例2之說明 當函數rect(x, y, area, length) 執行完後,變數area可存放矩形面積,而變數peri可存放矩形的周長。 指標的好處之一在於它可以更改傳入的引數值,利用此特性,我們便可以設計出很實用的程式。

指標與陣列 陣列事實上也是指標的一種應用,不同的是,陣列是固定長度的記憶體區塊;而指標是一個變數,用來記錄所指變數的位址. 利用index即可取出陣列的元素值,除了用index外,也可另外利用指標取出陣列的元素值. char a[10]; /*宣告陣列*/ char *pa; /*宣告指標*/ pa=&a[0]; 或 pa=a; /*指標指向陣列的開頭(第0個元素)*/ 以此為基點用索引的方式來取得陣列的每個元素 *(pa) 取到的是陣列的第0個元素 a[0] *(pa+1) 取到的是陣列的第1個元素 a[1] /*pa+1是將位址值加2(int佔2個bytes)*/ *(pa+i) 取到的是陣列的第i個元素 a[i]

指 標-指標與一維陣列 指標與一維陣列 int *ptr; int a[5]={3,8,6,2,5}; 表示宣告ptr是一個指標變數,ptr本身存的是一個變數的位址。 ptr=a的效果就是將ptr指向a[0]的位址。 printf(“%d”,*ptr); for(i=1;i<5;i++) printf(“%d”,*ptr++); /* 不能寫成*a++ */ int *ptr; int a[5]={3,8,6,2,5}; ptr=a; /* 或 ptr=&a[0]; */ *ptr取出陣列裡的值 陣列名稱本身是一個存放位址的「指標常數」,指向陣列的位址。 因為陣列宣告後,陣列的記憶體位址配置已被固定,所以我們不能再去改變陣列名稱的指向! for(i=0;i<5;i++) printf(“%d”,a[i]);

3 8 ptr 6 2 5 int a[5]={3,8,6,2,5}; int *ptr; ptr=&a[0]; a a[0] &a[0] fdd2 &a[0] ptr+0 *(ptr+1) a[1] &a[1] fdd4 ptr+1 *(ptr+2) a[2] &a[2] ptr+2 fdd6 a[3] &a[3] ptr+3 *(ptr+3) fdd8 &a[4] ptr+4 a[4] *(ptr+4) fdd10

課堂練習 範例4-2: #include <stdio.h> #include <stdlib.h> int main(void) { int a[3]={5,1,9}; printf(“a[0]=%d, *(a+0)=%d\n”,a[0],*(a+0)); printf(“a[1]=%d, *(a+1)=%d\n”,a[1],*(a+1)); printf(“a[2]=%d, *(a+2)=%d\n”,a[2],*(a+2)); system(“pause”); return 0; }

範例4-2 請說明以下變數的內容 9 1 5 &a[2] &a[1] &a[0] *(a+2) a[2] *(a+1) a[1] 1408 1406 1404

指標與陣列 範例四: 用指標取出陣列元素的值與位址 #include<stdio.h> main() { int i; char *pa; char a[4]={'A','B','C','D'}; pa=a; for(i=0;i<4;i++) printf("a[%d] value:%c ; *(pa+%d) value:%c\n",i,a[i],i,*(pa+i)); printf("&a[%d] address:%x ; *(pa+%d) address:%x\n",i,&a[i],i,pa+i); } Pointer指向陣列的開頭

範例四的結果 指標的算術運算多半用在存取陣列元素的操作上。 因為compile會配置給陣列一塊連續的記憶體空間,所以陣列元素的位址之間有很高的關聯性。

指 標-指標與二維陣列 ptr 第i列,第j行 的表示方式*(ptr+3*i+j) 指標與二維陣列 二維陣列在人們眼中通常用於處理二維的行列表格,但電腦內部的記憶體,是以一維陣列的方式排列,所以雖然是二維的陣列,但在電腦的記憶體中已轉為一維的方式儲存。 以指標來處理二維陣列,第一步驟設定第一元素的位址給指標變數: int *ptr; int a[4][3]; ptr=&a[0][0]; 第二步驟以ptr來表示二維陣列的值,必須先將二維排列轉為一為陣列的直線排列: 第0行 第1行 第2行 ptr *(ptr+3*0+2)=5 表示將 a[0][2]的值設為5 a(0,0) a(0,1) 1 a(0,2) 2 a(1,0) 3 a(1,1) 4 a(1,2) 5 a(2,0) 6 a(2,1) 7 a(2,2) 8 a(3,0) 9 a(3,1) 10 a(3,2) 11 第0列 第1列 第i列,第j行 的表示方式*(ptr+3*i+j) 第2列 第3列 3為此陣列行的個數

若要存取第i列第j行的值: *(*(a+i)+j)=5; a[i][j]=5; *(ptr + 3 *i + j)=5; /*a[i][j]=5;*/ j a(0,0) a(0,1) 1 a(0,2) 2 a(1,0) 3 a(1,1) 4 a(1,2) 5 a(2,0) 6 a(2,1) 7 a(2,2) 8 a(3,0) 9 a(3,1) 10 a(3,2) 11 i

陣列名稱num是指標常數,是一個指向指標的指標 int num[3][4]; num num[0] 12 1000 23 1002 42 1004 18 1006 1000 1000 第 0列 1000 1000 num[1] 43 1008 22 1010 16 1012 14 1014 1008 第1列 1008 num[2] 31 1016 13 1018 19 1020 28 1022 1016 第2列 1016 num[0]~num[2]也是指標常數,分別儲存了每一個一維陣列裡,第一個元素的位址 3*4的二維陣列可以看成是由3個一維陣列所組成 在宣告num陣列時,編譯器會自動配置一個「指標常數」的陣列num[0]、num[1]、num[2]讓他們分別指向每一列的第一個元素。

續上頁 *(num+0)可取出此值 *(num+2)可取出此值 12 23 42 18 1000 num+0 43 22 16 14 1002 42 1004 18 1006 1000 num+0 1000 num[1] 43 1008 22 1010 16 1012 14 1014 1008 num+1 1008 num[2] 31 1016 13 1018 19 1020 28 1022 1016 num+2 *(num+2)可取出此值 1016

*(num+i)+j 代表了第i列,第j行的位址 續上頁 *(*(num+1)+2) *(*(num+1)+1) *(*(num+1)+3) *(*(num+1)+0) *(num+1)可取出此值 43 1008 22 1010 16 1012 14 1014 num[1] 1008 第1列 1008 num+1 *(num+1)+0 *(num+1)+2 *(num+1)+3 *(num+1)+1 這裡列跟行的算法是從第0列第0行起算 *(num+i)+j 代表了第i列,第j行的位址 *(*(num+i)+j) 代表了取出第i列,第j行的值

指標與陣列---指標陣列 指標也可以宣告成陣列:指標陣列。 宣告方式如下: 例如: int *ptr[3]; 資料型態 *陣列名稱[元素個數]; 例如: int *ptr[3]; /*表示宣告了一個可存放3個指向整數的指標,分別是ptr[0] 、ptr[1]、ptr[2]*/ 二維陣列: char str[3][10]={“Clare”, ”Jane Wang”, ”Tom Lee”}; 指標陣列: char *ptr[3]={“Clare”, ”Jane Wang”, ”Tom Lee”};

指標陣列 指標陣列 C l a r e \0 J a n e W g \0 T o m L e \0 如何建立一個儲存字串的陣列?除了用二維的字元陣列處理,另外可用“指標陣列”來解決,用指標陣列來處理,會較節省記憶體空間. char Name[3][10]={“Clare”,”Jane Wang”,”Tom Lee”}; Name[0] Name[1] Name[2] C l a r e \0 J n W g T o m L FDB2 FDB4 FBD6 ( 圖 三 : 儲存字串的二維字元陣列儲存方式 ) char *Name[3]={“Clare","Jane Wang","Tom Lee"}; C l a r e \0 Name[0] Name[1] Name[2] FDB2 FDB4 FBD6 J a n e W g \0 T o m L e \0 ( 圖 四 : 指標陣列儲存方式 )

指標陣列 範例五: 指標陣列 #include <stdio.h> int main(void) { int i; char *name[3]={"David","Jane Wang","Tom Lee"}; for(i=0;i<3;i++) /* 印出指標陣列的內容 */ printf("name[%d]=%s\n",i,name[i]); /*puts(name[i];)*/ return 0; }

指標陣列 範例五: 指標陣列另一種寫法 #include <stdio.h> int main(void) { int i; char *ptr[3]; ptr[0]="David"; /*設定ptr[0]指向字串”David” */ ptr[1]="Jane Wang"; /*設定ptr[1]指向字串”Jane Wang” */ ptr[2]="Tom Lee"; for(i=0;i<3;i++) /* 印出指標陣列的內容 */ /*printf("ptr[%d]=%s\n",i,ptr[i]);*/ puts(ptr[i]); return 0; }

指向指標的指標—雙重指標 雙重指標宣告方式 資料型態 **指標變數; 例 : int **ptri; /*宣告一個指向整數的雙重指標ptri */ 資料型態 **指標變數; 位址 整數值 指向整數的指標 變數 1200 1460 5 雙重指標 指標變數 一般變數 1000 雙重指標

指向指標的指標—雙重指標 範例三: 雙重指標 , 輸出其內容及位址 #include<stdio.h> void main() { int *ptr1,**ptr2; int a=10; ptr1=&a; /* 指標 ptr1指向 a 的位址 */ ptr2=&ptr1; /* 雙重指標 ptr2 指向 ptr1的位址 */ printf("a=%d , &a=%x\n", a , &a ); printf("*ptr1=%d , ptr1=%x\n", *ptr1 , ptr1 ); printf("**ptr2=%d , *ptr2=%x\n", **ptr2 , *ptr2); printf("ptr2=%x, &ptr1=%x\n", ptr2 , &ptr1); }  a ffd4 ffd6 10 ptr2 ptr1 ffd2 Output: a=10, &a=ffd6 *ptr1=10, ptr1=ffd6 **ptr2=10 ,*ptr2=ffd6 ptr2=ffd4 , &ptr1=ffd4