目录
1 char *strtok(char *s, char *delim). 2
char *strtok_r(char *s, const char *delim, char **ptrptr);2
2 extern char *strstr(char *str1, char *str2). 3
3 size_t strspn (const char *s,const char * accept). 4
4 size_t strcspn(const char *s1,const char *s2);4
5 char *strrchr(char *str, char c);5
6 extern char *strcpy(char* dest, const char *src). 5
7 extern int strcmp(char *s1,char * s2). 5
8 double strtod(const char *nptr,char **endptr). 5
9 extern char *strncat(char *dest,char *src,int n). 5
10 extern char *strcat(char *dest,char *src). 6
11 extern int toupper(int c). 6
13 size_t strlen( const char *_Str )... 6
14 void *memcpy(void *dest, const void *src, size_t n). 7
1char *strtok(char *s, char *delim)
-字符串分割函数
功能:分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。实质上的处理是,strtok在s中查找包含在delim中的字符并用NULL(’\0′)来替换,直到找遍整个字符串。
说明:首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。strtok在s中查找包含在delim中的字符并用NULL(’\0′)来替换,直到找遍整个字符串。
返回值:从s开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。所有delim中包含的字符都会被滤掉,并将被滤掉的地方设为一处分割的节点。
具体使用例子:
- char* token = strtok( buf1, ",");
- while( token != NULL )
- {
printf( "%s", token );
token = strtok( NULL,",");
- }
问题:
char * buf1=”aaa, ,a, ,,,bbb-c,,,ee|abc”;
buff1指向一个常量区。
根据If string is not NULL, the function scans string forthe first occurrence of any character included in delimiters. If it is found,the function overwrites thedelimiter in string by a null-character and returns a pointer to the token,i.e. the part of the scanned string previous to the delimiter.注意这句话中有overwirtes这个单词,常量区是不能overwirte的!!!,所以得用char buff1[]。
1char *strtok_r(char *s, const char *delim, char **ptrptr);
-字符串分割新函数
带有_r的函数主要来自于UNIX下面。所有的带有_r和不带_r的函数的区别的是:带_r的函数是线程安全的,r的意思是reentrant,可重入的。
对于没有_r的函数,函数中使用static变量,但是在多线程时,很可能会出错,因此这个ptrptr所指向的地址保存的就是当前线程的调用结果,这样不同线程调用这个函数的时候就不会出错了,具体是什么内容用户不必知道,只需要传入一个有效的地址就行了。
charbuffer[INFO_MAX_SZ]="Fred male 25,John male 62,Anna female 16";
char *p[20]; char *buf=buffer; char *outer_ptr=NULL; char *inner_ptr=NULL;
while((p[in]=strtok_r(buf,",",&outer_ptr))!=NULL)
{
buf=p[in];
while((p[in]=strtok_r(buf," ",&inner_ptr))!=NULL)
{
in++;
buf=NULL;
}
p[in++]="***";
buf=NULL;
}
printf("Here we have %d strings\n",i);
for (int j=0; jn<i; j++)
printf(">%s<\n",p[j]);
这一次的输出为:
Here we have 12 strings
>Fred<
>male<
>25<
>***<
>John<
>male<
>62<
>***<
>Anna<
>female<
>16<
>***<
2 externchar *strstr(char *str1, char *str2)
-字符串查找函数
功能:从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。
返回值:返回该位置的指针,如找不到,返回空指针。
举例说明:
1 2 3 4 5 6 7 8 | char *s=” string1 onexxx string2 oneyyy”; char *p; p=strstr(s,”string2”); if(p==NULL) printf(“Not Found!”); p=strstr(p,”one”); if(p==NULL) printf(“Not Found!”); p+=strlen(“one”); printf(“%s”,p); |
说明:如果直接写语句p=strstr(s,”one”),则找到的是onexxx string2 oneyyy,不符合要求所以需采用二次查找法找到目标实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | char *mystrstr(char *s1 , char *s2) { if(*s1==0) { if(*s2) return(char*)NULL; return (char*)s1; } while(*s1) { int i=0; while(1) { if(s2[i]==0) return s1; if(s2[i]!=s1[i]) break; i++; } s1++; } return (char*)NULL; } |
3 size_tstrspn (const char *s,const char * accept)
函数说明: strspn()从参数s 字符串的开头计算连续的字符,而这些字符都完全是accept 所指字符串中的字符。简单的说,若strspn()返回的数值为n,则代表字符串s 开头连续有n 个字符都是属于字符串accept内的字符。
返回值: 返回字符串s开头连续包含字符串accept内的字符数目。
举例说明:
5 char *str="Linux was first developed for386/486-based pcs.";
6 printf("%d\n",strspn(str,"Linux"));
7 printf("%d\n",strspn(str,"/-"));
8printf("%d\n",strspn(str,"1234567890"));
输出结果
5
0
0
4 size_t strcspn(const char *s1,const char *s2);
功能:顺序在字符串s1中搜寻与s2中字符的第一个相同字符,包括结束符NULL,返回这个字符在S1中第一次出现的位置。返回字符串s1中第一个在s2中出现的字符在s1中的下标值,亦即在s1中出现而s2中没有出现的子串的长度。
函数说明:strcspn()从参数s1字符串的开头计算连续的字符, 而这些字符都完全不在参数s2指的字符串中. 简单地说, 若strcspn()返回的数值为n, 则代表字符串s1开头连续有n 个字符都不含字符串s2的字符.
返回值:返回字符串s 开头连续不含字符串reject 内的字符数目.
举例说明
char *str = "Linux was first developedfor 386/486-based pcs. ";
printf("%d\n", strcspn(str, " "));
printf("%d\n", strcspn(str, "/-"));
printf("%d\n", strcspn(str, "1234567890"));
执行结果:
5 //只计算到" "的出现, 所以返回"Linux"的长度
33 //计算到出现"/"或"-", 所以返回到"6"的长度
30 // 计算到出现数字字符为止, 所以返回"3"出现前的长度
5 char*strrchr(char *str, char c);
函数功能:查找一个字符c在另一个字符串str中末次出现的位置(也就是从str的右侧开始查找字符c首次出现的位置),并返回从字符串中的这个位置起,一直到字符串结束的所有字符。如果未能找到指定字符,那么函数将返回NULL。
举例说明
char string[20];
char *ptr, c = 'r';
strcpy(string, "Thereare two rings");
ptr = strrchr(string, c);
if (ptr)
printf("The character %c is at position: %s\n", c, ptr);
else
printf("Thecharacter was not found\n");
strrchr返回的指针应当指向"rings"里的'r',而不是“There”或"are"里的'r'。
6 externchar *strcpy(char* dest, const char *src)
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针
7 extern int strcmp(char *s1,char* s2)
功能:比较字符串s1和s2。
说明:
当s1<s2时,返回值<0
当s1=s2时,返回值=0
当s1>s2时,返回值>0
8 doublestrtod(const char *nptr,char **endptr)
函数说明:strtod()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,到出现非数字或字符串结束时('\0')才结束转换,并将结果返回。
若endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr传回。
参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分。如123.456或123e-2
9 extern char*strncat(char *dest,char *src,int n)
用法:#include <string.h>
功能:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
10 extern char *strcat(char*dest,char *src)
用法:#include <string.h>
功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
11 extern int toupper(int c)
用法:#include <ctype.h>
功能:将字符c转换为大写英文字母
说明:如果c为小写英文字母,则返回对应的大写字母;否则返回原来的值。
12 int tolower(int c)
功 能: 把字符转换成小写字母,非字母字符不做出处理
转换string类型的字符串的时候可以使用STL中的transform函数
string str("HelloWorld!");
transform(str.begin(), str.end(), str.begin(),::tolower);
可以实现将所有的字符转换为小写
函数说明: memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。
与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'/0'而结束
memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
返回值说明:返回指向dest的void *指针
附加说明: 指针src和dest所指的内存区域不可重叠
13 size_tstrlen( const char *_Str )
功能: 获取字符串长度, 字符串结束符NULL不计算在内。 没有返回值指示操作错误。
int Strlen( const char *_Str )
{
int length = 0;
assert(_Str != NULL);
while(*_Str++ != '\0'){
length++; }
return length;
}
14 void*memcpy(void *dest, const void *src, size_t n)
1.src和dest所指的内存区域可以重叠,但是如果src和dest所指的内存区域重叠,那么这个函数并不能够确保src所在重叠区域在拷贝之前被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向dest的指针。
2.strcpy和memcpy主要有以下3方面的区别。
2.1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2.2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
2.3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
3.如果目标数组dest本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。
注意:src和destin都不一定是数组,任意的可读写的空间均可。
15 void *memset(void *s, char ch, size_t n);
函数解释:将s中前n个字节用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法,n是以字节为单位的。
第一: 搞反了 ch 和 n 的位置.
一定要记住如果要把一个char a[20]清零,一定是 memset(a,0,20);而不是 memset(a,20,0);
第二: 过度使用memset,我想这些程序员可能有某种心理阴影,他们惧怕未经初始化的内存,所以他们会写出这样的代码:
1 2 3 | char buffer[20]; memset(buffer,0,sizeof(char)*20); strcpy(buffer,"123"); |
这里的memset是多余的. 因为这块内存马上就被覆盖了,清零没有意义.
第三: 其实这个错误严格来讲不能算用错memset,但是它经常在使用memset的场合出现
| int some_func(struct something *a) { memset(a,0,sizeof(a)); } |
这里错误的原因是VC函数传参过程中的指针降级,导致sizeof(a),返回的是一个 something*指针类型大小的的字节数,如果是32位,就是4字节。
16 sizeof
sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。
由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:
数组——编译时分配的数组空间大小;
指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);
类型——该类型所占的空间大小;
对象——对象的实际占用空间大小;
函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
**************
二、strlen
strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。
它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。
*************
三、举例:
eg1、char arr[10] ="What?";
int len_one =strlen(arr);
int len_two =sizeof(arr);
cout <<len_one << " and " << len_two << endl;
输出结果为:5 and10
点评:sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。strlen只关心存储的数据内容,不关心空间的大小和类型。
eg2、char * parr = new char[10];
int len_one =strlen(parr);
int len_two =sizeof(parr);
int len_three =sizeof(*parr);
cout <<len_one << " and " << len_two << " and "<< len_three << endl;
输出结果:23 and 4 and 1
点评:第一个输出结果23实际上每次运行可能不一样,这取决于parr里面存了什么(从parr[0]开始知道遇到第一个NULL结束);第二个结果实际上本意是想计算parr所指向的动态内存空间的大小,但是事与愿违,sizeof认为parr是个字符指针,因此返回的是该指针所占的空间(指针的存储用的是长整型,所以为4);第三个结果,由于*parr所代表的是parr所指的地址空间存放的字符,所以长度为1。
************
四、参考资料:
1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。
该类型保证能容纳实现所建立的最大对象的字节大小。
2.sizeof是算符,strlen是函数。
3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。
sizeof还可以用函数做参数,比如:short f(); printf("%d\n",sizeof(f()));
输出的结果是sizeof(short),即2。
4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;
6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
8.当适用一个结构类型时或变量, sizeof返回实际的大小,
当适用一静态地空间数组, sizeof归还全部数组的尺寸。
sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
fun(char [8])
fun(char [])
都等价于 fun(char*)
在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小
如果想在函数内知道数组的大小, 需要这样做:
进入函数后用memcpy拷贝出来,长度由另一个形参传进去
fun(unsiged char *p1, int len)
{
unsigned char* buf = new unsignedchar[len+1]
memcpy(buf, p1, len);
}
我们能常在用到 sizeof 和 strlen 的时候,通常是计算字符串数组的长度
看了上面的详细解释,发现两者的使用还是有区别的,从这个例子可以看得很清楚:
char str[20]="0123456789";
int a=strlen(str); //a=10; >>>> strlen 计算字符串的长度,以结束符 0x00 为字符串结束。
int b=sizeof(str); //而b=20; >>>> sizeof 计算的则是分配的数组 str[20]所占的内存空间的大小,不受里面存储的内容改变。
上面是对静态数组处理的结果,如果是对指针,结果就不一样了
char* ss = "0123456789";
sizeof(ss)=4===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是长整型的,所以是4
sizeof(*ss)=1===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类型的,占了 1 位
strlen(ss)=10===》 如果要获得这个字符串的长度,则一定要使用 strlen