9-字符串

140 阅读9分钟

头文件:#include <string>

知识点一:指针保存字符串

#include<stdio.h>
void main()
{
    char* a = "hello111";	//指针变量a 指向 字符串首地址
    printf("%s",a);
}

知识点二:测量字符串长度

返回值为字符串的长度不包含 '\0'

//s:被测量的字符串首元素地址
size_t strlen(const char *s)      //strlen(被测量的字符串首元素地址(一般是数组名))

void test01()
{
    char buf1[128] = "hehehe";
    char buf2[] = "hehehe";
    char buf3[] = "hehe\0he";

    // \123 代表一个字符,\hhh 八进制转义h: 0~7
    //\\表示'\'
    char buf4[]="hehe\123\\he";

    //\\x2f表示一个字符 \xdd 十六进制转义 d:0~9 a~f
    char buf5[]="hehe\x2fhe";


    printf("%d\n",sizeof(buf1));//128
    printf("%d\n",strlen(buf1));//6

    printf("%d\n",sizeof(buf2));//7
    printf("%d\n",strlen(buf2));//6

    printf("%d\n",sizeof(buf3));//8
    printf("%d\n",strlen(buf3));//4

    printf("%d\n",sizeof(buf4));//9
    printf("%d\n",strlen(buf4));//8
    printf("%s\n",buf4);

    printf("%d\n",sizeof(buf5));//8
    printf("%d\n",strlen(buf5));//7

    char buf6[]="\0hehe\0hehe";
    printf("%d\n",strlen(buf6));//0
    return;
}

知识点三:字符串拷贝

1、strcpy

遇到'\0'会结束,只是'\0'也会拷贝过去

//功能:把 src 所指向的字符串 复制 到dest 所指向的空间中
原型:
    char *strcpy(char *dest, const char *src)

//返回值:返回dest字符串的首地址
void test1()
{
    char src[] = {"hello\0string"};
    //保证dst足够大
    char dst[128] = "";
    strcpy(dst,src);
    printf("dst = %s\n",dst); //hello
}

2、strncpy

'\0'不拷贝

//功能:把 src 指向字符串的前 num 个复制到 dest 所指向的空间中
原型:
    char *strncpy( char *dest, const char *src, int num)

//返回值:返回dest字符串的首地址
void test1()
{
    char src[] = {"hello string"};
    //保证dst足够大
    char dst[128] = "";
    strncpy(dst,src,3);
    printf("dst = %s\n",dst);     //"hel"
}

知识点四:字符串拼接

1、strcat

char *strcat(char *dest, const char *src);
//将 src 的字符串拼接到 dst 的末尾(dst第一个'\0'的位置 )
void test1()
{
    char src[] = {"wor\0ld"};
    char dst[128] = "hello";
    strcat(dst, src);
    printf("dst = %s\n", dst);     //hellowor
}

2、strncat

'\0'一起拷贝过去

//功能:将str2前num个字母连接到str1后面
原型:
    char *strncat (char *str1, char *str2, int num)

返回值:返回str1字符串的首地址
void test1()
{
    char src[] = {"world"};
    char dst[128]="hello";
    strncat(dst,src,2);
    printf("dst = %s\n",dst); //hellowo
}

知识点五:字符串比较

1、strcmp

整个字符串的比较

//功能:将s1和s2指向的字符串逐个字符比较
int strcmp(const char *S1,const char *s2);

返回值:
    >0:表示s1 > s2
    <0:表示s1 < s2
    ==0:表示s1 == s2
void test1()
{
    char s1[] = "hehe haha";
    char s2[] = "hehe xixi";
    if(strcmp(s1,s2) > 0)
    {
        printf("s1 > s2\n");
    }
    else if(strcmp(s1,s2) < 0)        //<0
    {
        printf("s1 < s2\n");
    }
    else if(strcmp(s1,s2) == 0)
    {
        printf("s1 == s2\n");
    }
}

2、strncmp

    局部字符串的比较,比较两个字符串的 n 个字节是否一样

void test1()
{
    char s1[] = "hehe haha";
    char s2[] = "hehe xixi";
    if(strncmp(s1,s2,3) > 0)
    {
    	printf("s1 > s2\n");
    }
    else if(strncmp(s1,s2,3) < 0)        
    {
    	printf("s1 < s2\n");
    }
    else if(strncmp(s1,s2,3) == 0)    //== 0
    {
    	printf("s1 == s2\n");
    }
}

知识点六:字符查找函数

//功能:在字符串 str1 中查找字母 ch 出现的位置
原型:
    char* strchr (const char *str1, char ch)

//返回值:返回 第一次 出现的 ch地址,如果找不到,返回NULL
void test1()
{
    char str[] = "www.1000phone.com";
    char *ret = NULL;
    ret = strchr(str,'o');
    if(ret != NULL)
    {
    	*ret = '#';
    }
    printf("str=%s\n",str);	//"www.1000ph#ne.com";
}

知识点七:字符串查找

//从 s1 中查找字符串 s2,返回 第一次 s2 出现的地址
char *strstr(const char *s1,const char *s2); 

//查找失败返回NULL
void test1()
{
    char s1[] = "www.sex.777.sex.com";
    char s2[] = "sex";
    char *ret = NULL;
    ret = strstr(s1,s2);
    if(ret == NULL)
    {
        return;
    }
    printf("%s\n",ret);	//sex.777.sex.com
}

知识点八:替换字符函数

原型: void* memset (void *str, char C, int n)  
功能:将 str 所指向的内存区的 前n个 全部用 c 填充
    常用于清除指定空间,比如 数组 或 malloc 的空间
返回值:返回 str 的地址

知识点九:字符串转化数值

//功能:将 str 所指向的数字字符串转化为 int、long、double
//头文件:
    #include<stdlib.h>
//转int
atoi(需要转的字符串)
    
//转long
atol(需要转的字符串)
    
//转double
atof(需要转的字符串)
void test1()
{
    printf("%d\n", atoi("123"));	//123
    printf("%ld\n", atol("12356"));	//12345
    printf("%f\n", atof("12.3"));	//12.300000
}

知识点十:字符串切割函数

//第一次切割:str必须指向要切割的字符串首元素地址,delim指向要切割的符号
//第2~n次切割: str必须指向NULL  delim指向要切割的符号
    
char *strtok(char *str,const char *delim);

//返回值:切割成功返回切割到字符换片段的首元素地址,失败: NULL
//注意: strtok 不能切割字符串常量

/*
"hehe:haha:xixi:lala"
如果切制完成会产生 "hehe" "haha" "xixi" "lala"
一般选择char *arr[] 指针数组来存放上面独立的字符串的首元素地址
*/
void test1(void)
{
    char buf[] ="hehehe:haha:xixi:lala:heihei:henhen";
    char *arr [32]= {NULL} ;
    int i=0;
    //第1次切割
    arr[i] = strtok(buf,":@#") ;
    //第2~n切割
    while(arr[i] != NULL)	//保证上一次切割正常才有进行下一次切割的必要
    {
        i++ ;
        arr[i] = strtok (NULL,":");
    }
    //遍历切割的内容
    i=0;
    while(arr[i] != NULL)
    {
        printf ("%s\n",arr[i]);
        i++;
    }
}

知识点十一:格式化输出

//str :用来存放组装好的数据
//"格式":组装格式
//数据: 各个零散的数据

int sprintf(char *str, "格式",数据)

返回值:返回值的是组好的报文的实际长度(不包含'\0')
void test1(void)
{
    int year = 2020;
    int mon = 2;
    int day = 24;
    int len = 0;
    //需求:将2020 2 24组 成一个"2020年2月24日"
    char buf[ 128] = "";
    //%d 和 year 类型要一一对应
    len = sprintf (buf, "%d年%d月%d日", year, mon, day);
    printf("len = %d\n",len);
    printf("buf=%s\n", buf);
}

知识点十二:提取格式字符串

从一个字符串中提取字符串,浮点数,整数等值,并将其保存到指定的变量中

sscanf(被提取的字符串,"提取格式",保存的地址,....);

//成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF
void test09()
{
    char buf[] = "2020年2月24日";
    int year = 0;
    int mon = 0;
    int day = 0;
    char ch = 0;
    char str_year[32] = "";
    char str_mon[32] = "";
    char str_day[32] = "";


    //%d 只能提取'0'~'9'
    sscanf(buf,"%d年%d月%d日", &year, &mon, &day );
    printf("year = %d\n", year);	//2020
    printf("mon = %d\n", mon);	//2
    printf("day = %d\n", day);	//24

    //%c 提取一个字符 %f 提取提取浮点数
    sscanf(buf,"%c", &ch);
    printf("##%c##\n",ch);	//'2'

    //%s 提取一个字符串 遇到空格、回车、'\0' 停止获取
    //buf==>"2020年2月24日"
    sscanf(buf,"%s年%s月%s日", str_year, str_mon,str_day );
    printf("str_year=%s\n", str_year);	//"2020年2月24日"
    printf("str_mon=%s\n", str_mon);	//null
    printf("str_day=%s\n", str_day);	//null
}

sscanf高级用法

使用%*s %*d 跳过提取的内容(不要提取的内容)

void test1(void)
{
    int datal = 0;
    //sscanf("1234 5678", "1234 %d", &datal);    //5678
    //sscanf("1234 5678","%*d %d", &datal);    //5678
    sscanf("1234 5678","%*s %d", &datal);    //5678
    printf("datal = %d\n", datal);
}

使用%*ns %*nd提取指定宽度n的字符串或数据 n:需要的字节数

void test1(void)
{
    int datal = 0;
    int data2 = 0;
    char buf[16]="";
    sscanf ("12abc5678","%*5s%d",&datal) ;//5678
    printf("datal=%d\n", datal);
    sscanf ("12345678", "%*2s%2d%*2d%s",&data2,buf);    //data2=34 buf="78";
    printf("data2 = %d\n", data2);    //34
    printf("buf=%s\n",buf);    //"78'
}

%[a-z]提取a-z的字符串

void test1(void)
{
    char buf[128]="";
    //%[]都是按 字符串 提取
    sscanf("abcDefABC", "%[a-z]",buf);
    printf("buf=%s\n",buf);    //"abc"
}

%[aBc] 提取 a B c

void test1(void)
{
    char buf[128]="";
    //%[]都是按 字符串 提取
    sscanf("aaBBcEdef", "%[aBc]",buf);
    printf("buf=%s\n",buf);        //aaBBc
}

%[^abc]提取不是a b c其中一个的字符串

void test1(void)
{
    char buf[128]="";
    //%[]都是按 字符串 提取
    sscanf("ABCcABC", "%[^abc]",buf);
    printf("buf=%s\n",buf);	//ABC
}

知识点十三:const关键字

const修饰 变量 为只读

void test1(void)
{
    //const修饰num为只读变量 num 只能取值 num不能被赋值
    //const 修饰的变量 尽量 初始化
    const int num = 10;
    printf("num = %d\n",num) ;//ok
    //num = 100;	//err num不能被赋值
    
    printf("&num = %p\n",&num);	//0019FED8
    
    //但是如果知道num的地址也可以间接的修改num的值(一般不这么做)
    *(int *)(&num) = 1000;	//少干
    printf("num = %d\n",num);	//结果:num = 1000
}

const * int p

const在*的左边表示const修饰的是*而不是p

用户不能借助*p更改空间的内容,但是p可以指向其他空间(*p只读,p可读可写)

void test1(void)
{
    int num1=10;
    int num2 = 20;
    
    //const在*的左边 *p只读 p可读可写
    const int *p = &num1;
    printf("*p = %d\n",*p);    //10 
    //*p = 1000;    //err *p只读
    
    p = &num2;    //ok p可读可写
    printf("*p = %d\n",*p);	//20
}

int * const p

const在*的右边const修饰的是p而不是*

用户可以通过*p修改p所指向空间的内容,但是不能再更改p的指向(*p可读可写,p只读)

void test1(void)
{
    int num1 = 10;
    int num2 = 20;
    
    //const在*的右边 *p可读可写  p只读
    int * const p = &num1;    //p一旦初始化 就不能更改指向
    printf("*p = %d\n",*p);    //10
    *p = 1000;    //ok *p可读可写
    printf("*p = %d\n",*p);    // 1000
    
    //p=&num2;    //err p只读    
}

const int * const p (*p只读,p只读)

void test1(void)
{
    int num1 = 10;
    int num2 = 20;
    const int * const p = &num1;    //*p和p都是只读
    //*p = 1000;    //err *p只读
    //p = &num2;    //err p只读

}