dufaxing To be a better man

C 字符串库函数

2017-10-10


strcpy & strncpy

strcpy

strcpy(char* dest, const char *src);
复制字符串 src 到字符串 dest。

strcpy是一种C语言的标准库函数,strcpy把从src地址开始且含有’\0’结束符的字符串复制到以dest开始的地址空间,返回值的类型为char*。

  • 原型声明:char *strcpy(char* dest, const char *src);
  • 头文件:#include <string.h>#include <stdio.h>
  • 功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
  • 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
  • 返回指向dest的指针。

strncpy

strncpy(char *dest,char *src,size_t n);
将src中n个字符复制到dest中。

strncpy 是 C语言的库函数之一,来自 C语言标准库,定义于 string.h,char *strncpy(char *dest, const char *src, int n),把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。

  • 原型:char *strncpy(char *dest,char *src,size_t n);
  • 头文件:#include<string.h>
  • 功能:(c/c++)复制字符串src中的内容(字符,数字、汉字….)到字符串dest中,复制多少由size_t n的值决定。如果src的前n个字符不含NULL字符,则结果不会以NULL字符结束。如果n<src的长度,只是将src的前n个字符复制到dest的前n个字符,不自动添加’\0’,也就是结果dest不包括’\0’,需要再手动添加一个’\0’。如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符长度+’\0’。
  • demo code
#include<stdio.h>
#include<string.h>
int main()
{
	char name[]={"Chinanet"},dest[20]={};
	strncpy(dest,name,3);
	dest[3]='\0';//没有会乱码
	printf("%s\n",dest);
}

(1)src串长度<=dest串长度,(这里的串长度包含串尾NULL字符)
如果n>src由于长度达到src NULL,正常复制,特别注意,如果src中有NULL,strncpy复制到NULL即使没到n也提前停止。如果n = src串长度,与strcpy一致。注意n的选择当n > dest串长度,dest栈空间溢出产生崩溃异常。
(2)src串长度>dest串长度
如果n =dest串长度,则dest串没有NULL字符,会导致输出会有乱码。如果不考虑src串复制完整性,可以将dest 最后一字符置为NULL。

综上,一般情况下,使用strncpy时,建议将n置为dest串长度(除非你将多个src串都复制到dest数组,并且从dest尾部反向操作),复制完毕后,为保险起见,将dest串最后一字符置NULL,避免发生在第2)种情况下的输出乱码问题。当然喽,无论是strcpy还是strncpy,保证dest串容量(能容纳下src串)才是最重要的。

区别

strcpy只是复制字符串,但不限制复制的数量,很容易造成缓冲溢出。strncpy要安全一些。
strncpy能够选择一段字符输出,strcpy则不能。例如:

char name[]="Chinanet",dest[20]={0};
strncpy(dest,name,9);
printf("%s\n",dest);
strncpy可实现strcpy的字符串复制:
char name[]="Chinanet",dest[20]={0};
strncpy(dest,name,sizeof(name));
printf("%s\n",dest);

strcat & strncat

strcat

char *strcat(char *dest, const char *src);
连接字符串 src 到字符串 dest 的末尾。

  • 原型:extern char *strcat(char *dest, const char *src);
  • 头文件:在C中,函数原型存在 <string.h>头文件中。在C++中,则存在于<cstring>头文件中。
  • 功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)。
  • 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
    返回指向dest的指针。

strncat

strncat(char *dest, const char *src, size_t n); src所指字符串的前n个字符添加到dest所指字符串的结尾处,并覆盖dest所指字符串结尾的’\0’

  • 原型 char * strncat(char *dest, const char *src, size_t n);
  • 头文件: #include <string.h>
  • 说明:src和dest所指内存区域不可以重叠,并且dest必须有足够的空间来容纳src的字符串。
  • demo code
    #include<stdio.h>
    #include<string.h>
    int main(void)
    {
      char dest[20] = "Hello";
      char src[10] = "World";
      strncat(dest, src, sizeof(dest));
      printf("%s\n", dest);
      return  0;
    }
    【运行结果】:HelloWorld
    
  • 说明
    strncat()将会从字符串src的开头拷贝n 个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串。如果n大于字符串src的长度,那么仅将src指向的字符串内容追加到dest的尾部。
    strncat()会将dest字符串最后的’\0’覆盖掉,字符追加完成后,再追加’\0’。

sprintf & snprintf

sprintf

int sprintf( char *buffer, const char *format, [ argument] … );
把格式化的数据写入某个字符串缓冲区。

sprintf指的是字符串格式化命令,主要功能是把格式化的数据写入某个字符串中。sprintf 是个变参函数。使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。

snprintf

snprintf(char *str, size_t size, const char *format, …);
将可变个参数(…)按照format格式化成字符串,然后将其复制到str中

  • 原型:int snprintf(char *str, size_t size, const char *format, ...);
  • 头文件:#include <stdio.h>
  • 功能:
    • (1) 如果格式化后的字符串长度 < size,则将此字符串全部复制到str中,并给其后添加一个字符串结束符(‘\0’);
    • (2) 如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符(‘\0’),返回值为欲写入的字符串长度。
  • 函数返回值:若成功则返回欲写入的字符串长度,若出错则返回负值。
  • 与snprintf的返回值不同,sprintf的返回值是成功写入的字符串长度,此处需要谨慎处理!

  • demo code
#include<stdio.h>
#include<stdlib.h>
int main()
{ 
  char str[10]={0};
  int nLen=snprintf(str,sizeof(str),"0123456789012345678");
  printf("str=%s\n",str);
  printf("nLen=%d\n",nLen);
  return0;
}

运行结果:
str=012345678
nLen=19


strchr & strstr

strchr

strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。

  • 原型:char *strchr(const char* _Str,char _Val)
  • 头文件:#include <string.h>
  • 功能:查找字符串_Str中首次出现字符_Val的位置
  • 说明:返回首次出现_Val的位置的指针,返回的地址是被查找字符串指针开始的第一个与Val相同字符的指针,如果Str中不存在Val则返回NULL。
  • 返回值:成功则返回要查找字符第一次出现的位置,失败返回NULL

函数实现

char* strchr(char *s, char c)
{
    while(*s != '\0' && *s != c)
    {
        ++s;
    }
    return *s==c ? s : NULL;
}

strstr

strstr(s1, s2);
函数用于判断字符串s2是否是s1的子串。如果是,则该函数返回s2在s1中首次出现的地址;否则,返回NULL。

  • 原型:extern char *strstr(char *str1, const char *str2);
  • 头文件:string.h

函数实现
Copyright 1986 - 1999 IAR Systems. All rights reserved

char *strstr(constchar*s1,constchar*s2)
{
    int n;
    if(*s2)
    {
        while(*s1)
        {
            for(n=0;*(s1+n)==*(s2+n);n++)
            {
                if(!*(s2+n+1))
                    return(char*)s1;
            }
            s1++;
        }
        return NULL;
    }
    else
        return (char*)s1;
}

GCC-4.8.0

char *strstr(const char *s1,const char *s2)
{
    const char *p=s1;
    const size_tlen=strlen(s2);
    for(;(p=strchr(p,*s2))!=0;p++)
    {
        if(strncmp(p,s2,size_tlen)==0)
            return (char*)p;
    }
    return(0);
}

常用经典实现方法

char *strstr(const char *str1, const char *str2)
{
    char *cp = (char*)str1;
    char *s1, *s2;

    if (!*str2)
        return((char *)str1);

    while (*cp)
    {
        s1 = cp;
        s2 = (char *)str2;

        while (*s1 && *s2 && !(*s1 - *s2))
            s1++, s2++;

        if (!*s2)
            return(cp);

        cp++;
    }
    return(NULL);
}

strcmp

strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。

  • 原型:extern int strcmp(const char *s1,const char *s2);
  • 头文件:string.h
  • 功能:C/C++函数,比较两个字符串设这两个字符串为str1,str2,strcmp(str1, str2);
    • 若str1==str2,则返回零;
    • 若str1<str2,则返回负数;
    • 若str1>str2,则返回正数。

strcmp()函数用于比较两个字符串,它锁存在的其中一个问题是:当两个字符串相等时函数的返还值为零。当字符串比较是条件语句的一部分是,这个问题就会导致令人费解的代码:

if(!strcmp(s,"volatile"))
    return QUALIFIER;

返回值为零使条件语句的结果为假,所以我们不得不对其取反,得到我们需要的结果。
这里有个更好的方法。建立宏定义:

#define STRCMP(a, R, b) (strcmp(a, b) R 0)
if(STRCMP(s, ==, "volatile"))

展开为if(strcmp(s,"volatile") == 0)
使用这个宏定义,代码可以用更自然的风格来表示它的意思。


strlen

strlen(s1);
返回字符串 s1 的长度(不包括’\0’在内)。

  • 原型:extern unsigned int strlen(char *s);
  • 头文件:<string.h>
  • 功能:计算给定字符串的(unsigned int型)长度,不包括’\0’在内.
  • 说明:返回s的长度,不包括结束符NULL。

与sizeof的区别

strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个’\0’,如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到’\0’停止。而sizeof()返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个取字节运算符,strlen是函数。strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。

我们能常在用到 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



上一篇 C 数据类型

Comments

Content