2 C標準庫字符串
2.1 <stdlib.h>定義的寬字節字符wchar_t
在標準C中,字符串有兩種 char*和wchar_t*,一個是多字節字符串,另一個是寬字節字符串。前者是C的關鍵字,編譯器會直接爲其分配空間,而wchar_t在便準庫中定義,不包含頭文件的話,編譯器會報錯。但是可以修改項目屬性中的SDL選項來更改安全屬性,可以避免編譯錯誤。建議不使用,安全性控制由程序員控制,只要是考慮到跨平臺的問題。
2.2 C標準庫中操作字符的庫函數
注意:在新的VC++標準中,這些C標準庫的庫函數已經因爲安全性問題被禁用(主要是爲了防止內存泄露),取代的是C++提供的新的stdlib.h庫函數,這些函數通常具有更高的安全性,命名規則一般是在原來的庫函數後面加”_s”,或者在函數名前面加”_”亦或者都要加。
2.2.1 <stdlib.h>中定義
double atof(const char *str) |
把參數 str 所指向的字符串轉換爲一個浮點數(類型爲 double 型) 參數:str -- 要轉換爲浮點數的字符串 |
double db; char ch[40] = "18284.7475755"; db = ::atof(ch); |
|
int atoi(const char *str) |
把參數 str 所指向的字符串轉換爲一個整數(類型爲 int 型) 參數:str -- 要轉換爲整數的字符串 |
int db; char ch[40] = "18284"; db = ::atoi(ch); |
|
long int atol(const char *str) |
把參數參數 str 所指向的字符串轉換爲一個長整數(類型爲 long int 型) 參數:str -- 要轉換爲長整數的字符串 |
long val; char ch[40] = "18284"; db = ::atol(ch); |
|
double strtod(const char *str, char **endptr) |
把參數 str 所指向的字符串轉換爲一個浮點數(類型爲 double 型)。如果 endptr 不爲空,則指向轉換中最後一個字符後的字符的指針會存儲在 endptr 引用的位置 參數: str -- 要轉換爲雙精度浮點數的字符串。 endptr -- 對類型爲 char* 的對象的引用,其值由函數設置爲 str 中數值後的下一個字符。 |
double db; char ch[50] = "183495.8475756\0aaa"; char *pc; db = ::strtod(ch, &pc);//db==183495.8475756 pc++; //pc最終指向”aaa” |
|
long int strtol(const char *str, char **endptr, int base) |
把參數 str 所指向的字符串根據給定的 base 轉換爲一個長整數(類型爲 long int 型),base 必須介於 2 和 36(包含)之間,或者是特殊值 0。 參數: str -- 要轉換爲長整數的字符串。 endptr -- 對類型爲 char* 的對象的引用,其值由函數設置爲 str 中數值後的下一個字符。 base -- 基數,必須介於 2 和 36(包含)之間,或者是特殊值 0。(位權) |
unsigned long int strtoul( const char *str, char **endptr, int base)。 |
把參數 str 所指向的字符串根據給定的 base 轉換爲一個無符號長整數(類型爲 unsigned long int 型),base 必須介於 2 和 36(包含)之間,或者是特殊值 0 參數: str -- 要轉換爲無符號長整數的字符串。 endptr -- 對類型爲 char* 的對象的引用,其值由函數設置爲 str 中數值後的下一個字符。 base -- 基數,必須介於 2 和 36(包含)之間,或者是特殊值 0。 |
void *calloc(size_t nitems, size_t size) |
分配所需的內存空間,並返回一個指向它的指針。malloc 和 calloc 之間的不同點是,malloc 不會設置內存爲零,而 calloc 會設置分配的內存爲零。 參數: nitems -- 要被分配的元素個數。 size -- 元素的大小。 |
分析如下代碼: char *pc = (char*)::calloc(10, sizeof(char));//在程序堆棧中申請10個char類型的長度(10個byte) for (int i = 0; i < 16;i++)//但卻賦值了16個字節的值 { pc[i] = 'a'; }//執行完後pc字符串的值爲” aaaaaaaaaaaaaaaa鉿”,除了出現我們要求賦的字符還出現了亂碼,再看下下面兩個函數的返回值 size_t nstr = sizeof(pc);//nstr==4,對char*指針使用sizeof()是無意義的,即使是const char*或者 char* const,除非char pc[]=”aaaa”; size_t strlength = strlen(pc);//strlength==24,當計算字符串的長度時是以’\0’爲結束標誌的,如果是使用以上的動態分配空間創建字符串必須在字符串結束的後一位置手動賦值’\0’ |
|
void free(void *ptr) |
釋放之前調用 calloc、malloc 或 realloc 所分配的內存空間。 參數: ptr – 指針指向一個要釋放內存的內存塊,該內存塊之前是通過調用 malloc、calloc 或 realloc 進行分配內存的。如果傳遞的參數是一個空指針,則不會執行任何動作。 |
void *malloc(size_t size) |
分配所需的內存空間,並返回一個指向它的指針。 參數:size -- 內存塊的大小,以字節爲單位。 |
malloc, calloc與new的區別:前者由C標準庫定義,如果使用時不包含<stdlib.h>就會編譯出錯;而new是C++關鍵字,不需要包含任何頭文件,編譯器會自動將其編譯爲目標代碼。malloc返回值爲void*,我們需要顯示轉換(char*)malloc(),而new則不需我們人爲做這些操作,並且可以自動計算所需要大小。 |
|
void *realloc(void *ptr, size_t size) |
嘗試重新調整之前調用 malloc 或 calloc 所分配的 ptr 所指向的內存塊的大小 參數: ptr -- 指針指向一個要重新分配內存的內存塊,該內存塊之前是通過調用 malloc、calloc 或 realloc 進行分配內存的。如果爲空指針,則會分配一個新的內存塊,且函數返回一個指向它的指針。 size -- 內存塊的新的大小,以字節爲單位。如果大小爲 0,且 ptr 指向一個已存在的內存塊,則 ptr 所指向的內存塊會被釋放,並返回一個空指針。 |
int mblen(const char *str, size_t n) |
返回參數 str 所指向的多字節字符的長度。 參數: str -- 指向多字節字符的第一個字節的指針。 n -- 要檢查的字符長度的最大字節數。 |
char ch[10] = "abcdefg"; int nlen = ::mblen(ch, sizeof(ch)); //nLen==1,表示一個char字符佔一個字節 |
|
size_t mbstowcs(schar_t *pwcs, const char *str, size_t n) |
把參數 str 所指向的多字節字符的字符串轉換爲參數 pwcs 所指向的數組。 參數: pwcs -- 指向一個 wchar_t 元素的數組,數組長度足以存儲一個最大字符長度的寬字符串。 str -- 要被轉換的多字節字符字符串。 n -- 要被轉換的最大字符數。 |
wchar_t wch[10]=_T("\0"); size_t nwch; char mbch[4] = "123"; ::mbstowcs_s(&nwch, wch, mbch, strlen(mbch)); //在C++標準庫中認爲mbstowcs不安全,要求使用mbstowcs_s,第一個參數實際轉換的字符數的引用,(其他重載參看MSDN) |
|
int mbtowc(whcar_t *pwc, const char *str, size_t n) |
把一個多字節序列轉換爲一個寬字。 參數: pwc -- 指向類型爲 wchar_t 對象的指針。 str -- 指向多字節字符的第一個字節的指針。 n -- 要被檢查的最大字節數。 |
char ch = 'a'; wchar_t wch; int nwchar = ::mbtowc(&wch, &ch, ::mblen(&ch,sizeof(char)));//由於編譯器的不同,所以建議先用mblen()計算一個多字節字符的長度 int nLen = sizeof(wch);//nLen==2 |
|
size_t wcstombs(char *str, const wchar_t *pwcs, size_t n) |
把寬字符字符串 pwcs 轉換爲一個 str 開始的多字節字符串。最多會有 n 個字節被寫入 str 中。 參數: pwc -- 指向類型爲 wchar_t 對象的指針。 str -- 指向多字節字符的第一個字節的指針。 n -- 要被檢查的最大字節數。 返回: 該函數返回轉換和寫入到 str 中的字節數,不包括結尾的空字符。 |
int wctomb(char *str, wchar_t wchar) |
把一個寬字符 wchar 轉換爲它的多字節表示形式,並把它存儲在 str 指向的字符數組的開頭。 參數: str -- 一個指針,指向一個足以存儲多字節字符的數組。 wchar -- 類型爲 wchar_t 的寬字符。 |
2.2.2 <ctype.h>中定義
C 標準庫的 ctype.h 頭文件提供了一些函數,可用於測試和映射單個字符。
這些函數接受 int 作爲參數,它的值必須是 EOF 或表示爲一個無符號字符。
如果參數 c 滿足描述的條件,則這些函數返回非零(true)。如果參數 c 不滿足描述的條件,則這些函數返回零。
int isalnum(int c) |
int isalpha(int c) |
int iscntrl(int c) |
int isdigit(int c) |
int isgraph(int c) |
int islower(int c) |
int isprint(int c) |
int ispunct(int c) |
int isspace(int c) |
int isupper(int c) |
int isxdigit(int c) |
標準庫還包含了兩個轉換函數,它們接受並返回一個 "int"
int tolower(int c) |
int toupper(int c) |
2.2.3 <stdio.h>中定義
int fprintf(FILE *stream, const char *format, ...) // fprintf(stdout,”aaaa”)==printf(“aaaa”) |
發送格式化輸出到流 stream 中。 參數: stream -- 這是指向 FILE 對象的指針,該 FILE 對象標識了流。 format -- 這是 C 字符串,包含了要被寫入到流 stream 中的文本。它可以包含嵌入的 format 標籤,format 標籤可被隨後的附加參數中指定的值替換,並按需求進行格式化。format 標籤屬性是 %[flags][width][.precision][length]specifier |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int vfprintf( FILE *stream, const char *format, va_list arg ) // fprintf的內部實現 |
使用參數列表發送格式化輸出到流 stream 中 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void WriteFrmtd(FILE *stream, char *format, ...) { va_list args; va_start(args, format); vfprintf(stream, format, args);//相當於重定位 va_end(args); } void main() { WriteFrmtd(stdout, "This is just one argument %d \n%f", 10,1.9); } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int printf(const char *format, ...) |
發送格式化輸出到標準輸出 stdout 參數: format -- 這是字符串,包含了要被寫入到標準輸出 stdout 的文本。它可以包含嵌入的 format 標籤,format 標籤可被隨後的附加參數中指定的值替換,並按需求進行格式化。format 標籤屬性是 %[flags][width][.precision][length]specifier,具體講解如下:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
討論一下printf函數的實現: void MyPrintf(char* formate, int param0 = ‘\0’, ...) { va_list ap; va_start(ap, formate); char *pch = formate; int nSpecifier = 0; //判斷格式字符串的個數 while (*pch!='\0') { if (*pch == '%' && (*(pch + 1) == 'd' || *(pch + 1) == 'c')) { nSpecifier++; pch++; } pch++; } //如果沒有格式字符串就直接輸出 if (nSpecifier == 0 && param0 == '\0') { printf(formate); return; } //else pch = formate; int n = 0; while (n<nSpecifier) { while (*pch != '%' && *pch!='\0') { cout << *pch; pch++; } //目前只支持兩種格式字符串控制 switch (*(pch + 1)) { case 'd':printf("%d", va_arg(ap, int)); break; case 'c':printf("%c", va_arg(ap, char)); break; default: break; } pch += 2; n++; } va_end(ap); } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int vprintf(const char *format, va_list arg) //等於vfprintf(stdout, format, args); //是printf函數的實現 |
使用參數列表發送格式化輸出到標準輸出 stdout |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void MtPrintf(char *format, ...) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int sprintf(char *str, const char *format, ...) |
發送格式化輸出到 str 所指向的字符串 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int vsprintf(char *str, const char *format, va_list arg) // sprintf的實現 |
使用參數列表發送格式化輸出到字符串 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int scanf(const char *format, ...) |
從標準輸入 stdin 讀取格式化輸入。*問題*貌似在vs2013中scanf_s包括<conio.h>中的_cscanf_s()使用後都沒有反應,必須寫明接收的字節數如:scanf_s(“%s”, ch, sizeof(ch)); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int fscanf(FILE *stream, const char *format, ...) |
從流 stream 讀取格式化輸入。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int getc(FILE *stream) |
從指定的流 stream 獲取下一個字符(一個無符號字符),並把位置標識符往前移動 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
char c; printf("請輸入字符:"); c = getc(stdin);//相當於getchar() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int getchar(void) |
從標準輸入 stdin 獲取一個字符(一個無符號字符)。這等同於 getc 帶有 stdin 作爲參數 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
char *gets(char *str) |
從標準輸入 stdin 讀取一行,並把它存儲在 str 所指向的字符串中。當讀取到換行符時,或者到達文件末尾時,它會停止,具體視情況而定。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int fgetc(FILE *stream) 從指定的流 stream 獲取下一個字符(一個無符號字符),並把位置標識符往前移動。 char *fgets(char *str, int n, FILE *stream) 從指定的流 stream 讀取一行,並把它存儲在 str 所指向的字符串內。當讀取 (n-1) 個字符時,或者讀取到換行符時,或者到達文件末尾時,它會停止,具體視情況而定。 int fputc(int char, FILE *stream) 把參數 char 指定的字符(一個無符號字符)寫入到指定的流 stream 中,並把位置標識符往前移動。 int fputs(const char *str, FILE *stream) 把字符串寫入到指定的流 stream 中,但不包括空字符。 int getc(FILE *stream) 從指定的流 stream 獲取下一個字符(一個無符號字符),並把位置標識符往前移動。 int getchar(void) 從標準輸入 stdin 獲取一個字符(一個無符號字符)。 char *gets(char *str) 從標準輸入 stdin 讀取一行,並把它存儲在 str 所指向的字符串中。當讀取到換行符時,或者到達文件末尾時,它會停止,具體視情況而定。 int putc(int char, FILE *stream) 把參數 char 指定的字符(一個無符號字符)寫入到指定的流 stream 中,並把位置標識符往前移動。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int putchar(int char) 把參數 char 指定的字符(一個無符號字符)寫入到標準輸出 stdout 中。 int puts(const char *str) 把一個字符串寫入到標準輸出 stdout,直到空字符,但不包括空字符。換行符會被追加到輸出中。 int ungetc(int char, FILE *stream) 把字符 char(一個無符號字符)推入到指定的流 stream 中,以便它是下一個被讀取到的字符。 void perror(const char *str) 把一個描述性錯誤消息輸出到標準錯誤 stderr。首先輸出字符串 str,後跟一個冒號,然後是一個空格。 |
2.2.4 <string.h> 中定義
函數 & 描述 |
void *memchr(const void *str, int c, size_t n) |
int memcmp(const void *str1, const void *str2, size_t n) |
void *memcpy(void *dest, const void *src, size_t n) |
void *memmove(void *dest, const void *src, size_t n) |
void *memset(void *str, int c, size_t n) |
char *strcat(char *dest, const char *src) |
char *strncat(char *dest, const char *src, size_t n) |
char *strchr(const char *str, int c) |
int strcmp(const char *str1, const char *str2) |
int strncmp(const char *str1, const char *str2, size_t n) |
int strcoll(const char *str1, const char *str2) |
char *strcpy(char *dest, const char *src) |
char *strncpy(char *dest, const char *src, size_t n) |
size_t strcspn(const char *str1, const char *str2) |
int len; const char str1[] = "ABCDEF4960910"; const char str2[] = "013"; len = strcspn(str1, str2); printf("第一個匹配的字符是在 %d\n", len + 1);//輸出10,實際上就是找str1中第一個包含在str2中任意字符的位置 |
char *strerror(int errnum) |
size_t strlen(const char *str) |
char *strpbrk(const char *str1, const char *str2) |
char *strrchr(const char *str, int c) |
size_t strspn(const char *str1, const char *str2) |
int len; const char str1[] = "ABCDEFG019874"; const char str2[] = "ABCD"; len = strspn(str1, str2); printf("初始段匹配長度 %d\n", len );//輸出4,即找到str1中第一個不在str2中出現過的字符 |
char *strstr(const char *haystack, const char *needle) |
char *strtok(char *str, const char *delim) |
size_t strxfrm(char *dest, const char *src, size_t n) |
2.2.5 <conio.h>(非標準庫--控制檯輸入輸出庫)
注:conio.h不是C標準庫中的頭文件
char *cgets( char *buffer ); |
從鍵盤得到一個字符串 |
int cputs( const char *string ) |
在當前光標處向文本屏幕輸出字符串str,光標自動右移字符串長度個字符位置 |
char ch[10]; size_t nLen; _cgets_s(ch,&nLen); //vc6.0後採用_cgets_s,參數二是實際獲得的字節數 _cputs(ch); //vc6.0後採用_cputs |
|
int _cscanf_s(char *format[,argument, ...]) C++新標準_cscanf_s |
從控制檯執行格式化輸入 |
int inp( unsigned short port ); unsigned short inpw( unsigned short port ); unsigned long inpd( unsigned short port ); |
從端口逐字節 (_inp),逐字 (_inpw)或者逐雙字 (_inpd)輸入。 |
int getch(void) |
這個函數是一個不回顯函數,當用戶按下某個字符時,函數自動讀取,無需按回車,有的C語言命令行程序會用到此函數做遊戲,但是這個函數並非標準函數,要注意移植性! |
int getche(void); |
輸入後立即從控制檯取字符,不以回車爲結束(帶回顯) |
注意不同版本編譯器對函數名的要求(以下是VS2013的錯誤提示): error C4996: 'getche': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getche. See online help for details. error C4996: 'getch': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getch. See online help for details. |