字符串是由数字、字母、下划线组成的一串字符。一般记为 s=“a1a2···an”(n>=0)。它是编程语言中表示文本的数据类型。在程序设计中,字符串(string)为符号或数值的一个连续序列,如符号串(一串字符)或二进制数字串(一串二进制数字)。

1、简介

C语言中没有字符串这种变量类型,要表示一个字符串一般采用字符数组或是字符指针。一个字符串以 ‘\0’ 结束。注意在用字符去初始化字符数组时字符数组的最后一个字符要用 ‘\0’ 结束,否则在使用时会出错。用字符串初始化则系统会自动在末尾加上 ‘\0’ 。

char str1[] = {'h','e','l','l','o'};
char str2[] = "world";
char *str3  = "SUST";

2、相关函数

(1)字符串比较

int strcmp(const char* str1,const char* str2);

从头依次比较字符串str1和str2的每个字符,若大于则返回大于0的值,若小于则返回小于0的值,若相等则继续比较,若全部相等则返回0;实现如下:

int Strcmp(const char *s1, const char *s2){  
    assert(NULL !=s1 && NULL != s2);  
    while(*s1 != '\0' && *s2 != '\0' && *s1==*s2){  
        s1++;  
        s2++;  
    }  
    return *s1 - *s2;  
}

举例如下:

#include <stdio.h>

int main()
{
    char *s1 = "hello";
    char *s2 = "world";
    char *s3 = "abcde";
    char *s4 = "hello";

    printf("%d\n",strcmp(s1,s2));
    printf("%d\n",strcmp(s1,s3));
    printf("%d\n",strcmp(s1,s4));
    return 0;
}

如果不是对整个字符串进行比较而只是比较指定数目的字符串,可以使用函数:

int strncmp(const char *s1, const char *s2, size_t n);

用法和返回值都和strcmp类似,之比较给定字符串的前n个字符,或者到遇到任一字符串结尾。实现如下:

int Strncmp(const char *s1, const char *s2, size_t n){   
    assert(NULL!=s1 && NULL!=s2);  
    if(n == 0)  
        return 0;  
    size_t cnt = 1;  
    while(*s1 != '\0' && *s2 != '\0' && *s1==*s2 && cnt < n){  
        s1++;  
        s2++;  
        cnt++;  
    }  
    return *s1 - *s2;  
}

(2)字符串查找

最简单的是查找字符串查找字符:

char *strchr(const char *s, int c);

至于参数为什么是int,历史遗留问题,这里不多讨论。函数返回在s中找到的第一个c的位置的指针,注意的是,字符串末尾的‘\0’也是可以被查找的。实现如下:

char *Strchr(const char *s, int n){  
    assert(s != NULL);  
    char c = (char)n;  
    do{  
        if(*s == c)  
            return (char *)s;  
    }while(*s++);  
    return NULL;  
}

还有查找字符串的函数strstr:

char *strstr(const char *s1, const char *s2);

函数返回s2在s1中出现的首字符的位置,实现如下:

char *Strstr(const char *s1, const char *s2){  
    assert(NULL!=s1 && NULL!=s2);  
    size_t len = strlen(s2);  
    while(*s1){  
        if(!strncmp(s1,s2,len))  
            return (char *)s1;  
        s1++;  
    }  
    return NULL;  
}

(3)字符串复制

最常见的字符串复制函数是strcpy:

char *strcpy(char *dst, const char *src);

把src所指的由NULL结尾的字符串复制到由dst所指的字符串中,src和dst不可以相同(可以由c99的restrict关键字声明),dst必有足够的空间存放复制的字符串。还有一点要注意的是函数返回值,返回值是指向dst的指针,这样做的目的是方便程序中语句内联,比如strlen(strcpy(s,t))。
函数的实现如下:

char *Strcpy(char *dst, const char *src){  
    assert(NULL!=dst && NULL!=src);  
    char *p = dst;  
    while((*dst++ = *src++) != '\0');  
    return p;  
}

使用strcpy需要注意的是要保证dst所指的空间足够拷贝src所指的字符串大小,否则会造成溢出。所以,在大多数情况下都是用strncpy会更加保险,实现如下:

char *Strncpy(char *dst, const char *src, size_t n){  
    assert(NULL!=dst && NULL!=src);  
    char *p = dst;  
    while(n){  
        if((*dst++ = *src++) == '\0')  
            break;  
        n--;  
    }  
    return p;  
}

需要注意另外一个函数strdup:

char strdup(const char );

该函数和strcpy的不同是,函数会自己申请内存空间存放拷贝的字符串,然后返回指向该字符串的指针。所以在使用strdup函数时需要注意的是,在使用完复制的字符串后使用free函数释放其占用的空间。

(4)字符串连接

字符串连接是把一个字符串的头连接到另一个字符串的结尾。

char *strcat(char *s1, const char *s2);

函数的实现如下:

char *Strcat(char *s1, const char *s2){  
    assert(NULL!=s1 && NULL!=s2);  
    char *p =s1;  
    while(*s1)s1++;  
    strcpy(s1,s2);  
    return p;  
}

同样,strcat也是不安全的,因为也对缓冲区足够存放连接的字串进行了假设。所以,多数情况下我们应该使用更安全的:

char *strncat(char *s1, const char *s2, size_t n);