C语言|《C Primer Plus》|字符、字符串、字符函数和字符串函数

C双引号代表字符串;字符串存储在char类型的数组中。

C语言中,字符串用空字符(null character)\0标识字符串结束;故数组容量 = 字符串字符数 + 1;

#1 字符串数组

定义:

char 字符串名[常量] = 

%s打印。

#2 字符串和字符

“x”和‘x’是不同的:

  1. “x”是派生类型(char数组);‘x’是基本类型(char)
  2. “x”由‘x’和\0组成

#3 字符串相关函数

#3.1 strlen()函数

        所需头文件string.h;返回值是size_t类型(无符号整型),用%zd(C99 C11)或%u %lu打印返回值;从字符串第一个字符开始数,数到\0结束,\0不算计数范围内。

        对于size_t类型有些需要注意的点:

int main()
{
    if(strlen("abc")-strlen("abcdef") > 0)
    {
        printf(">\n");
    }
    else
    {
        printf("<=\n");
    }
    return 0;
}

        最终打印出来的结果是>,因为strlen返回值是无符号整型,3-6得到一个很大的正数,因此是>;

        可以进行如下修改:

if(strlen("abc") > strlen("abcdef"))
if(int(strlen("abc")-strlen("abcdef")) > 0)

#3.2 strcmp()函数

       所需头文件string.h;用于比较两个字符串;若字符串相同,则返回0;

        模拟实现一个strcmp:

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 && str2);
    while(*str1==*str2)
    {
        if(*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return (*str1 - *str2);
}

        注:两个字符串比较不能用==

int main()
{
    char arr1[20] = "zhangsan";
    char arr2[] = "zhansan";

    if(arr1 == arr2)  // 比较的是arr1和arr2的地址(数组名)
        printf("==\n");
    else
        printf("!=\n");  // 永远只打印这个

    return 0;
}

#3.3 strcpy()函数

        所需头文件string.h;用于将第二个字符串复制到第一个字符串当中(\0也会被复制过去);

        要保证源数据有'\0';目标空间必须能够容纳源数据;目标空间必须是可修改的;当目标空间不够时,代码仍然能运行,因此其不是很安全;

int main()
{
    char* p = "abcdef";
    char arr[] = "bit";
    strcpy(p, arr); // error,目标空间不可修改

    return 0;
}

        模拟实现strcpy():

char* my_strcpy(char* dest, const char* src)
{
    assert(dest && src);
    char* ret = dest;
    while(*dest++ = *src++); // 当src='\0'时,执行完*dest++ = *src++后得到'\0',也即0或者说逻辑假,跳出while循环
    return ret;
}

        使用示例:

int main()
{
    char arr1[20] = "abcdef";
    char arr2[] = "hello bit";

    strncpy(arr1, arr2, 5);
    printf("%s\n", arr1);  // hellof

    return 0;
}

#3.4 strncpy()函数

        函数申明:

char* strncpy(char* desination, const char* source, size_t num); // num表示要拷贝的字符数

#3.5 strcat()函数

        字符串追加,将源字符串添加到目标空间;目标空间必须能够容纳源数据;目标空间必须是可修改的;不能自己给自己追加;

        模拟实现strcat():

char* my_strcat(char* destination, const char* source)
{
    assert(destination && source);
    char* ret = destination;
    # 找到目标字符串的'\0'
    while(*destination != '\0')
    {
        destination++;
    }
    # 赋值源字符串到目标字符串
    while(*destination++ = *source++);
    
    return ret;
}

#3.6 strncat()函数

        比strcat()函数多了一个参数num,表示追加num个字符;在目标空间的第一个'\0'处开始追加(覆盖掉这个'\0');会自动在追加完成的字符串后面添加'\0';

#3.7 strstr()函数

        使用示例:

int main()
{
    char email[] = "zpw@bitejiuyeke.com";
    char substr[] = "bitejiuyeke";
    char* ret = strstr(email, substr);
    if(ret == NULL)
        printf("字串不存在");
    else    
        printf("%s\n", ret);
    return 0;
}

        模拟实现(效率不够高):

char* my_strstr(const char* str1, const char* str2)
{
    assert(str1 && str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;

    while(*p)
    {
        s1 = p;
        s2 =str2;
        while(*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
        {
            s1++;
            s2++;
        }
        if(*s2 == '\0')
            return (char*)p;
        p++;
    }
    return NULL;
}

#3.8 strtok()函数

        用于切割字符串;找到标记位后将其替换为'\0';strtok函数会改变源字符串,如果不想改变源字符串,需要先做好备份;

        函数声明:

char* strtok(char* str, const char* sep);

        strtok函数第一个参数不为NULL时,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置,并将该标记替换为'\0';

        strtok函数第一个参数为NULL('\0')时,函数将在同一个字符串中被保存的位置开始,查找下一个标记;

        如果字符串不存在更多的标记,则返回NULL指针;

        使用示例:

int main()
{
    const char* sep = "@.";
    char email[] = "zhangpengwei@bitejiuyeke.com";
    char copy[30] = {0};
    strcpy(cp, email);

    char* ret = strtok(cp, sep);
    printf("%s\n", ret);  // zhangpengwei
    char* ret = strtok(NULL, sep);
    printf("%s\n", ret);  // bitejiuyeke 
    char* ret = strtok(NULL, sep);
    printf("%s\n", ret);  // com
    char* ret = strtok(NULL, sep);
    printf("%s\n", ret);  // (null)

    return 0;
}

        当我们事先不知道字符串需要调用几次strtok才能全部切割完时,我们就需要进行判断,如下:

int main()
{
    const char* sep = "@.";
    char email[] = "zhangpengwei@bitejiuyeke.com";
    char copy[30] = {0};
    strcpy(cp, email);

    char* ret = NULL;
    for(ret=strtok(cp, sep); ret!=NULL; ret = strtok(NULL, sep))
    {
        printf("%s\n", ret);
    }

    return 0;
}

#3.9 strerror()函数

        返回错误码(C语言的库函数在执行失败时,都会设置错误码)所对应的错误信息;

        errno是C语言设置的一个全局的错误码存放的变量(需要包含<errno.h>);

         使用示例:

#include <errno.h>
#include <string.h>
#include <stdio.h>

int main()
{
    //printf("%s\n", strerror(0)); 
    //printf("%s\n", strerror(1));
    //printf("%s\n", strerror(2));
    //printf("%s\n", strerror(3));
    //printf("%s\n", strerror(4));

    FILE* pf = fopen("test.txt", "r");
    if(pf == NULL)
    {
        printf("%s\n", strerror(errno);
        return 1;
    }
    else
    {
    
    }

    return 0;
}

#3.10 memcpy()函数

        从内存中拷贝,可以拷贝任意类型的数据;只能拷贝两块独立空间中的数据(要处理重叠的内存间数据拷贝的情况,使用memmove函数);

        函数声明:

void* memcpy(void* destination, const void* source, size_t num);  //num是要传递的字节总数

        模拟实现memcpy():

void* my_memcpy(void* dest, const void* src, size_t num)
{
    assert(dest && src);
    void* ret = dest;

    while(num--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest+1;  // dest如果没有强制转为char*,就不能加1,void*类型的指针不能+-
        src = (char*)src+1;
    }
    return ret;
}

#3.11 memmove()函数

void* my_memmove(void* dest, const void* src, size_t num)
{
    // 以下两种情况是重叠时的,不重叠的话怎么考都可以
    // 目标地址dest比源地址src大(高位)时,从后向前实现比较容易
    // 目标地址dest比源地址src小(低位)时,从前向后实现比较容易
    assert(dest && src);
    void* ret = dest;

    if(dest<src)  // 第二种情况
    {
        // 从前向后
        while(num--)
        {
            *(char*)dest = *(char*)src;
            dest = (char*)dest+1;
            src = (char*)src+1;
        }
    }
    else
    {
        // 从后向前
        while(num--)
        {
           *((char*)dest+num) = *((char*)src+num);
        }
    }
    return dest;
}

#3.13 memcmp()函数

int memcmp(const void* ptr1, const void* ptr2, size_t num);  // 一个字节一个字节地比较

#3.14 memset()函数

void* memset(void* ptr, int value, size_t num);  // 一个字节一个字节设置

#4 字符判断和处理函数

        ctype.h头文件中,包含处理字符的函数。

#5 总结

1. C语言字符串存储在char类型数组中,由“字符串内容+\0“”组成,因此数组长度至少要比字符串内容多1;

2. 打印字符串用%s

3. 字符串用双引号,字符用单引号

4. 计算字符串长度的函数:strlen();比较两个字符串是否相同的函数:strcmp();复制一个字符串到另一个字符串中的函数:strcpy();这三个函数都需要string.h头文件

5. ctype.h头文件中有处理字符的函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值