C和指针读书笔记(第九章)

1. 字符串以字符串常量的形式存储与字符数组中。字符串以NUL字节结尾,但NUL不是字符串的一部分,所以字符串的长度不包括NUL字节,局势它所包含的字符个数。头文件string.h包含了使用字符串函数的原型和声明。


2. 计算字符串参数的长度

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

size_t strlen(char const *string);
int main()
{
    int i;
    /*******读入字符串,存入字符数组*******/
    char str[] = "http://www.baidu.com";    //20
    printf("%s\n", str);
    puts(str);
    int num = strlen(str);
    printf("%d\n", num);
    return 0;
}
size_t strlen(char const *string)   //计数函数
{
    int len;

    for(len = 0; *string++ != '\0'; ){
        len += 1;
    }

    return len;
}

3. 复制字符串
函数:strcpy()
原型:

char +strcpy(char *dst, char *src);  //把src字符串复制到dst字符串

复制后,目标参数以前的内容将被覆盖而丢失。即使新的字符串比dst原先的字符串更短,由于新字符串是以NUL结尾,所以老字符串多出来的最后几个字符也会被删除。
如果字符串比数组长,多余的字符仍被复制并且覆盖原先存储数组后弥漫的内存空间的值。(strcpy无法解决这个问题,因为它无法判断目标字符数组的长度)


4. 连接字符串
函数:strcat()
原型:

//函数要求dst参数原先就包含了一个字符串(可以为空)
char *strcat(char *dst, char const *src);  //把src拷贝添加到dst的末尾部分

5. 函数的返回值
strcpy和strcat都返回第一个参数的一份拷贝,也就是一个指向指向目标字符串的一个指针。故可以嵌套的调用这些函数。

strcat(strcpy(dst, a), b);
//strcpy先执行,把字符串从a复制到dst并返回dst
//strcpy的返回值成为了strcat的第一个参数,strcat把b添加到dst的后面

6. 字符串比较
比较两个字符串是对两个字符串对应的字符进行逐个比较,直到发现不匹配为止,最先不匹配的字符中比较小(字符集中的序数小)的字符会被认为小于另一个字符串,如果一个字符串是另一个的一部分,也被认为比较小。
函数:strcmp()
原型:

int strcmp(char const *s1, char const *s2);
//s1小于s2,返回一个小于0的值
//s1大于s2,返回一个大于0的值
//s1等于s2,返回0

7. 长度受限的字符串函数

  • strncat()函数
    strncat就是把src中的最多len个字符复制到目标数组的后面,但是,strncat总是在结果的字符加一个NUL字节。
char *strncat(char *dest,const char *src,size_t len);
  • strncpy()函数
    strncpy把源字符串的字符复制到目标数组,strncpy()会将字符串src前n个字符拷贝到字符串dest。
    不像strcpy(),strncpy()不会向dest追加结束标记’\0’。
    它总是正好向dest写入len个字符,如果strlen(src)值小于len,dest数组就用额外的NUL字节填充到len长度。如果stelen(src)的值大于或者等于len,那么只有len个字符被复制到dest中。注意:它的结果将不会以NUL字节结尾。
    可以通过指定最后一个字符为’\0’的方式来限制以NUL结尾。
char buffer[n];
strncpy(buffer, name, n);
buffer[n - 1] = '\0'; //指定最后一个字节
  • strncmp()函数
int strncmp(char const *str1, charconst *str2,size_t len);

strcmp函数用来比较两个字符串,但它比较len个字节,如果两个字符串在第len个字符之前存在不相等的字符,也就是说,如果字符串s1与s2的前size个字符相同,函数返回值为0


8. 字符串查找基础

  • 查找一个字符串
    strchr()函数和strrchr()函数(区分大小写)
char *strchr(char const *str, int ch);  //查找字符ch第一次出现的位置
char *strrchr(char const *str, int ch);  //查找字符ch最后一次出现的位置
  • 查找任何几个字符串
    strpbrk()函数(区分大小写)
//查找一组字符第一次在字符串中出现的位置
//返回一个指向str中第一个匹配group中任何一个字符的字符位置
//未找到匹配就返回NULL指针
char *strpbrk(char const *str, char const *group);
  • 查找一个子串
    strstr()函数
//在s1中查找整个s2第1次出现的起始位置,并返回一个指向该位置的指针
//如果s2没有完整的出现在s1的任何地方,函数将返回一个NULL指针
//如果s2是一个空字符串,函数就返回s1
char strstr(chsr const *s1, char const *s2);

自行编写strrstr()函数:查找子串最后一次出现的位置

#include<stdio.h>

char *my_strrstr(char const *s1, char const *s2);
int main(void)
{
    char s1[30] = "I love You, lover, forever.";
    char s2[5] = "ve";
    char *la = NULL;
    la = my_strrstr(s1, s2);
    printf("%c, %c, %c, %c", *(la - 1), *la, *(la + 1), *(la+2));
    return 0;
}

/**在字符串s1中查找字符串s2最右出现的位置,并返回一个指向该位置的指针**/
char *my_strrstr(char const *s1, char const *s2)
{
    //把指针初始化为我们已经找到的前一次匹配的位置
    register char *last;
    register char *current;

    //只在第2个字符串不为空时才进行查找,如果s2为空,返回NULL
    last = NULL;
    if(*s2 != '\0'){
        //查找s2在s1中第1次出现的位置
        current = strstr(s1, s2);
        //每次找到字符串时,让指针指向它的起始位置,然后查找该字符串的下一个匹配位置
        while(current != NULL){
            last = current;
            current =strstr(last + 1, s2);
        }
    }
    return last;
}

9. 高级字符串查找

  • 查找一个字符串前缀
    strspn()函数和strcspn()函数

strspn()函数用来计算字符串 str中连续有几个字符都属于字符串 group(区分大小写)

strspn()从参数str字符串的开头计算连续的字符,而这些字符都完全是group所指字符串中的字符。简单的说,若strspn()返回的数值为n,则代表字符串str开头连续有n个字符都是属于字符串group内的字符。

返回字符串str开头连续包含字符串group内的字符数目。所以如果 str 所包含的字符都属于group,那么返回str的长度;如果str的第一个字符不属于group,那么返回 0。

strcspn()函数和strspn()函数正好相反,它对str字符串起始部分中不与group中任何字符匹配的字符进行匹配

size_t strspn(char const *str, char const *group);
size_t strcspn(char const *str, char const *group);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ()
{
    int i, j, m, n;
    char str[] = "Linux was first developed for 386/486-based pcs.";
    char group[] = "1234567890";
    i = strspn(str, group);
    j = strcspn(str, group);
    //换页符:\f, 换行符:\n, 回车符:\r, Tab符:\t, 垂直Tab符:\v
    m = strspn(str, "\n\r\f\t\v");  
    n = strcspn(str, "\n\r\f\t\v");
    printf("str 前 %d 个字符都属于 group\n",i);  //0
    printf("str 前 %d 个字符都不属于 group\n",j);  //30
    printf("str 中第一个指向非空白字符的指针:%d\n",m);  //0
    printf("str 中第一个参数字符串起始部分所有非空白字符的值:%d\n",n);  //48

    return 0;
}
  • 查找标记
    strtok()函数
    strtok()函数执行时会修改它所处理的字符串,若源字符串不允许修改,那就复制一份,并将拷贝传给strtok()函数。
//从字符串中隔离各个单独称为标记的部分,并丢弃分隔符
char *strtok(char *str, char const *sep);
//sep是字符串,定义了用作分隔符的字符集合
//第一个参数指定一个字符串,包含零个或多个由sep字符串中一个或多个分隔符分隔的标记
//strtok()找到str的下一个标记,将其用NULL代替并返回一个指向这个标记的指针

strtok()函数的第一个参数不是NULL,函数将找到字符串的第1个标记。strtok()同时将保存它在字符串中的位置。若第一个参数是NULL,函数就在同一个字符串中从这个被保存的位置开始向前面一样查找下一个标记。如果字符串内不存在更多标记,strtok()函数就返回NULL指针。
典型情况下,第一次调用strtok()函数时,给它传递一个指向字符串的指针,谭厚这个程序被循环调用,直到返回NULL为止。
strtok()函数保存它所处理的函数的局部状态信息,所以无法用它同时解析两个字符串。

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

void print_token(char *line);
int main(void)
{
    char s[] = "Happy Ending Never say never ";
    print_token(s);
    return 0;
}

void print_token(char *line)
{
    static char white[] = " \t\f\r\v\n";  
    //此处\t前必须有空格,如无空格将无法识别
    char *token;
    for(token = strtok(line, white);
    //第一个参数不是NULL,函数将找到字符串的第1个标记
        token != NULL;
        token =  strtok(NULL, white))
        //第一个参数是NULL,函数就在同一个字符串中从这个被保存的位置开始向前面一样查找下一个标记
        printf("下一个标记是: %s\n", token);

}

10. 字符操作

  • 字符分类
    每个分类函数接收一个包含字符值的整形参数,函数测试这个字符并返回一个整型值,表示真或假。以下是字符分类函数的表格。
    字符分类函数
    直接测试会降低程序的可移植性(以下两个程序功能相同,但程序二移植性更好)
//测试ch是否为大写字符
//1
if(ch >= 'A' && ch <= 'Z')
//2
if(isupper(ch))
  • 字符转换
    大小写字母互相转换
int tolower(int ch);  //返回小写形式
int toupper(int ch);  //返回大写形式

11. 计算字符串长度
strlen()函数

size_t strlen(char const *string);
//size_t是一个无符号整数,用于表达式可能会出现不可预知的结果
//如果把strlen的返回值强制转换为int,就可以消除这个问题

12. memxxx函数提供了类似字符串函数的功能,但它们可以处理包括NUL字节在内的任意字节。这些函数都接受一个长度参数。P185

void *memcpy(void *dst, void const *src, size_t length);

memcpy从源参数向目标复制由长度参数指定的字节数。从src的起始位置复制length个字节到dst的内存起始位置。

void *memmove(void *dst, void const *src, zise_t length);

memmove函数执行相同的功能,但它能够正确处理源参数和目标参数出现重叠的情况。memmove把源操作数复制到一个临时的位置,这个位置不会与源或目标操作数重叠,接着再把操作数从临时位置复制到目标操作数。

void *memcmp(void const *a, void const *b, size_t length);

memcmp函数比较两个序列的字节。共比较length的字节,这些值按照无符号逐字节进行比较,函数的额返回类型为:小于返回负数,等于返回0,大于返回正数。

void *memchr(void const *a, int ch, size_t length);

memchr函数在一个字节序列中查找一个特定的值,从字符串起始位置查找字符ch第1次出现的位置,并返回指向该位置的指针,它共查找length个字节,如果在这length个字节中没有找到该字符,函数就返回NULL指针。

void *memset(void *a, int ch, size_t length);

memset函数把一序列字节初始化为一个特定的值,把字符串从开始的length个字节都设置为字符值ch。


2016.10.8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值