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. |