本文章用於沒有太多C語言知識的讀者,想要讀懂開源的水力建模軟體EPANET時,會遇到如下的一些C標準函數,現介紹如下:
一、fgets函數
原型: char *fgets(char *s, int n, FILE *stream);
參數:
*s: 字元型指標,指向將儲存到的資料地址。
n: 整型資料,將從流中讀取 n - 1 個字元。
*stream: 指標資料,欲讀取的流。
功能:
從檔案指標stream中讀取n-1個字元,存到以s為起始地址的空間裡,直到讀完一行,如果成功則返回s的指標,否則返回NULL。
例:
如果一個檔案的當前位置的文本如下
Love ,I Have
但是,如果用
fgets(str1,4,file1);
則執行後str1="Lov",讀取了4-1=3個字元,
而如果用
fgets(str1,23,file1);
則執行str1="Love ,I Have",讀取了一行(包括行尾的'\n',並自動加上字串結束符'\0')。
二、strtok
表標頭檔:
#include<string.h>
原型:
char *strtok(char *s, const char *delim);
功能: 分解字串為一組字串。s為要分解的字串,delim為分隔字元字串。
參數s: 指向欲分割的字串;
參數delim:
則為分割字串。
傳回值: 從s開頭開始下一個分割後的字串指標,如果已無從分割則返回NULL。 strtok()用來將字串分割成一個個片段。當strtok()在參數s的字串中發現到參數delim的分割字元時則會將該字元改為\0 字元。在第一次調用時,strtok()必需給予參數s字串,往後的調用則將參數s設定成NULL。每次調用成功則返回下一個分割後的字串指標。
所有delim中包含的字元都會被濾掉,並將被濾掉的地方設為一處分割的節點。
例子:
#include <stdio.h>
#include <string.h>
int main()
{
char s[]="a b j w y;z";
char *delim=" \t\n\r";
char *p;
printf("%s\n",strtok(s,delim));
while((p=strtok(NULL,delim))) printf("%s\n",p);
return 0;
}
運行結果:
三、strncpy
標頭檔:#include "string.h"
原型:char * strncpy(char *dest, char *src, size_t n);
其中size_t是標準C庫中定義的,應為unsigned int,在64位系統中為 long unsigned int。
功能:將字串src中最多n個字元複製到字元數組dest中(它並不像strcpy一樣只有遇到NULL才停止複製,而是多了一個條件停止,就是說如果複製到第n個字元還未遇到NULL,也一樣停止),返回指向dest的指標。
說明:
如果n > dest串長度,dest棧空間溢出產生崩潰異常。
否則:
1)src串長度<=dest串長度,(這裡的串長度包含串尾NULL字元)
如果n∈(0, src串長度),src的前n個字元複製到dest中。但是由於沒有NULL字元,所以直接存取dest串會發生棧溢出的異常情況。
如果n = src串長度,與strcpy一致。
如果n = dest串長度,[0,src串長度]處存放於dest字串,(src串長度, dest串長度]處存放NULL。
2)src串長度>dest串長度
如果n =dest串長度,則dest串沒有NULL字元,會導致輸出會有亂碼。如果不考慮src串複製完整性,可以將dest最後一字元置為NULL。
綜上,一般情況下,使用strncpy時,建議將n置為dest串長度,複製完畢後,為保險起見,將dest串最後一字元置NULL,避免輸出會有亂碼的問題。當然嘍,無論是strcpy還是strncpy,保證src串長度<dest串長度才是最重要的。
四、strlen
strlen所作的僅僅是一個計數器的工作,它從記憶體的某個位置(可以是字串開頭,中間某個位置,甚至是某個不確定的記憶體地區)開始掃描,直到碰到第一個字串結束符'\0'為止,然後返回計數器值。
原型:extern unsigned int strlen(char *s)
標頭檔:string.h
格式:strlen (字元數組名)
功能:計算字串s的(unsigned int型)長度,
不包括'\0'在內
說明:返回s的長度,不包括結束符NULL。五、strcomp
原型:int strcmp(const char * cs, const char * ct)
說明:strcmp(cs,ct)比較字串cs 和ct;當cs<ct 時,返回一個-1;當cs==ct 時,返回0;當cs>ct 時,返回1
例子:
#include <stdio.h>
#include <string.h>
int main()
{
char *Mid="ab";
char *Min="aa";
char *Max="ac";
printf("strcmp(Mid,Mid)=%d\n",strcmp(Mid,Mid));
printf("strcmp(Max,Min)=%d\n",strcmp(Max,Min));
printf("strcmp(Min,Max)=%d\n",strcmp(Min,Max));
return 0;
}
六、fopen
函數功能:開啟一個檔案
函數原型:FILE * fopen(const char * path,const char * mode);
所在標頭檔:<stdio.h>
傳回值:檔案順利開啟後,指向該流的檔案指標就會被返回。如果檔案開啟失敗則返回NULL。
一般而言,開啟檔案後會作一些檔案讀取或寫入的動作,若開啟檔案失敗,接下來的讀寫動作也無法順利進行,所以一般在fopen()後作錯誤判斷及處理。
參數說明:
參數path字串包含欲開啟的檔案路徑及檔案名稱,參數mode字串則代表著流形態。
mode有下列幾種形態字串:
r 以唯讀方式開啟檔案,該檔案必須存在。
r+ 以可讀寫方式開啟檔案,該檔案必須存在。
rb+ 讀寫開啟一個二進位檔案,允許讀資料。
rw+ 讀寫開啟一個文字檔,允許讀和寫。
w 開啟唯寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案。
w+ 開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。
a 以附加的方式開啟唯寫檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾,即檔案原先的內容會被保留。(EOF符保留)
a+ 以附加方式開啟可讀寫的檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾後,即檔案原先的內容會被保留。 (原來的EOF符不保留)
wb 唯寫開啟或建立一個二進位檔案;只允許寫資料。
wb+ 讀寫開啟或建立一個二進位檔案,允許讀和寫。
ab+ 讀寫開啟一個二進位檔案,允許讀或在檔案末追加資料。
at+ 開啟一個叫string的檔案,a表示append,就是說寫入處理的時候是接著原來檔案已有內容寫入,不是從頭寫入覆蓋掉,t表示開啟檔案的類型是文字檔,+號表示對檔案既可以讀也可以寫。
上述的形態字串都可以再加一個b字元,如rb、w+b或ab+等組合,加入b 字元用來告訴函數庫以二進位模式開啟檔案。如果不加b,表示預設加了t,即rt,wt,其中t表示以文字模式開啟檔案。 有些C編譯系統可能不完全提供所有這些功能,有的C版本不用"r+","w+","a+",而用"rw","wr","ar"等,讀者注意所用系統的規定。七、strcpy原型聲明:extern char *strcpy(char *dest,const char *src);標頭檔:#include <string.h>功能:把從src地址開始且含有NULL結束符的字串複製到以dest開始的地址空間說明:src和dest所指記憶體地區不可以重疊且dest必須有足夠的空間來容納src的字串。返回:指向dest的指標。八、time函數原型:time_t time(time_t * timer) 功能: 擷取當前的系統時間,返回的結果是一個time_t類型,其實就是一個大整數,其值表示從CUT(Coordinated Universal Time)時間1970年1月1日00:00:00(稱為UNIX系統的Epoch時間)到當前時刻的秒數。然後調用localtime將time_t所表示的CUT時間轉換為本地時間(我們是+8區,比CUT多8個小時)並轉成struct tm類型,該類型的各資料成員分別表示年月日時分秒。
補充說明:time函數的原型也可以理解為 long time(long *tloc),即返回一個long型整數。因為在time.h這個標頭檔中time_t實際上就是: #ifndef _TIME_T_DEFINED
typedef long time_t; /* time value */
#define _TIME_T_DEFINED /* avoid multiple defines of time_t */
#endif
即long。
九、ctime
功能: 把日期和時間轉換為字串
原型: char *ctime(const time_t *time);