偷偷告诉你C的有些难题是这样理解的(1)
1.string.h
包含了使用字符串函数所需的原型和声明,尽管非必须,但是包含这个头文件的确是件好事情,因为有了它所包含的原型,编译器可以更好的为你的程序检查错误。
2.字符串的长度
*字符串的长度就是字符串所包含的字符的个数
以下是一段求字符串长度的函数
size_t strlen(char const *string){
int length = 0;
for(length;*string!='\0';*string++)length++;
return length;}
}
实现的例子
#include <stdio.h>
size_t strlen(char const *string);
int main(){
char str[] = "1234567890";
int length = strlen(str);
printf("the num is :%d\n",length);
return 0;
}size_t strlen(char const *string){
assert( string != NULL ); //断言字符串地址非0
int length = 0;
for(length;*string!='\0';*string++) length++;
return length;
}***我们应该利用string.h中的strlen函数,因为可以直接复用此函数,可以提高我们的使用效率,寻找一种更好的算法比改进一个糟糕的算法更有效率,复用已经存在的软件比重写一个软件更加的有效率。
3.字符串函数
strcpy
char *strcpy(char *dst , char const *src)
/*dst参数必须是一个字符数组或者是一个指向动态分配的内存的数组指针,不能使用字符串常量
strcpy 只是返回dst的一份拷贝,就是一个指向目标字符数组的指针
*/
void test1(char* str1)
{
char string[10];
if( strlen( str1 ) < strlen(string) )
{
strcpy( string, str1 );
}printf(“%s”, string);
}
strcat
char *strcat(char *dst , char const *src)
/*dst参数必须是一个字符数组或者是一个指向动态分配的内存的数组指针,不能使用字符串常量,在dst的空间的判定的过程中要考虑目标数组的原有的字符,两者要结合考虑。
*/
void test1()
{
char string[10];
if( (strlen( str1 ) + strlen(str2) )< strlen(string) )
{
strcat( string, str2 );
}printf(“%s”, string);
}
strcmp
用于两个字符串的比较,比较的结果是int类型,int strcmp(char const *s1 , char const *s2)
s1 > s2--->大于0
s1 < s2 --->小于0
最好的办法就是和零值比较,然后得出布尔值
strncpy,strncat,strncmp
在使用这几个函数的时候,要注意他们是有数目的限制的,而且他们的结果将不会以nul字节为结尾
在 ANSI C 中,strcpy 的安全版本是 strncpy
char *strncpy(char *s1, const char *s2, size_t n);char *strncat(char *s1, const char *s2, size_t n);
char strncmp(char *s1, const char *s2, size_t n);
但 strncpy 其行为是很诡异的(不符合我们的通常习惯)。标准规定 n 并不是 sizeof(s1),而是要复制的 char 的个数。一个最常见的问题,就是 strncpy 并不帮你保证 \0 结束。
char buf[8];
strncpy( buf, "abcdefgh", 8 );
看这个程序,buf 将会被 "abcdefgh" 填满,但却没有 \0 结束符了。
另外,如果 s2 的内容比较少,而 n 又比较大的话,strncpy 将会把之间的空间都用 \0 填充。这又出现了一个效率上的问题,如下:
char buf[80];
strncpy( buf, "abcdefgh", 79 );
上面的 strncpy 会填写 79 个 char,而不仅仅是 "abcdefgh" 本身。
strncpy 的标准用法为:(手工写上 \0)
strncpy(path, src, sizeof(path) - 1);
path[sizeof(path) - 1] = '\0';
len = strlen(path);
strchr,strbrk,strstr
char string[20] = “hello , there ,honey”;
char *acs;
char *ans;
char *ams;
acs = strchr(string , ‘h’);
返回是一个指针,也就是找到的’h’字符第一次出现的位置
ans = strbrk(string,’aeiou’);
返回一个指针,但是这次范围比较大,只要有’aeiou’中的任何一个字母都可以
ams = strstr(string,’hello’);
返回一个指针,条件是要找到’hello’整个相搭配的数组
4.字符分类
每个分类函数接受一个包含字符值的整型参数,函数测试这个字符并返回一个整型值,表示真或假:
iscntrl 任何控制字符
isspace 空白字符:空格' ',换页'\f',换行'\n',回车'\n',制表符'\t',垂直制表符'\v'
isdigit 十进制数字 0-9
isxdigit 十六进制数字,包括所有十进制数字,小写字母 a-f,大写字母 A-F
islower 小写字母 a-z
isupper 大写字母 A-Z
isalpha 字母 a-z 或 A-Z
isalnum 字母或数字,a-z,A-Z,0-9
ispunct 标点符号,任何不属于数字或字母的图形字符(可打印符号)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符//对于ctype.h中的函数应用,要一个个写出来!!!!!!!!!!!!!!!!!!!
字符转换
int tolower(int ch);
int toupper(int ch);
直接测试或操作字符将会降低程序的可移植性,如下:
if (ch >= 'A' && ch <= 'Z') 这条语句在使用 ASCII 字符集上的机器能够运行,但在使用 EBCDIC 字符集上的机器将会失败,但是下面语句在任何机器都能顺利运行
if (isupper(ch))
内存操作
这些函数能够操作任意的字节序列,和 strn 带头的函数不同,它们在遇到NULL字节时并不会停止操作
void *memcpy(void *dst, void const *src, size_t length);
void *memmove(void *dst, void const *src, size_t length);
void *memcmp(void const *a, void const *b, size_t length);
void *memchr(void const *a, int ch, size_t length);
void *memset(void *a, int ch, size_t length);memcpy 从 src 的起始位置复制 length 个字节到 dst 的内存起始位置,可以用这个方法复制任何类型的值,第 3 个参数指定复制值的长度(字节),如果 src 和 dst 以任何形式出现了重叠,它的结果是未定义的.
char temp[SIZE], values[SIZE];
....
memcpy(temp, values, SIZE);它从数组 values 复制SIZE个字节到数组 temp.
但是如果两个数组都是整型数组,则:
memcpy(temp, values, sizeof(val ues));
前两个参数不需要强制类型转换,因为在原型中,参数的类型都是 void*型指针,任何类型的指针都可以转换为 void* 型指针.
对于长度大于一个字节的数据,要确保把数量和数据类型的长度相乘,如:
memcpy(saved_answer, answers, count * sizeof(answers[0]));
也可以用这种技巧复制结构或结构数组.
memmove 和 memcpy 的行为差不多,只是它的源和目的操作数可以重叠, 它可以比 memcpy 慢一些,但是如果源和目标参数真的可能存在重叠,变应该使用 memmove.
memcmp 对两段内存的内容进行比较,两段内存起始于 a 和 b,共比较 length 个字节这些值按照无符号字符逐字节进行比较,由于这些值是根据一串无符号字节比较的,所以如果 memcmp 函数用于比较不是单字节的数据如整数或浮点数时就可能给出不可预料的结果.
memchr 从 a 的起始位置开始查找字符 ch 第 1 次出现的位置,并返回一个指向该位置的指针,它共查找 length 个字节,如果在这 length 个字节中未找到该字符,函数就返回一个 NULL 指针.
memset 把从 a 开始的 length 个字节都设置为字符值 ch.如:memset(buffer, 0 ,SIZE);把 buffer 的前 SIZE 个字节都初始化为 0.
5.警告总结
1.strlen函数要给予符号或者类型,不要直接用strlen的size_t类型来运算
2.strcmp返回值和0比较,然后得出布尔值
3.strcpy注意目标函数的长度,要注意其是否有越界的危险。
6.字符串的提示总结
1.尽量不要试图编写功能相同的函数来取代库函数,将自己的时间花在别的事情上,不要浪费时间在这个上面
2.使用字符分类和转换函数可以提高函数的移植性