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

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

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

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

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

1.举例1:

本质为分配在常量区

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

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:

本质为分配在栈区

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

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

 3.举例3:

本质为分配在堆区。

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

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

二、总结

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

1.举例1:

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

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

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

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

}

 

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

 2.举例2

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

分配在栈上的情况同理。

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值