C——常用字符串函数、内存操作函数总结

《C和指针》第九章讲到了:字符串、字符和字节。学习之后,现把这一章的一些知识点提炼、总结。

===========================================
回顾一下字符串基础知识:字符串就是由零个或多个字符构成,结尾以’\0’作为终止标志的一种数据类型。
但是在我们的C语言中,没有像int、float这样,有一个显式的数据类型。因为字符串以一个字符串常量形式表示,或者存储在一个字符数组中。
存储方式除了字符串常量是放在文字常量区(.rodata)外,其他的可存在字符数组或是动态分配的内存中。


8.12日补充:
关于内存重叠的学习:http://blog.csdn.net/feitianxuxue/article/details/7195158


如下两句代码:
char *str = "hello,wrold";    /*"hello,wrold"内容不可修改因为在文字常量区*/
char arr[] = "nihao,xiexie";/*"nihao,xiexie"的内容可以修改因为是在栈中分配了空间*/
例(摘自《C和指针》):
/*
**用动态分配内存制作一个字符串的一份拷贝。
*/

char *strdup(char const *string)
{
    char *new_string;

    /*请求足够长度的内存,用于存储字符串和'\0'*/
    new_string = malloc(strlen(string) + 1);

    /*如果得到内存,就复制字符串*/
    if(new_string != NULL)
        strcpy(new_string, string);

    return new_string;
}

一、字符串长度

字符串的长度就是它包含的字符个数。
库函数strlen原形如下:
size_t strlen(const char *string);
在Linux(3.0内核)中string.c中实现如下:

size_t strlen(const char *s)
{
     const char *sc;

     for (sc = s; *sc != '\0'; ++sc)
         /* nothing */;
     return sc - s;
 }

值得注意的是,它返回的是size_t类型,size_t是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。

二、字符串函数

1.复制字符串strcpy:
用于复制字符串的函数是strcpy,原型:
char *strcpy(char *dest, const char *src)

在Linux(3.0内核)中string.c中实现如下:

 char *strcpy(char *dest, const char *src)
 {
     char *tmp = dest;

     while ((*dest++ = *src++) != '\0')
         /* nothing */;
     return tmp;
 }

(1)功能是把参数src字符串复制到dest参数。dest里的内容将会被新串覆盖并且丢失。
(2)这个会有可能src和dest在内存中出现重叠。
(3)dest是要被修改的,所以它必须是个字符数组或者是一个指向动态分配内存的数组指针,不能是字符串常量。
(4)返回值是第一个参数的一份拷贝,是指向目标字符数组的指针。这个函数就可以嵌套的调用,也就是说可以作为别的函数的参数来使用。

2.复制字符串strncpy:
strncpy原型:
char *strncpy(char *dest, const char *src, size_t count)

在Linux(3.0内核)中string.c中实现如下:

char *strncpy(char *dest, const char *src, size_t count)
{
    char *tmp = dest;

    while (count) {
        if ((*tmp = *src) != 0)
            src++;
        tmp++;
        count--;
    }
    return dest;
}

较之strcpy,这个函数接受一个显示的参数count,用于限定复制的字符数,这是更安全的机制。
(1)同样是把src字符串复制到dest,但是它规定了向dest写入count个字符。
(2)如果源src的字符个数小于给定的count,那么在dest里会用额外的’\0’填充到count。
(3)如果源src的值大于count,那么只会有count个字符被复制到dest中。
它的结果将不会以’\0’结尾。

3.连接字符串strcat:
原型:
char *strcat(char *dest, const char *src)

在Linux(3.0内核)中string.c中实现如下:

char *strcat(char *dest, const char *src)
{
    char *tmp = dest;

    while (*dest)
        dest++;
    while ((*dest++ = *src++) != '\0')
        ;
    return tmp;
}

(1)功能是把一个字符串连接到另一个字符串的后面。
(2)要注意dest的剩余空间要足够保存整个的src字符串。

4.连接字符串strncat:
原型:
char *strncat(char *dest, const char *src, size_t count)

在Linux(3.0内核)中string.c中实现如下:

char *strncat(char *dest, const char *src, size_t count)
{
    char *tmp = dest;

    if (count) {
        while (*dest)
            dest++;
        while ((*dest++ = *src++) != 0) {
            if (--count == 0) {
                *dest = '\0';
                break;
            }
        }
    }
    return tmp;
}

(1)从src中最多复制count个字符到dest后面,并且总在新生成的字符串后面添加一个’\0’。

5.字符串查找strstr
原型:
char *strstr(const char *s1, const char *s2)

在Linux(3.0内核)中string.c中实现如下:

char *strstr(const char *s1, const char *s2)
{
    size_t l1, l2;

    l2 = strlen(s2);
    if (!l2)
        return (char *)s1;
    l1 = strlen(s1);
    while (l1 >= l2) {
        l1--;
        if (!memcmp(s1, s2, l2))
            return (char *)s1;
        s1++;
    }
    return NULL;
}

(1)在某一个字符串中查找一个字串,该函数在s1查找整个s2第一次出现的位置,返回一个指向该位置的指针。
(2)若s2没有完整出现在s1,则返回一个NULL指针。
(3)若第二个参数是空字符串,函数就返回s1。

strstr的另一种实现方法:

char *my_strstr(const char *find, const char *need)
{
    assert(find !=NULL && need !=NULL);

    while( *find !='\0')
    {
        const char *p = find;
        const char *q = need;
        const char *res;

        if(*p == *q)
        {
            res= p;
            while(*p++ == *q++)
                ;
            if(*q == '\0')
            return (char *)res;
        }
        find ++;
    }
    return NULL;
}

二、内存操作函数

内存操作函数可以处理任意的字节序列。
memcpy:

void *memcpy(void *dest, const void *src, size_t count)
{
    char *tmp = dest;
    const char *s = src;

    while (count--)
        *tmp++ = *s++;
    return dest;
}

该函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
可以看到参数类型是void* 指针,而任何类型的指针都可以转换为void* 类型。所以前两个参数在使用时不需要强制类型转换。

memmove:

void *memmove(void *dest, const void *src, size_t count)
{
    char *tmp;
    const char *s;

    if (dest <= src) {
        tmp = dest;
        s = src;
        while (count--)
            *tmp++ = *s++;
    } else {
        tmp = dest;
        tmp += count;
        s = src;
        s += count;
        while (count--)
            *--tmp = *--s;
    }
    return dest;
}

memmove的行为和memcpy差不多,但是它的src和dest可以重叠。
具体区别可以查看这一篇文章:http://www.linuxidc.com/Linux/2013-06/85344.htm

memset:

 void *memset(void *s, int c, size_t count)
{
    char *xs = s;

    while (count--)
        *xs++ = c;
    return s;
}

memset是把从s开始的count个字节都设置成c。
memset(buffer, 0, SIZE)
把buffer的前SIZE个字节初始化为0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值