C++学习之字符和字符串


这篇文章是有关C++字符和字符串的学习内容。

上午给大一的C++课学生答疑,一个学弟在做“福尔摩斯的密码”问题,程序里面字符数组的定义出现了错误,他的定义是:char b[7][4] = {'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'},在VS2018里面编译只是有警告大概是”int常量转换为cha类型“,放到网站测试代码就会报错,错误提示是一样的。学弟的本意是在二维字符数组的每一行存三个字母。但是这么初始化字符数组肯定是错误的,因为单引号是字符,只能有单个字符,学弟的写法应该改成双引号。这也激起我对字符和字符串的细致的学习,从这篇文章开始,我会逐渐积累C++的知识点,希望自己不断地进步。

先附上C++的API链接,cplusplus,好多细节的知识可以从这里学习到。

在C/C++里,单个字符和字符串是有区别的,而这又取决于使用的是单引号或双引号。

  1. 表达式'A'代表一个单个字符。编译期间,C++将表达式替换为字符“A”的ACSII编码,该编码的十进制值是65
  2. “A”代表一个长度为1的字符串,C++编译器会把以下两个字节放到数据区里:
    • 字母"A"的ASCII代码
    • 一个零值(字符串结束标记)

C++编译器随后会把表达式“A”替换为这两个字节数组的地址。

'A'"A "是不同的,前者将被转换为一个整数值,后者被转换为一个地址。

下面来具体看一下C和C++中的字符和字符串。

C中的字符和字符串

  1. C中的字符使用单引号‘ ’,引号内只能有一个字符。

  2. C中并没有字符串数据类型,有两种方式表示字符串。

    • 一种方式是使用字符数组来保存字符串,c字符串实际上是一个以‘null’‘\0’)字符结尾的字符数组,’null‘字符表示字符串的结束。例如:char str[10] = "woshilee";

      注意:只有以null字符结尾的字符数组才是C字符串,否则只是一般的C字符数组。

    • 另一种方式是使用字符指针来访问一个字符串,通过字符指针指向存放字符串数组的首元素地址来进行访问。

      例如:char* str = "12345";

    其实两种方式中的变量str意义是一样的,都是指向字符串数组的首地址。

    C字符串定义时可以使用=进行初始化,但不能使用=对C字符串进行赋值,对C字符串的操作需要使用string文件中定义的字符串处理函数。

    字符串处理函数(头文件<string.h><cstring>)

    • strlen(const char *str):返回字符串的长度,但不包含字符串结尾的’\0’

      例子:char mystr[100]="test string";

      注意:sizeof(mystr)值为100(sizeof返回占用的字节数,如果是char arr[]="string",sizeof(arr)=7sizeof包括‘\0’),strlen(mystr)值为 11。

    • strcpy(char *destination, const char *source):复制source指针指向的字符串到des,包括’null‘结束字符。des空间要足够,避免内存溢出,两者空间不能重叠。

    • strncpy(char *destination, const char *source, size_t num):从source复制前num个字符到des;如果source的字符数少于num个,在des中会自动补0凑够num个;如果source的字符数大于num,des结尾就不会有隐式的结束符,要手动添加‘0’,否则读des会溢出。参数size_t是无符号整型。

    • strcat(char *destination, const char *source):拼接两个字符串,des的结尾字符被覆盖,拼接后的字符串结尾自动添加’null‘结束字符。des空间要足够,以避免内存溢出des和source空间不能重叠

    • strncat(char *destination, const char *source, size_t num):拼接source的前num个字符串到des,结尾自动添加’null‘结束字符;source的字符数小于num时,只有到结束字符的内容被复制。

    • strcmp(const char *str1, const char *str2):从第一个字符开始,两两比较两个字符串是否相等,相等返回0,否则返回非0<0>0,取决于第一个不同的字符的值的大小)。

    • strncmp(const char *str1, const char *str2, size_t num):比较两个字符串的前num个字符是否相等,相等返回0,否则返回非0<0>0,取决于第一个不同的字符的值的大小)。

  3. C中字符串的输入

    • scanfscanf_s函数(头文件<cstdio><stdio.h>

      例如:

      1
      2
      3
      4
      char str[10] = { 0 };
      scanf("%s", str);
      char str[10] = { 0 };
      scanf_s("%s", str, 10);

      注意:

      • 使用scanf函数时,若输入的字符数大于定义的字符数组长度就会出现缓冲区溢出;
      • 当输入的字符串中包含空格时,scanfscanf_s 函数只会接收空格前的字符串。例如:hello world则只会接收到:hello
      • scanf_s函数最后一个参数代表缓冲区的大小,示例中缓冲区大小为10,但最多能放入9个字符,因为最后一个需要放’\0’
    • getsgets_s函数(头文件<cstdio><stdio.h>

      gets函数从标准输入流stdin中读取字符,并存储在字符串指针所指的内存空间,直到读取到换行符或文件结束符,换行符不会读入字符串;结束符号‘null’会自动添加到结尾。

      1
      2
      3
      char str[10] = { 0 };
      gets(str);
      gets_s(str, 10);

      注意:

      • gets函数解决了scanfscanf_s不能输入空格的问题,但是没有解决缓冲区溢出的问题。
      • gets函数由于也不安全所以被 gets_s函数代替,该函数的后一个参数代表缓冲区大小。

      但是,get_s在linux中用不了,会提示没有定义,因为该函数是微软自创的,要在windows下vs中使用才行,可以使用fgets 函数替代。

    • fgets 函数(头文件<cstdio><stdio.h>

      函数原型:

      1
      char * fgets (char *str, int num, FILE *stream);

      fgets接受一个流参数,将读取到的字符保存在C字符串中,直到读取到num-1个字符或读到换行符或文件结束符;与gets函数不同的是它会将换行符读入字符串,作为字符串的一部分;结束符号‘null’会自动添加到结尾。其中参数num包含结束符号‘null'

      总结一下fgetsgets的区别:

      • gets函数从标准输入流stdin读取字符,换行符不会加入字符串;fgets接受一个流参数,换行符会加入字符串;
      • fgets函数限制了接收字符的个数,改进了gets函数缓冲区溢出的问题,是安全函数;
      • fgets是为读取文件设计的,读取键盘时没有gets函数方便。
  4. C中字符串的输出

    • printfprintf_s函数(头文件<cstdio><stdio.h>

      printf函数输出字符串到标准输出流stdout

    • puts函数(头文件<cstdio><stdio.h>

      将字符串数据写到标准输出流stdout,直到遇到结束符号'\0'(不输出结束符号),并在末尾自动添加一个换行符’\n'

      例如:

      1
      2
      char *str="hello world";
      puts(str);
    • fputs函数(头文件<cstdio><stdio.h>

      将字符串数据写到流,一个指向标识输出流的FILE对象的指针,直到遇到结束符号'\0'(不输出结束符号)。

      函数原型:

      1
      int fputs(const char *str, FILE *stream);

      例如:

      1
      2
      char *str="hello world";
      fputs(str, stdout);

C++中的字符和字符串

不同于C中的使用字符数组或字符指针表示字符串,C++中定义了字符串类String类,引用头文件<string>可以直接定义string类的对象,即字符串对象,使用该变量对字符串进行操作。string是C++标准库的一个重要的部分,主要用于字符串处理。可以使用输入输出流方式直接进行操作,也可以通过文件等手段进行操作。同时C++的算法库对string也有着很好的支持,而且string还和C语言的字符串之间有着良好的接口。当然也存在一些弊端。

  1. C++字符串的输入

    • 使用输入操作符填充一个字符串变量

      例如:

      1
      2
      string str;
      cin>>str;

      注意:读取过程会忽略最初的空白字符(空格、制表符和换行符),同时输入会在下一个空格或者换行符处停止。例如:hello world则只会接收到:hello

    • 使用预定义函数getline()获取整行输入(包括空格)

      从输入流中提取字符。

      函数原型:

      1
      istream& getline (istream&  is, string& str);//其中之一

      getline()的两个参数:

      • is:输入流
      • str:用于接收输入的字符串变量

      例如:

      1
      2
      string str;
      getline(cin, str);

      注意:getline()函数在遇到行结束(换行符或‘\n’)时停止接收字符。

  2. string类型的变量可以使用+=等运算操作符,直接对字符串变量进行操作。

字符串中的小细节

  1. string对象和C字符串直接的转换

    • 可以将C字符串存储在string类型的变量中

      例如:

      1
      2
      3
      char str[] = "hhhha";
      string s;
      s = str;
    • string对象不能自动的转换为C字符串,需要进行显式的类型转换,用到string类的成员函数c_str()

      例如:

      1
      strcpy(str, s.c_str());
  2. 字符串到数字的转换

    可以使用atoi函数获取一个字符串参数,该函数返回字符串对应的int值。如果参数不与一个int值对应,atoi就会返回0。atoi函数在文件为cstdlib的库中。如果数字太大,不能转换成int类型的值,可以使用atol将字符串转换为long类型的值。如果想转换为浮点数,可以使用atof函数。

    例如:

    1
    2
    3
    4
    5
    6
    atoi("1234");   //返回整数1234
    atoi("#123"); //返回0
    char* str1 = "29.3547";
    float f = atof(str1);//给f赋值为29.354700
    char* str2 = "31465666";
    long l = atof(str2);//给l赋值为31465666
  3. C++对于单引号“字符串”的处理

    ‘ABCD’为例,在C++中将单引号引用的部分看作一个字符,它表示一个整形常量。

    1
    2
    3
    4
    5
    6
    7
    int flag = 'ab';  
    cout<< flag <<endl;
    printf("%X\n", flag);
    char * array = (char *)&flag;
    char buff[5] = {0};
    strncpy(buff, array, 4);
    cout << buff <<endl;

    输出:

    1
    2
    3
    24930
    6162
    ba

    C++在处理单引号引出的多个字符时,用4个字节大小的整数来表示,‘ab’的每个字符逐个赋给了flag这个变量的每个字节,Intel的CPU基于x86的架构,X86采用的是小端模式,即将整形的高位放在了内存的低地址处,所以a看成高位,b看成低位。如果使用printf("%X\n", flag)会看到输出为6162。在C++内部的运算:a的ACSII是97b的ACSII是98,经过运算97*256+98=2493097 << 8 + 98 = 24930(左移操作符相当于扩大为2^4倍)。值得注意的是,如果大小超过4字节,就会溢出。

关于字符和字符串的知识先总结到这里,在今后的学习中会继续学习积累,希望能不断进步。加油~~:smile:

本文标题:C++学习之字符和字符串

文章作者:阿翔

发布时间:2018年03月23日 - 10:03

最后更新:2019年05月28日 - 21:05

原始链接:http://ttshun.com/2018/03/23/C++学习之字符和字符串/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

点击给我一些鼓励叭!
-------------本文结束感谢您的阅读-------------
0%