1. VS2019项目出现"const char *" 类型的实参与
    “char*” 类型的形参不兼容错误的解决方法

    解决方案一
    在VS2019中依次点击项目->属性->C/C+±>语言->符合模式,将原来的“是”改为“否”即可。
    解决方案二
    在声明变量 char* 时改成 const char *即可
  2. https://blog.csdn.net/edward_zcl/article/details/89451078 https://blog.csdn.net/YfBong/article/details/90277418

  3. char* s != char s[x] 虽然都能表示字符串 但是两者一个能修改字符串 一个是指定一个字符段且不能改
    图片说明
    图片说明

字符串 即末尾为\0

  • 字符数组!=字符串 ,因为不能用字符串的方式来计算
  • 字符串 => char word [] = {'H','e','l','l','o','!','\0'}; '\0' == 0 使得字符数组变成C语言的字符串
    字符数组 => char word [] ={{'H','e','l','l','o','!'};
  • 字符串以'\0' (整数0 )结尾的一串字符
    0 或'\0' 是一样的 【有些时候强调的是'\0是一个字节' 而0 是四个字节】,但是和'0'不同
  • 0标志字符串的结束,但它不是字符串的一部分
    计算字符串长度的时候不包含这个0
  • 字符串以数组的形式存在,以数组或指针的形式访问
    更多的是以指针的形式
  • string.h 有很多处理字符串的函数

字符串变量

  • char * str = "hello";
  • char word[] = "hello";
  • char line[10] = "hello"; 占据六个位置 6个字节 包括 \0(编译器自动生成\0加在字符串最后面 再赋值到line中)

字符串常量

  • "hello"

  • "hello" 会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0

  • 两个相邻的字符串常量会被自动连接起来

    #include<stdio.h>
    int main(void) {
    printf("考研" //自动连接
        "加油\n");
    printf("考研 \
    加油");//需置顶
        return 0;
    }
    //考研加油
    //考研加油

C语言字符串

  • C语言的字符串是以字符数组的形态存在的

  • 不能用运算符对字符串做运算 包括:字符串+字符串 直接即可:字符串字符串

  • 通过数组的方式可以遍历字符串

  • 唯一特殊的地方是字符串面量可以用来初始化字符数组

  • 以及标准库提供一系列字符串函数

char* 字符串是一个常数

  • s 是一个指针,初始化为指向一个字符串常量 i为变量 s2也是字符串

  • 由于这个常量所在的地方,所以实际上s是const char* s 但是由于历史的原因 ,编译器接受不带 const 的写法

  • 但是试图对s所指的字符串做写入会导致严重的后果

  • 如果需要修改字符串,应该用数组: char s3[] = "HELLO";

    #include<stdio.h>
    int main(void) {
    char* s = "Hello world"; //"hello world" 代码段 放在很小地址那
    //--> s[0] = 'B'; //ERROR 保护机制
    char* s2 = "Hello world";  //需要区别于 != char []s2    数组可以修改
    printf("%p\n", s);
    printf("%p", s2); //得 s == s2 是同一个
    return 0;
    32位架构
        //006FFA60 有差距
        //00917BD8
        //00917BD8
    64位架构
    // 0x7ffe6adbecf0 有差距
    // 0x414420 小的很 代码段 且有保护机制
    // 0x414420
    }

指针or 数组

  • 数组:这个字符串在这里
    作为本地变量空间自动被回收
  • 指针:这个字符串不知道在哪里
    处理参数
    动态分配空间

如果要构造一个字符串--->数组
如果要处理一个字符串--->指针

char* 是字符串吗?不一定 char* + \0 是字符串

  • 字符串可以表达为char * 的形式
  • char* 不一定是字符串
    本意是指向字符的指针,可能指向的是字符的数组(int * 一样 也可能是一个int数组)
    只有他指向的字符数组有结尾的0 才可以说他指的是字符串

字符串赋值

  • char* t = "title";

  • char *s;

  • s = t;
    并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的
    重新指向而非更改!!!

    图片说明

字符串的输入输出

  • 代码

    char string[8]; //超过八个字符 (只能接受七个 + \0)
    scanf("%s",string); //hello word 中间的空格会被当成分割两个字符串 读到空格就停了 【不安全】
    printf("%s",string);
    scanf读入一个单词 (到空格、tab或回车为止)
    scanf是不安全的,因为不知道要读入什么内容的长度
    ???
    scanf("%7s",word); //最多读七个字符 大于七就不要了 并留给下一个

常见错误

  • char * string
  • scanf("%s",string);
  • 以为char* 是字符串类型,定义了一个字符串类型的变量string 就可以直接使用了
  • 由于没有对string初始化为0,所以不一定每次运行都出错

空字符串

  • char buffer[100] ="" 这是一个空的字符串 ,buffer[0] =='\0'
  • char buffer[] = ""; 这个数组的长度只有1

代码输入12345678 12345678超过承载 有什么问题

  • 代码 情况一是会报错 【这种是先定义在低地址 后定义在高地址】
    而情况二##12345678## 【先变量在高地址 后定义在地址 可以通过取地址来进行验证】导致第一个word[0]='\0'输出为空

    #include<stdio.h>
    int main(void){
      char word[8];
      char word2[8];
      scanf("%s",word); //12345678
      scanf("%s",word2); //12345678
      printf("%s##%s",word,word2); //##12345678 word没有输出
      return 0;
    }

    图片说明

  • 为避免输入越界 可以采用scanf("%7s",&arr) 仅读小于7个 但是多余的字符会留到下一个
    #include<stdio.h>
    int main(void) {
      char c1[8];
      char c2[8];
      //12345678 12345678
      scanf("%7s", &c1);
      scanf("%7s", &c2);
      printf("%s\n",c1);
      printf("%s\n",c2);
      return 0;
      //1234567
      //8
    }

字符串数组用来表示很多个字符串

  • char **a:a是一个指针,指向另外一个指针,那个指针指向一个字符(串)
    图片说明) "图片标题")

  • char a[][10]
    图片说明) "图片标题")

  • char *a[10] 指针数组, 10个一维的,每个数组中都存放一个char *的东西 []结合优先级高于 *

    #include<stdio.h>
    int main(void){
      //char arr1[] = {"123","456","789","9123456789","131499",};//ERROR
      char arr2[][10] = {"123","456","789","123456789123","1131499",};//9123456789过长 导致\0写到下一块区域
      printf("%s\n",arr2[3]);
      printf("%s\n",arr2[4]);
      char *arr3[] = {"123","456","789","9123456789","131499",};
      return 0;
    }    
    //12345678911131499
    //1131499

程序参数

  • int main(int args , char const* argv[]) 字符串数组
  • argv[0] 是命令本身【在Unix 运行同一个代码可以用符号连接】,当使用Unix的符号连接时,反映符号链接的名字
    图片说明
  • 符号链接
    图片说明
    #include<stdio.h>
    int main(int argc, char const*argv[]){
    int i ;
    for(i=0 ; i < argc ; i++){
    printf("%d:%s\n",i , argv[i]);
    }
    return 0;
    }

字符串函数

putchar

  • int putchar(int c); int整数能够接收的是一个字符
  • 向标准输出写一个字符 char -> int return int ;
  • 返回写了几个字符, EOF(-1)表示写失败

getchar 会等用户输入东西取出来

  • int getchar(void);

  • 从标准输入读入一个字符

  • 返回类型是int是为了返回EOF(-1)
    Windows -> ctrl - z
    Unix ——> ctrl - D

    #include<stdio.h>
    int main(int argc, char const*argv[]){
    int ch;
    while((ch = getchar())!= EOF){
        putchar(ch);
        printf("-------\n"); //one by one
    }
    printf("EOF\n");
    return 0;
    }

    图片说明
    键盘输入- - - 缓冲区 --- 回车 --- 显示
    图片说明

字符串函数

string.h

  • strlen
    size_t strlen(constr char*s); constr 保证不修改s字符串 而char s[] 变成是一个一个字符
    返回s的字符串长度(不包括结尾的0)
    int是有符号整型,包括小于0的整数,size-t是无符号整型,只有0到max的整数。

    #include<stdio.h>
    #include<string.h>
    size_t mystrlen(const chara){
     int idx = 0 ;
     while(a[idx] != '\0')idx++;
     return idx;
    }
    int main(int argc, char constargv[]){
     char a[] = "Hello , world";
     printf("strlen(a)= %lu\n",strlen(a));
     printf("mystrlen(a)= %lu\n",mystrlen(a));
     printf("sizeo***",sizeof(a));
     return 0;
    }

  • strcmp 哪个位不相等 相减返回 acdadf < b

    int strcmp(const char *s1 , const char *s2); 安全版本 strncmp 末尾加一个参数 表示比较前几个
    比较两个字符串,返回

    • 0:s1 == s2
    • 1: s1>s2
    • -1: s1<s2
    #include<stdio.h>
    #include<string.h>
    int main(int argc, char const*argv[]){
    char *a = "abc";    //指针还可以进行==比较  
    char *b = "abc";
    printf("%d\n",strcmp(a,b));
    printf("%d\n",a==b);
    char c[] = "efg";
    char d[] = "efg";
    printf("%d\n",strcmp(c,d));
    printf("%d\n",c==d);// 数组的比较永远是false 不可以用==进行比较
    char e[] = "efg";
    char f[] = "abc";
    printf("%d\n",strcmp(e,f));
    printf("%d\n",e==f); 
    return 0;
    }

    4 = "efg" 和 "abc"的e a 差值 那个大那个小 高位重要性大于地位 所以高位先出现不同 直接return
    图片说明

  • strcpy 但存在安全问题---> 安全版本 strncpy 在末尾加一个int参数表示拷贝多少个

    • char * strcpy(char * restrict dst 目的 , const char* restrict src 材料);
    • 把src的字符串拷贝到dst
    • restrict 表明 src 和 dst 不重叠(C99) [][][1][2] --->[1][2][][] 这就是重叠 因为底层分段拷贝 节省性能 重叠无法实现该效果
    • 返回dst
    • 为了能链起代码来
    #include<stdio.h>
    #include<string.h>
    int main(int argc, char const*argv[]){
    char *a = "bcdadf";     
    char * dst = (char*)malloc(strlen(a)*sizeof(char)+1) ;//'/0'
    strcpy(dst,a);
    printf("%s",dst);//bcdadf
    return 0;
    }
  • strcat 连接 字符串(s1 , s2) 但存在安全问题---> 安全版本 strncat 在末尾加一个int参数表示末尾添加多少个
    把s2拷贝到s1后面 也就是s1的\0替换成s2[0]
    返回s1 且s1必须要有足够的空间

字符串搜索函数

返回NULL是没有找到 空指针

  • char* strchr(const char * s , int c)
  • char * strrchr(const char * s , int c)
  1. 代码 找到同个字母的第二个开始的字符串
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    int main(int argc, char const*argv[]){
     char *s = "hello";//char s[] = "hello";     
     char * p = strchr(s,'l');
     char * p1 = strchr(p+1,'l');
     //不知道p之后多大
     char * p2 = (char* )malloc(strlen(p1)+1);
     strcpy(p2,p1);
     printf("%s\n",p);
     printf("%s\n",p1);
     printf("%s\n",p2);
     free(p2);
     return 0;
    }
    //llo
    //lo
    //lo
  2. 找到某字母前的一段
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    int main(int argc, char const*argv[]){
     char s[] = "hello";//char *s = "hello";     
     char * p = strchr(s,'l');
     *p = '\0'; //字符串要用数组存储
     char * p1 = (char* )malloc(strlen(s)+1);
     strcpy(p1,s);
     printf("%d\n",strlen(p1));
     *p = 'l';
     printf("%s\n",s);
     printf("%s\n",p1);
     free(p1);
     return 0;
    }
    //hello
    //he
  • char* strstr(字符串,字符串) 在字符串中找到目标字符串
  • char* strcasestr(字符串,字符串) 在字符串中找到目标字符串 且忽略大小写