• C/C++(字符串)


    字符串

    c语言没有字符类型,字符串是有双引号硬起来的一串字符。

    字符串常量

    系统自动默认的在字符串末尾添加一个;

    stack:栈
    heap:堆
    data(初始化[全局变量,static 局部变量,常量])(未初始化) 
    text:
    

    大小实际大小加所占的一个字符。
    存储位置:data域

    printf("sizeof("china") = %d
    ",sizeof("china"));//6
    printf("%s
    ","china");//china
    char *p = "china";//编译无错
    printf("p = %p p+1 = %p p[0] = %c 0[p] = %c
    ",p,p+1,p[0],0[p]);
    printf("p = %p p+1 = %p p[0] = %c 0[p] = %c
    ","china","china"+1,"china"[0],0["china"]);
    /*
    sizeof("china") = 6
    p = 0040405A p+1 = 0040405B p[0] = c 2[p] = i
    p = 0040405A p+1 = 0040405B p[0] = c 0[p] = i
    */
    

    c语言,将字符串常量处理一个指向data段这段字符串的首地址。
    对比数组,三要素(起始地址,步长,范围)char *:代表了整个字符串,起始地址,步长,。三要素代表了整个字符串。

    修改字符常量:

    char arr[] = {'c','h','i','n','a'};
    arr[2] = 'x';//修改
    char arr1[6] = "china"; 
    printf("sizeof(arr) = %d arr = %p arr+1%p	
    ",sizeof(arr),arr,arr+1);
    printf("sizeof("china") = %d "china" = %p "china"+1%p	
    ",sizeof("china"),"chaina","china"+1);
    
    sizeof(arr)     = 6   arr   = 0061FEA6    arr+1  = 0061FEA7
    sizeof("china") = 6 "china" = 004040DC "china"+1 = 0040405B
    

    因为字符数组和字符串具有相同的性质。所以如果为了修改字符串的内容,可以将字符串拷贝到数组中去。
    数组是栈上的空间,“china”字符串常量是data域中,一块常量区。只要放到栈上就能任意的改变。

    char arr[] = {'c','h','i','n','a'};
    arr[2] = 'x';//修改
    char arr1[6] = "china"; 
    printf("sizeof(arr) = %d arr = %p arr+1%p	
    ",sizeof(arr1),arr1,arr1+1);
    printf("sizeof("china") = %d "china" = %p "china"+1%p	
    ",sizeof("china"),"chaina","china"+1);
    arr1[2] = 'x';//可以修改
    "china"[2] = 'x';//修改不了,报错
    

    字符数组与字符串

    字符数字和字符串之间具有相同的性质,但并不表示字符串可以与任意的字符数组划等号。

    等价关系

    sizeof(字符数组)的大小 >= sizeof(字符串)的大小。

    不等价

    sizeof(字符数组)的大小 小于 sizeof(字符串)的大小,此时不存在等价关系,此时的字符数组只是字符数组。

    更好的做法自适应,不定义数组的大小。

    printf("%s
    ","china");//chi
    char arr[2] = "china";//字符数组的大小大于等于字符串的大小时两者等价。
    printf("arr = %s
    ",arr);//ch({[]}
    

    字符串的输入与输出

    char arr[] = "china";
    printf("%s
    ",arr);//china
    puts(arr);//自带回车
    putd("");//换行,输出一个空串并且自带换行
    

    输入:
    输入的字符串,如果越界,此时的数组仅仅是字符数组而已。不能越界。scanf()函数遇到空格会结束。[^ ]可解决scanf()函数遇到结束的问题。
    gets()函数输入字符串,也会存在越界风险,但空格也会读入。
    fgets(arr,10,stdin);读入的字符放入数组中,最长10个数字(留一个放),stdin从键盘输入。

    char arr[6] = "china";
    scanf("%s
    ",arr);//arr本身是地址,无需取地址
    scanf("%[^
    ]s
    ",arr);//解决scanf()的空格换行问题
    gets(arr);//
    fgets(arr,10,stdin);
    
    printf("%d
    ",'');//0 asc码
    printf("%d
    ",NULL);//0,NULL,专门的标识符
    

    c语言是将如何处理常量字符串?将其编译为一个指向rodata一个字符的首地址。
    这个首地址,能代表字符串
    首地址+步长+范围(自动追加'')
    通过字符指针的方式,可以使用常量字符串,但不可以修改。

    char *p = "china";
    p[0] = 'x';//不可以
    

    若要操作内容:利用数组形式

    char arr[6] = "china";//将data 的rodata段的字符拷贝带了arr代表的字符串中。
    arr[2] = 'x';//此时操作字符等价于操作字符串,并且可以修改。
    
    

    是不是随便一个字符串都可以放到字符数组中
    当然不是,只有两者等价的关系下才可以。sizeof(字符数组的大小) >= sizeof(字符串的大小)

    char ch[2] = "china";
    printf("%s
    ",ch);//是不行的,
    char ch[6] = "china";//才可以,实际长度加一
    char [] = "china";//或者自适应
    

    可得出结论,对于字符串的处理就变成了对字符指针或者是字符数组的处理

    字符数组的操作(原生)

    字符串的长度:不包含''
    字符串的大小:包含''

    char *p = "china";//将指针赋值给了p sizeof(p) = 4的首地址
    char arr[] = "china";//将指针指向的内容赋值给了arr sizeof(arr) = 6;
    char *q = p;
    int count = 0;
    while(*q++) {//'',也就是0,假
        count++;
        //q++;//可以放面
    }
    for(count = 0;*q++;count++);
    printf("count = %d
    ",count);
    
    int len = strlen(arr);//
    int len = strlen(p);//
    printf("len = %d
    ",len);//5
    

    strlen()函数求数组的大小

    数组传递的时候谣传三要素(数组名,步长,范围),传字符串的时候,只需要传字符指针或者字符数组,因为字符串自带结束标志' '
    自己封装一个求字符串长度的函数

    int myStrlen(char * str) {
        int _len;
        for(_len = 0;*str++;_len++);
        return _len;
    }
    

    strcat()链接两个字符串

    把后面的一个参数合并到第一个参数的后面。concatenate

    char firstName[] = "assassin";
    char lastName[] = "wunworld";
    strcat(firstName,lastName);
    printf("%s
    ",firstName);
    
    
    char firstName[20] = "assassin";//要有足够的空间
    char lastName[10] = "wunworld";
    
    char *p,*q;
    p = firstName;
    q = lastName;
    while(*p) {//p指向''的位置,++不能放在括弧里,会移动到''后面的一个外置
        p++;
    }
    /*while(1) {
        *p = *q;//拷贝
        if(*p == '') {
            break;
        }
        p++;
        q++;
    }*/
    /*while(1) {
        if((*p = *q) == '')//简化
            break;
        p++;
        q++;
    }*/
    /*while(*p = *q) {//''即0,
        p++;
        q++;
    }*/
    while(*p++ = *q++); 
    
    printf("%s
    ",firstName);//assassinwunworld
    

    完整代码:

    #include<stdio.h>
    char *myStrcat(char *src,char *dist);
    int main() {
        char firstName[30] = "assassin";
        char middleName[10] = "seafwg";
        char lastName[10] = "wunworld";
        myStrcat(myStrcat(firstName,middleName),lastName);
        printf("%s
    ",firstName);
    
        return 0;
    }
    
    char *myStrcat(char *dest,char *src) {//返回char * 是因为链式操作
        char *d = dest;
        while(*dest) 
            dest++;
        while(*dest++ = *src++);//判断条件加赋值操
        return d;
    }
    
    

    strcpy()字符串的拷贝

    char name[222];//被拷贝要有足够的空间
    char *pName = "China";
    char name2 = "assassin";
    strcpy(name,name2);
    printf("%s
    ",name);//assassin
    
    char *myStrcpy(char *dest,char * src) {
        char *d = dest;
    //先拷贝,在判断,再加加
        /*while(1) {
            *dest = *src;
            if(*dest == '') {
                break;
            }
            dest++;
            src++;
        }*/
        while(*dest++ = *src++);
        return d;
    }
    

    strcmp()比较两个字符串是否相等

    一次比较ASCII的值,相同返回0,小于返回-1,大于返回1;

    char *s1 = "china";
    char *s2 = "china";
    //s1 == s3;//这样无疑判断的是两个字符串的地址
    strcmp(s1,s2);
    

    eg:简单的登录校验:

    #include<stdio.h>
    int main() {
        char name[100] = {0};
        char pawd[100] = {0};
        /*
        do{
            printf("输入用户名:");
            scanf("%s",name);
            printf("输入密码:");
            scanf("%s",pawd);
        }while(!(strcmp(name,"assassin") == 0) && !(strcmp(pawd,"123456") == 0));
     */
        int count = 4;
        while(1) {
            if(count < 4) {
                printf("你还有%d次机会
    ",count);
            }
            printf("输入用户名:");
            scanf("%s",name);
            printf("输入密码:");
            scanf("%s",pawd);
            if(strcmp(name,"assassin") == 0 && strcmp(pawd,"123456") == 0) {
                break;
            }else{
                count--;
                if(count == 0) {
                    exit(-1);
                }
            }
        }
        printf("欢迎光临!您好,%s
    ",name);
    
        return 0;
    }
    

    完整优化代码:

    #include<stdio.h>
    char myStrcmp(char * s1,char *s2);
    int main() {
        char name[100] = {0};
        char pawd[100] = {0};
        /*
        do{
            printf("输入用户名:");
            scanf("%s",name);
            printf("输入密码:");
            scanf("%s",pawd);
        }while(!(strcmp(name,"assassin") == 0) && !(strcmp(pawd,"123456") == 0));
     */
        int count = 4;
        while(1) {
            if(count < 4) {
                printf("你还有%d次机会
    ",count);
            }
            printf("输入用户名:");
            scanf("%s",name);
            printf("输入密码:");
            scanf("%s",pawd);
            if(myStrcmp(name,"assassin") == 0 && myStrcmp(pawd,"123456") == 0) {
                break;
            }else{
                count--;
                if(count == 0) {
                    exit(-1);
                }
            }
        }
        printf("欢迎光临!您好,%s
    ",name);
    
        return 0;
    }
    
    char myStrcmp(char * s1,char *s2) {
        //两者中没有空的
        while(*s1 != '' && *s2 != '') {
            if(*s1 > *s2)
                return 1;
            else if(*s1 < *s2)
                return -1;
            else{
                s1++;
                s2++;
            }
            /* 优化1
                if(*s1 != *s2) {
                    return *s1-*s2;
                }else{
                    *s1++;
                    *s2++;
                }
             */
            /*优化2
              for(;*s1 != '' && *s2 != '';s1++,s2++) {
                if(*s1 != *s2) {
                    break;
                }
              }
             * */
            /*优化3
              for(;*s1 && *s2;s1++,s2++) {//在代码中任何''只要是比较就是0,*s1 != ''(就是*s1非0,即存在) <=>*s1
                if(*s1 != *s2) {
                    break;
                }
              }
             * */
            /*优化4
              for(;*s1 && *s2 && *s1 == *s2;s1++,s2++) {//但不建议这么写,以后不利于优化,但可以表明小面判断的可以到for循环中添加,简化循环中的操作
                  break;
              }
             * */
        }
        //两者中有空的字符串(可以优化成 return *s1 - *s2;)
        if(*s1 == '' && *s2 != '')
            return -1;
        else if(*s1 != '' && s2 == '')
            return 1;
        else
            return 0;
        //return *s1 - *s2;//两个字符串相减确定了大小关系
    }
    
    

    多文件编程

    1.把一类共功能的函数写到一个XXX.c文件中。
    2.把XXX.c中的所有函数声明写到XXX.h文件中。
    3.在XXX.h中加入避免头文件重复包含的语句

    ifndef MYSTRING_H

    define MYSTRING_H

    XXX.c中文件的函数声明部分...

    endif

    4.将XXX.h文件包含到XXX.c中,自包含,自己实现的用双引号
    5.在main函数中包含XXX.h,谁用谁包含
    第一步是实现过程,第二步是声明过程,第三步(3,4)把1做成库,给别人提供就可以了

  • 相关阅读:
    20140710 sequence 前缀和
    20140709 testC 数学题
    20140708 testA 组合数学
    20140708 testB DP 组合数学
    Sad :(
    已经是一个废人了……
    Game Theory
    HDU Math Problems
    2-sat问题
    并查集
  • 原文地址:https://www.cnblogs.com/intelwisd/p/8299738.html
Copyright © 2020-2023  润新知