课程主题字串.docx
- 文档编号:10573570
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:27
- 大小:65.40KB
课程主题字串.docx
《课程主题字串.docx》由会员分享,可在线阅读,更多相关《课程主题字串.docx(27页珍藏版)》请在冰点文库上搜索。
课程主题字串
C/C++基礎
課程主題:
字串、字串函數
字串(string)即是由字元(character)所組成的一段文字,在C語言裡,沒有專屬字串的資料型態,因此我們是用字元陣列來模擬字串的。
字串的基本概念
字串是由字元所組成的一維陣列,為了要知道字串結束的位置,字串的末端必須要加上一個'\0'字元,稱之為空字元(NULLcharacter),ASCII碼值為0。
表示一個字元要在字元前後加上單引號('),同樣的表示一個字串則要在前後加上雙引號("),例如:
"IloveInfor!
"。
字串的宣告
宣告字串有兩種方式,一種是以陣列方式,另外一種是用指標的形式,例如:
charS1[10]="Hello";//陣列式的宣告,剩餘的空間補'\0'
charS2[]="Hello";//自動設定字元陣列的長度為6
charS3[]={'H','e','l','l','o','\0'};//標準陣列初始化寫法(不可省略'\0')
char*pS=S3;//指標式的宣告
記憶體中的配置如下所示:
※計算長度時要注意:
英文字母等等半形碼佔1byte,而中文字等等全形碼佔2bytes。
【範例】
#include
#defineSIZE6
intmain()
{
inti;
charS1[SIZE]="INFOR";
for(i=0;i printf("S1[%d]=%c\n",i,S1[i]); printf("S1=%s\n",S1);//%s是使用於字串的轉換規格符號 system("pause"); return0; } 字串的輸出輸入 輸出指令 printf() 【語法】 printf("%s",字串名稱); 【說明】 %s是使用於字串的轉換規格符號。 相較於puts(),printf()不會自動加上換行字元('\n'),需要自行加入。 puts() 【語法】 puts(字串名稱); 【說明】 puts的使用方式很簡單,只要傳入一個字串當引數就可以了。 puts()會在印完每段字串後自動加上換行字元('\n')。 輸入指令 scanf() 【語法】 scanf("%s",字串名稱);//不用加& 【說明】 scanf()會從一個非空白字元(如果開頭是空白字元會被略過)一直讀取到空白字元(Space、Tab、Enter)之前。 換行字元不會被去掉。 gets() 【語法】 gets(字串名稱); 【說明】 gets()函數會讀取換行字元('\n')前的所有字元,並且加上空字元('\0'),然後再將讀取的字串傳給呼叫它的程式。 換行字元讀取時會被去掉。 【討論】 使用gets()和scanf()函數有一個很大的缺點,就是不能限制輸入資料的大小,若有多餘的字元會溢出至鄰近的記憶體。 這個問題可以使用fgets()函數來解決(往後課程會介紹)。 【範例】 #include #include intmain() { chartmp[100]; //測試printf(),scanf() printf("使用scanf()輸入: "); scanf("%s",tmp); printf("輸出結果: %s\n",tmp); while(getchar()! ='\n')continue;//清空緩衝區 //測試puts(),gets() puts("使用gets()輸入: "); gets(tmp); printf("輸出結果: %s\n",tmp); system("pause"); return0; } 字串函數 如果我們要作字串的比對、字串的串接、計算字串長度等功能,C語言有提供許多這類處理字串的函數,ANSIC使用了string.h的標頭檔來提供這些函數的原型。 以下列出一些常用的函數: 函數用法 用途(以下函數都要引入string.h才能使用) strlen(string) 計算string的長度(不含'\0')。 strcat(string1,string2) 將string2的內容接到string1的後面。 strcmp(string1,string2) 將string1和string2作比較,相等傳回0。 strcpy(string1,string2) 將string2的內容複製到string1內。 strstr(string1,string2) 傳回string2在string1中第一次出現的位置(以char*型態)。 strrev(string) 將string字串倒置。 strtok(string1,string2) 將string2的每個字元當作分隔符號,把string1做切割。 遇到結尾會傳回NULL。 ※在使用strcat()或strcpy()這些函數時,要特別注意目的字串是否有足夠的空間。 【範例】 #include #include #include intmain() { chartmp[100],*token,*sep=",.";//分隔字元 puts("輸入欲切割的字串: "); gets(tmp); puts("結果: "); for(token=strtok(tmp,sep);token! =NULL;token=strtok(NULL,sep)) puts(token); puts("切開後的原字串"); puts(tmp); system("pause"); return0; } C/C++基礎 課程主題: 指標的基本概念、函數的傳址呼叫 指標的基本概念 當我們宣告一個變數時,其實是向系統申請一個記憶體空間來儲存資料,系統會分配一個位址來存放這個變數,因此宣告的程序結束後,每個變數都擁有自己的位址。 指標(pointer)也是一個變數,就像int變數能儲存整數一樣,指標變數能儲存記憶體內的位址。 指標的宣告 指標的宣告是在資料型態後面加上星號(*),如下所示: int*ptr;//宣告ptr為一個指向int的指標 float*ptr2;//宣告ptr2為一個指向float的指標 char*pS,*pS2;//宣告pS,pS2分別為指向char的指標 取值運算子(*)、取址運算子(&) 運算子 功能 * 傳回運算元所指向位址的資料 & 傳回運算元的起始位址 【範例】 #include #include intmain() { intval=10; int*ptr=&val; printf("val的值=%d\n",val); printf("val的位址=%p\n",&val); printf("ptr的值=%p\n",ptr); printf("ptr的位址=%p\n",&ptr); printf("ptr指向的值=%d\n",*ptr); //system("pause"); return0; } 【範例】 #include #include intmain() { inta=10; int*b=&a; printf("a=%d*b=%d\n",a,*b); *b=20; printf("a=%d*b=%d\n",a,*b); system("pause"); return0; } 函數的傳址呼叫 在C語言裡,函數呼叫的方式可以分為「傳值呼叫(callbyvalue)」和「傳址呼叫(callbyaddress)」兩種。 函數在傳遞引數的時候,會先將引數複製一份然後再進行運算,因此如果以傳值呼叫的方式,即傳遞的引數為一般變數,原先變數的值是不會改變的(只會改變複製變數的值,不會影響到原來變數);但如果傳遞的是變數的位址,我們可以透過取值運算子(*)直接取到該位址的變數,因此可以改變該變數的值,這就是所謂的傳址呼叫。 【範例】 #include #include voidswap(int,int);//傳值呼叫 voidswap2(int*,int*);//傳址呼叫 intmain() { inta,b; printf("輸入a,b兩整數..."); scanf("%d%d",&a,&b); printf("a=%db=%d\n",a,b); swap(a,b); printf("執行swap(a,b)後\n"); printf("a=%db=%d\n",a,b); swap2(&a,&b); printf("執行swap2(&a,&b)後\n"); printf("a=%db=%d\n",a,b); system("pause"); return0; } voidswap(inta,intb) { inttmp=b; b=a; a=tmp; } voidswap2(int*a,int*b) { inttmp=*b; *b=*a; *a=tmp; } C/C++基礎 課程主題: 指標的運算、指標與陣列、動態配置記憶體 指標的運算 指標的運算除了取值、取址或者設定之外,還有加減法和差值這兩種運算。 【範例】 #include #include intmain() { inta[10],*ptr=&a[1],*ptr2=&a[4]; printf("ptr=%p\n",ptr); printf("ptr+1=%p\n",ptr+1);//加法 printf("(char*)ptr+1=%p\n",(char*)ptr+1);//加法 printf("ptr-1=%p\n",ptr-1);//減法 printf("ptr2-ptr=%d\n",ptr2-ptr)//差值; printf("ptr-ptr2=%d\n",ptr-ptr2);//差值 system("pause"); return0; } 【討論】 由上面的範例我們可以知道,指標的加減法實際上就是做位址的移動,因此指標是什麼資料型態就顯得格外重要,因為它代表著每單位位移的大小。 例如,int是4bytes,每移動1單位相當於移動4bytes,而char是1byte,移動1單位即移動1byte。 所以,不同型態的指標之間,除非經過強制轉換,否則是不能做運算的。 另外C語言有提供一種void*型態的指標,它純粹只用來記錄位址,因此不能做加減運算,它的功能在於能與任意型態的指標相容。 【範例】 #include #include #defineSIZE5 voidcopy(void*,void*,int); intmain() { inti; inta[SIZE]={1,2,3,4,5},b[SIZE]={0,0,0,0,0}; printf("原始陣列: "); for(i=0;i printf("\n"); copy(a,b,sizeof(int)*SIZE); printf("後來陣列: "); for(i=0;i printf("\n"); system("pause"); return0; } voidcopy(void*src,void*des,intlen) { inti; char*src_tmp=(char*)src,des_tmp=(char*)des; for(i=0;i des_tmp[i]=src_tmp[i]; } 指標與陣列 陣列是記憶體中一塊連續的空間,陣列的名稱記錄了整塊空間開頭的位址,所以我們可以透過索引值(偏移量)來存取到我們需要的位置;換句話說,陣列名稱算是一種不能改變位址的常數指標,和指標之間的關係相當密切。 指標與一維陣列 如果宣告: inta[5]={1,2,3,4,5}; 陣列標記 指標標記 內容 陣列標記 指標標記 內容(假設) a[0] *(a+0) 1 &a[0] a 0x0012FEC4 a[1] *(a+1) 2 &a[1] a+1 0x0012FEC8 a[2] *(a+2) 3 &a[2] a+2 0x0012FECC a[3] *(a+3) 4 &a[3] a+3 0x0012FED0 a[4] *(a+4) 5 &a[4] a+4 0x0012FED4 指標與多維陣列 如果宣告: inta[2][3]={{1,2,3},{4,5,6}}; 陣列標記 指標標記 內容 陣列標記 指標標記 內容(假設) a[0][0] *(*(a+0)+0) 1 &a[0][0]或a[0]+0 *(a+0)+0 0x0012FEC0 a[0][1] *(*(a+0)+1) 2 &a[0][1]或a[0]+1 *(a+0)+1 0x0012FEC4 a[0][2] *(*(a+0)+2) 3 &a[0][2]或a[0]+2 *(a+0)+2 0x0012FEC8 a[1][0] *(*(a+1)+0) 4 &a[1][0]或a[1]+0 *(a+1)+0 0x0012FECC a[1][1] *(*(a+1)+1) 5 &a[1][1]或a[1]+1 *(a+1)+1 0x0012FED0 a[1][2] *(*(a+1)+2) 6 &a[1][2]或a[1]+2 *(a+1)+2 0x0012FED4 示意圖如下: 【說明】 上述a是一個二維陣列,所以a的每個元素其實是一個大小為3的int陣列,因此a+1會移動3個int的大小即12bytes。 相對的a[0]所指向的物件是一個整數,所以a[0]+1只會移動一個int大小。 #include #include intmain() { inta[2][3]={1,2,3,4,5,6}; printf("a=%p\ta+1=%p\n",a,a+1); printf("a[0]=%p\ta[0]+1=%p\n",a[0],a[0]+1); printf("*a=%p\t*a+1=%p\n",*a,*a+1); printf("a[0][0]=%d\n",a[0][0]); printf("*a[0]=%d\n",*a[0]); printf("**a[0]=%d\n",**a); printf("a[1][2]=%d\n",a[1][2]); printf("*(*(a+1)+2)=%d\n",*(*(a+1)+2)); //補充說明 printf("(*a)[1]=%d\n",(*a)[1]); printf("*a[1]=%d\n",*a[1]); system("pause"); return0; } 動態配置記憶體 之前變數的宣告,都是使用「靜態宣告」的方式,也就是在編譯階段即完成宣告;現在我們要介紹的是「動態宣告」,能夠在程式執行中才配置記憶體空間,使記憶體的使用更加具有彈性。 以下是兩種配置方式的比較: 動態配置 靜態配置 記憶體配置 執行階段 編譯階段 記憶體釋放 程式結束釋放,否則造成記憶缺口 程式結束自動歸還系統 效能 較慢 較快 指標遺失位址 記憶缺口 無此問題 配置動態空間所使用的函數常用的是malloc()和free(),前者是配置所需的空間,後者是釋放配置的空間。 兩個函數都宣告在stdlib.h裡,需要引入才可使用。 【語法】 資料型態*指標名稱=(資料型態*)malloc(sizeof(資料型態)*資料長度); free(指標名稱); 【範例】 #include #include intmain() { inti,n,*num,sum=0; printf("輸入多少數字: "); scanf("%d",&n); num=(int*)malloc(sizeof(int)*n); for(i=0;i printf("輸入第%d個數字: ",i+1); scanf("%d",&num[i]); sum+=num[i]; } printf("總和為: %d\n",sum); system("pause"); return0; } C/C++基礎 課程主題: 檔案輸出輸入 對於檔案的處理,C提供了強大的功能,可以讓我們在程式中開啟檔案,利用特殊的I/O函數執行讀入或寫入的動作。 ※stdio.h全名為StandardInput/OutputHeader,內容就是有關I/O的函數、常數、結構等等的宣告。 以下所介紹的都宣告在stdio.h的檔案裡,所以不再特別註明。 開檔 使用任何檔案之前都要經過開檔的動作,我們使用fopen()函數來執行這項動作。 【語法】 FILE*指標名稱=fopen(檔案路徑或名稱,檔案開啟模式); 【說明】 fopen()執行成功後會傳回一個FILE型態的指標(失敗回傳NULL),因此我們要宣告一個FILE*變數來接收其值。 FILE是一個包含檔案相關資訊的資料結構(struct),以提供I/O函數對某個檔案做處理。 此外,在stdio.h裡宣告了三種FILE*供我們使用,如下表: 標準檔案 檔案指標 慣例 標準輸入 stdin 鍵盤 標準輸出 stdout 螢幕 標準錯誤 stderr 螢幕 關於檔案開啟的模式整理至下表: 模式 意義 "r" 開啟用來讀取的檔案,檔案不存在則傳回NULL "w" 開啟用來寫入的檔案,自行建立新檔,若檔案存在舊檔會被刪除。 "a" 開啟用來寫入的檔案,寫入的資料加在檔尾,檔案不存在則建立新檔 "r+" 開啟用來更新(也就是可寫也可讀)的檔案,檔案不存在則傳回NULL "w+" 開啟用來更新的檔案,若檔案存在舊檔會被刪除,檔案不存在則建立新檔 "a+" 開啟用來更新的檔案,寫入的資料加在檔尾,檔案不存在則建立新檔 上述的模式是以文字(text)的方式作存取,如果要以二元(binary)方式存取的話只要在原本模式後加上"b"就行了。 例如: "rb"、"r+b"、"rb+"……等等。 【範例】 #include #include intmain() { FILE*fp; charch; if((fp=fopen("tmp.txt","r"))==NULL){//如果開啟檔案失敗就結束程式 printf("Can'tfindthefile.\n"); system("pause"); exit (1); } while((ch=getc(fp))! =EOF)//從檔案裡讀取一個字元 putchar(ch);//印至螢幕上 system("pause"); return0; } 檔案處理函數 輸出指令 fprintf() 【語法】 fprintf(FILE*,"輸出內容",變數名稱); 【說明】 與printf()的使用方法相近,只是額外多第一個參數,以識別要輸出至什麼檔案。 fputs() 【語法】 fputs(字串名稱,FILE*); 【說明】 將第一個參數的字串輸出至FILE*指向的檔案,與puts()不同的是,不會自動加上換行字元('\n')。 輸入指令 fscanf() 【語法】 fscanf(FILE*,"輸入內容",變數位址); 【說明】 同樣與scanf()使用方法相近,但多一個FILE*參數識別檔案。 讀到檔案結尾或讀取錯誤時,fscanf()會回傳EOF。 fgets() 【語法】 fgets(字串名稱,最大長度,FILE*); 【說明】 fgets()可以限制輸入資料的長度,因此使用上比gets()來的更加安全。 另外,fgets()會讀入換行字元,而讀到檔案結尾或錯誤時,會回傳NULL。 關檔 使用完檔案後要養成關檔的好習慣,因為每個系統能同時開啟的檔案有限,隨手關閉不再讀寫的檔案可以節省系統資源,所以我們使用fclose()來關閉檔案。 【語法】 fclose(FILE*); 【說明】 fclose()執行成功會傳回0,否則會傳回EOF。 【範例】 #include #include intmain() { FILE*in,*out; charbuf[100],name[20],name2[20]; fprintf(stdout,"請輸入要複製的檔案: "); fscanf(stdin,"%s",name); if((in=fopen(name,"r"))==NULL)exit (1);//無法開檔結束程式 fprintf(stdout,"複製檔的名稱: "); fscanf(stdin,"%s",name2); if((out=fopen(name2,"w"))==NULL)exit (1);//無法建檔結束程式 while(fgets(buf,100,in)! =NULL) fputs(buf,out); fclose(in); fclose(out); system("pause"); return0; } C/C++基礎 課程主題: 列舉(enum)、結構(struct) 列舉 列舉型態(enumeratedtype)常運用在具有相同類型特點的常數識別字,將它們集合在一起,給予一個可以辨識的名字,取代沒有意義的數值,既可以統一名稱管哩,也方便我們記憶,加強了程式的可讀性。 【語法】 enum列舉名稱{成員1,成員2,成員3,......}變數名稱; 【說明】 enum是一種衍生的資料型態,所以我們可以使用自訂的enum來宣告變數。 enum中成員的值可以自訂,如果沒有特別指定,則會自動往後遞增編號(完全沒給會從0開始編號)。 enum成員其實就是整數常數,所以可以把它用來當作switch敘述的標籤使用。 【範例】 #include
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 课程 主题 字串