• C++关于字符串的一点注意事项


    之前在给字符数组分配堆空间时出现了堆访问越界的问题。

    经过一番查找,发现是对字符串的strlen、sizeof和字符串末尾结束符没理解清楚,现在趁这个空隙捋一捋。

    一.字符串读取默认是会以'\0'结尾的。

    首先要知道strlen函数读出来的字符串长度是以在哪个位置上读取到'\0'作为字符串的终止标志的。

    1.举例1:

    本质为分配在常量区

    1. int main()
    2. {
    3. char* s = "123\0 45";//在字符串中间人为插入'\0'
    4. cout << strlen(s) << " " << sizeof(s) endl;
    5. for (int i = 0; i < 8; ++i)cout << s[i] << endl;
    6. return 0;
    7. }

    1) 观察输出结果,发现 strlen只读取了前三位1、2、3的长度,这说明strlen的读取规则是以第一次出现的'\0'作为字符串结尾的。

    2)但是实际上为"123\0 45"这个字符串开辟了8个字节,分别存储的{ '1', '2' ,'3', '\0', '4', '5' , '\0'};

    注意系统会为"123\0 45"这个字符串最后再多分配一个'\0'

    3) 除此之外,还有一个需要注意到的:sizeof并不会正确读取这种情况下字符串的正确长度,只是读出一个字符指针的地址长度。

     2.举例2:

    本质为分配在栈区

    1. int main()
    2. {
    3. char s2[5]{ '1','2','3','\0','5' };
    4. cout << strlen(s2) << " " << sizeof(s2) << endl;
    5. for (int i = 0; i < 5; ++i)cout << s2[i] << endl;
    6. return 0;
    7. }

    以字符数组的形式分配字符串 ,strlen函数同样是以'\0'结尾作为结尾的。但是这时候的sizeof能正确读取到实际的字符数组的长度。

     3.举例3:

    本质为分配在堆区。

    1. int main()
    2. {
    3. char* s3 = new char[6]{ '1','2','\0','3','4','5' };
    4. cout << strlen(s3) << " " << sizeof(s3) << endl;
    5. for (int i = 0; i < 5; ++i)cout << s3[i] << endl;
    6. return 0;
    7. }

     同样,分配在堆区的情况strlen也是以读取'\0'作为结尾的。并且sizeof也只是读取到了字符指针的地址长度。

    二、总结

    如果要安全使用字符数组去表示字符串时,那么最后一位一定不要将其赋值,因为默认为字符数组分配的值便是'\0'。最后一位不赋值能让strlen函数正确读取到有效的字符串长度。

    1.举例1:

    1. int main()
    2. {
    3. char* s3 = new char[7]{ '1','2','3','4','5' };
    4. cout << strlen(s3) << " " << sizeof(s3) << endl;
    5. for (int i = 0; i < 5; ++i)cout << s3[i] << endl;
    6. return 0;
    7. }

    数组在'5'后面没有赋值了,因此系统的默认分配是'\0'。因此读出的有效长度是5。

    如果占用了最后一位的话呢?

    1. int main()
    2. {
    3.     char* s3 = new char[5]{ '1','2','3','4','5' };
    4.     cout << strlen(s3) << "  " << sizeof(s3) << endl;
    5.     for (int i = 0; i < 5; ++i)cout << s3[i] << endl;
    6.     return 0;
    7. }

     

     这时候strlen读出来的长度是22,这可能是一个随机的值。如果我们采用的strlen读出的值作为数组长度那就会产生读取越界的问题了。

     2.举例2

    1. int main()
    2. {
    3. char s4[5]{ '1','2','3','4','5' };
    4. cout << strlen(s4) << " " << sizeof(s4) << endl;
    5. int n1 = strlen(s4);
    6. for (int i = 0; i < n1; ++i)cout << s4[i] << endl;
    7. }

    分配在栈上的情况同理。

    不正确地使用字符数组容易造成一些不易察觉的但是严重的问题,这是值得注意的。 

  • 相关阅读:
    nodejs系列-编写接口实现前端302重定向
    C++设计模式02-——策略设计模式
    Python中NumPy的常见用法
    窗口看门狗使用介绍
    mysql只copy数据库文件而不copy系统表文件到另一个数据库,新库可以正常使用该库和表吗?
    连续信号与系统的频域分析之傅里叶级数
    化繁为简,聊一聊复制状态机系统架构抽象
    创建vue项目的安装汇总
    find 与 cp 命令组合使用
    与web3.0有关的科技热词的提问和SmartChat给出的回答
  • 原文地址:https://blog.csdn.net/qq_42987967/article/details/126257255