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;iprintf("\n");
copy(a,b,sizeof(int)*SIZE);
printf("後來陣列:
");
for(i=0;iprintf("\n");
system("pause");
return0;
}
voidcopy(void*src,void*des,intlen)
{
inti;
char*src_tmp=(char*)src,des_tmp=(char*)des;
for(i=0;ides_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;iprintf("輸入第%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