C初阶3:字符串
3.1 字符串操作:遍历、赋值、修改
int main(){
    char s[] = "Hello World!";
    // 字符串遍历1
    char* q = s;
    while('\0' != *q){
        printf("%c",*q++);
    }
    printf("\n");
    // 字符串遍历2
    for(int i = 0;'\0' != s[i];i++){
        printf("%c",s[i]);
    }
    printf("\n");
    // 字符串赋值
    char* p;
    p = s; //字符串可以赋值给指针
    // s = p; //指针不允许赋值给字符串
    // 字符串修改
    p[1] = 'A';
    printf("%p\n%p\n",s,p);
    printf("%s\t%s\n",s,p);
    s[2] = 'L';
    printf("%p\n%p\n",s,p);
    printf("%s\t%s\n",s,p);
}
 
Hello World!
Hello World!
0x7ffc0789c4fb
0x7ffc0789c4fb
HAllo World!	HAllo World!
0x7ffc0789c4fb
0x7ffc0789c4fb
HALlo World!	HALlo World!
 
3.2 字符串与函数
- 字符串传参
字符串传参方式与数组传参方式一样,只不过很多时候不需要传递字符串的长度
两种传参方式:char* str / char str[] 
void print_str(char* str){
    printf("%s\n",str);
}
void print_str2(char str[]){
    printf("%s\n",str);
}
int main(){
    char str[] = "Hello World!";
    print_str(str);
    print_str2(str);
}
 
- 字符串返回
字符串返回只能使用指针char*
str1和str2拼接 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* Strcat(char* s1,char* s2){
    char *s = malloc(strlen(s1)+strlen(s2)+1);
    int k = 0;
    for(int i = 0;s1[i] != '\0';i++){
        s[k++] = s1[i];
    }
    for(int i = 0;s2[i] != '\0';i++){
        s[k++] = s2[i];
    }
    return s;
}
int main(){
    char str1[] = "Hello";
    char str2[] = "World";
    char* s = Strcat(str1,str2);
    printf("%s\n",s);
}
 
字符拼接2
#include <stdio.h>
char* Strcat(char* s1,char* s2){
    char* res = s1;
    while('\0' != *s1){
        ++s1;
    }
    while('\0' != *s2){
        *s1++ = *s2++;
    }
    *s1 = '\0';
    return res;
}
int main(){
    char str1[11] = "Hello";
    char str2[] = "World";
    char* s = Strcat(str1,str2);
    printf("%s\n",s);  
}
 
3.3 字符串指针
数组可以用指针表示
 字符数组可以直接初始化字符数组,并且可以赋值给指针。
#include <stdio.h>
int main(){
    char s[] = "Hello World";
    char* p = s;
    printf("%s\n",p);
}
 
字符串也可以直接赋值给指针,这种指针成为字符串指针
#include <stdio.h>
int main(){
    char* s = "Hello World";
    printf("%s\n",s);
}
 
3.4 字符串指针 vs 字符数组
1、sizeof与strlen()
 2、字符是否可修改
 3、地址是否可修改
- 1、sizeof与strlen()
 
#include <stdio.h>
#include <string.h>
int main(){
    char* s = "Hello World";
    char s1[] = "Hello World";
    printf("%d\t%d\n",sizeof(s),strlen(s));
    printf("%d\t%d\n",sizeof(s1),strlen(s1));
}
 
8	11 sizeof(s)为指针s的长度,strlen(s)为字符串的长度
12	11 sizeof(s1)为字符串s1的长度(包含'\0'),strlen(s1)为字符串的长度
 
- 2、字符是否可修改
字符串指针的元素不可以修改
字符数组的元素可以修改 
    char* s = "Hello World";
    char s1[] = "Hello World";
    //*(s+2) = 'L'; //字符串指针不支持修改元素
    s1[2] = 'L'; //字符数组可以修改元素
    printf("%s\n%s\n",s,s1);
 
//等价
char s[] = "Hello World";
char s[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};
//等价
char* s = "Hello World";
const char t[]="Hello World"; //看作const型,所以无法修改元素
char* s = t;
 
- 3、地址是否可修改
字符串指针内容可以整体修改
字符串数组内容无法整体修改 
#include <stdio.h>
#include <string.h>
int main(){
    char* p = "Hello";
    char s[] = "Hello";
    p = "World"; //可以修改
    // s = "World"; //无法修改
    printf("%s\n%s\n",p,s);
}
 
- 字符串指针和字符数组如何选择
1、如果需要构造字符串使用数组;如果需要处理字符串使用指针(指向字符数组的指针)。
2、字符串不需要修改,使用字符串字面量初始化字符串指针。
3、字符串需要修,改使用字符串字面量初始化字符数组。 
3.5 字符串const
- const字符数组
 - 指向const字符是数组的字符串指针
 
#include <stdio.h>
#include <string.h>
int main(){
    const char s[] = "Hello World";
    //s[0] = 'h'; //不可修改
    //s[6] = 'w';
    char* p = s;
    printf("%s\n%s\n",s,p);
    *(p+6) = 'w'; //可修改
    *p = 'h';
    printf("%s\n%s\n",s,p); //s和p均被修改
}
 
Hello World
Hello World
hello world
hello world
 
结论:决定能否修改的是指针指向的值能否修改,const的限制只针对对应为const的变量。
3.6 字符串函数
- 字符串比较 strcmp
 
int strcmp(const char* s1,const char* s2)
 
s1>s2,返回值>0;
 s1<s2,返回值<0;
 s1==s2,返回值为0.
- 字符串拷贝 strcpy
 
char* strcpy(char* restrict dst,const char* restrict src);
 
返回值为dst
#include <stdio.h>
#include <string.h>
int main(){
    char dst[3] = "cd";
    const char* src = "ab";
    char* res  = strcpy(dst,src);
    printf("%s\t%s\n",dst,res);
    printf("%p\t%p\n",dst,res);
}
 
ab	ab
0x7ffd7f72fbbd	0x7ffd7f72fbbd
 
#include <stdio.h>
#include <string.h>
int main(){
    char dst[3] = "cd";
    const char* src = "ab";
    strcpy(dst,src);
    printf("%s\n",dst);
}  
 
ab
 
- 字符串拼接 strcat
 
#include <stdio.h>
#include <string.h>
int main(){
    char* a = "hello";
    const char* b = "world";
    char res[11];
    strcat(strcat(res,a),b);
    printf("%s\n",res);
}
 
strcpy和strcat都会有安全问题:dst空间不足,出现越界。
- 字符查找
 
#include <stdio.h>
#include <string.h>
int main(){
    const char* s1 = "abcdef";
    const char* s2 = "cd";
    char* c = strstr(s1,s2);
    printf("%s\n",c);
    printf("%p\t%p\n",c,s1+2);
}
 
cdef
0x40072a	0x40072a
 
返回地址为s2在s1中首次出现的地址
3.7 空字符串
#include <stdio.h>
#include <string.h>
int main(){
    char str[10] = "";
    char str2[] = "";
    printf("%d\t%d\n",strlen(str),strlen(str2));
    printf("%d\t%d\n",sizeof(str),sizeof(str2));
    // char* str3; //错误,使用未初始化的char*,若指针定义时候无法确定初始值,使用NULL初始化指针
    // printf("%s\n",str3);
}
 
0	0
10	1










