伍
***字符串***
字符串是一種特殊的數組類型。字符串必須用’\0’作為結束標識。’\0’占用存儲空間,但不計入串的實際長度。
***字符串的初始化:***(編譯器會自動在其尾部添加’\0’標識)
~~~
char str[] = {‘a’, ‘b’, ‘c’} ; //標準形式
char str[] = {“abc”} ; //簡寫
char str[] = “abc” ; //最簡寫
注意:
char a[3] = “abc” ; //在C中是合法的。但其不是字符串,它沒有把’\0’存入。(C++中非法)
char a[3] = “abcdefg”; //也是合法的,但會產生警告。編譯器會只取前三個字符放到數組中
int a[3] = {1,2,3,4,5}; //是非法的。
~~~
char a[] = “abcd” ;? 與 char * p = “abcd” ; 的區別
***字符串字面量:***(也稱字符串常量,即形如“abcd”的)**
①當作為數組初始值時,它指明該數組中字符的初始值。(只是定義字符串的一種簡寫形式)
②在其它情況下,它會轉化為一個無名字符數組的首地址,且此字符數組存儲在內存中的只讀常量區中,這就導致它不能被修改。
故:上面,a[]是個字符串數組,而p是指向字符串首字符的指針。
例:”xyz”+1 的結果為:指向第二個字符的指針值
????? “xyz”[2]的結果為:字符z (方括號是一個后綴表達式的操作符)
注意:
ASCI C引入的另一個新特性是,**相鄰的字符串常量將被自動合并成一個字符串。**
這樣,后續的字符串也可以出現在每行的開頭。
***字符數組:***
char laguage[3][10] = {“BASIC”, “C++”, “JAVA”};
//數組的第一個下標決定了字符串的個數,第二個下標是字符串的最大長度。
//其在內存中開辟了一個 3*10*sizeof(char)大小的存儲區。
//由于字符串有長有短,故用數組會浪費一定的存儲空間。
***字符指針數組:***
char *p[] = {“BASIC”, “C++”, “JAVA”} ;
p是由三個字符指針組成的數組。這三個指針分別指向只讀區的三個無名字符串的首字符。
//字符指針數組可用于:單詞的檢索表。**
// char *p[] = {“BASIC”, “C++”, “JAVA”,NULL} ;若在表的末尾增加一個NULL指針作為結束標志,則可使在檢索的時候能檢測到表的結束,而無需預先知道表的長度。
***常用的字符串處理庫函數陷阱:***
**函數strlen( )的返回值是size_t**,這個類型是在頭文件stddef.h中定義的 是unsigned int 類型的別名。 故使用時一定要注意,隱私類型轉換可能產生的錯誤!
例: if(strlen(s1) – strlen(s2) >= 0 ) {........}
表達式的左邊的結果是無符號數,根據值的類型轉換提升規則,右邊的int型0會提升為無符號數。而無符號數是絕不可能為負的。故這個條件判斷永遠為真。
【為避免混用有符號數和無符號數 可能產生的問題,**在使用strlen( )時,設一個int型的變量來接收strlen( )的返回值,可避免錯誤。**】
**函數strncpy( )的結果將不會自動以’\0’字節結尾!你必須自己給結果字符串添加’\0’ 字節。**
函數strncat( )的結果會自動添加’\0’字節。(故:我們可把目的字符串先置空,然后就可用strncat( )來代替strncpy( )的功能 )
***函數***
***關于函數返回值***
**當設計函數返回指針時,一定要警惕!檢查其返回指針的類型。被調函數絕對不能返回本局部變量的指針**,(因為函數返回后其開辟的運行時棧,被回收,其中所有的局部變量被拋棄,返回它們的指針是無效的)。
函數返回的指針可以是:
①靜態分配的緩沖區。例:全局變量的指針 ?【少用】
②調入者傳入的緩沖區。(在主調函數中)?? 【常用】
③用malloc()獲得的內存????????????????? 【記得要在不用的時候釋放】
***主函數***
ANSI標準C規定了主函數的兩種形式:
int?main(void) ;
int?main(int? argc, char? **argv) ;
main( )所需的實參是在命令行與程序名一同輸入的。程序名和各實參之間用空格分隔。
格式為:含路徑的可執行程序名 參數1 參數2 ......參數n
形參argc 為命令行中參數的個數(包括執行程序名)其值大于等于1。
形參argv為一個二級指針? 指向一個指針數組的首元素,這個指針數組中的元素依次指向命令行中以空格分開的各參數字符串。(即第一個指針argv[0]指向的是程序名字符串,argv[1]指向的是參數1,......)
***可變參函數***(讓函數可以接受不定數目的參數)
可變參數列表是通過宏來實現的,這些宏定義于stdarg.h頭文件中,這個頭文件聲明了一個類型 va_list 和三個宏 va_start? va_arg? va_end
~~~
//計算不定數量值的平均值
#include <stdarg.h>
//注意:可變參數的類型必須保持一致!
double Average(int num, ...) //參數:第一個num為后面參數的個數,不定參數用3個點來表示。
{
va_list values ; //values是一個參數列表類型。其中包含著所有的不定參數。
int cnt=0 ;
float sum=0 ;
/*準備訪問可變參數*/
va_start( values, num ) ; //初始化參數列表變量values
for(cnt=0; cnt < num; cnt++)
sum += va_arg( values, double) ; // double指明參數列表中參數的類型,每調用一次此語句此宏表示的參數就順移到下一個參數。(如此,可順序地處理每個傳入的參數)
/*結束訪問可變參數*/
va_end( values ) ;
return sum/num ;
}
~~~
***內聯函數:***
函數指定符inline只能出現在函數聲明中,這種函數便成為內聯函數。使用inline是向編譯器所提供的提示,表示應該采用措施來提高這個函數的調用速度。即,對一個函數的調用將被該函數的一份拷貝所替代。(有點類似宏函數,但有區別)這就消除了函數調用的開銷。
【注意,編譯器并不一定要執行內聯展開,C程序不能依賴于一個函數調用將被內聯展開】
***動態內存分配***
【**勿忘:及時釋放不再使用的動態分配的內存!**】
***幾個庫函數:***
void * malloc(size_t? bit) ;????????????????? //函數名意為:memoryallocation
void * calloc(size_t num,? size_t bit) ;?//函數名意為:cleanallocation
此函數在返回指向內存的指針之前 把內存中的值初始化為0
void?realloc(void? *ptr, size_t? new_size) ;
此函數用于修改一個原先已經分配的內存塊大小。
①用于擴大內存塊。(新增內存添加到原先內存塊的后面)
②用于縮小內存塊。(內存塊的尾部部分被拿掉,剩余的內存內容保留)
③若原先內存塊的大小無法改變,則recalloc重新分配新內存,并復制原先內容。
【故在使用realloc函數時,通常不應該立即將新指針賦給就指針,最好用一個臨時指針】
void?free(void *ptr) ;
將指針ptr所指的動態存儲空間釋放。