字符串操作汇总-持续更新中

目录

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

12 int tolower(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中包含的字符都会被滤掉,并将被滤掉的地方设为一处分割的节点。

具体使用例子:

  1. char* token = strtok( buf1, ",");
  2. while( token != NULL )
  3. {

printf( "%s", token );

token = strtok( NULL,",");

  1. }

问题:

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值