6 CPP之C风格字符串

CPP之C风格字符串

c++中的string类,封装了C风格的字符串。 使用方便,能自动扩展,不用担心内存问题

在某些场景中,C风格字符串更方便,更高效

C标准库、Linux系统和开源库,大部分开源库一定有C语言版本,但不一定有C++版本,还有数据库接口函数,例如MySQL,只有C语言版本,没有C++版本。

C语言约定:如果字符串(char)数组的末尾包含了空字符\0(也就是0),那么该数组中的内容就是一个字符串。

这是一个数组,不是字符串。

 这是一个字符串数组,也是一个字符串

 c++也遵守这个约定,string类中的字符串,最后也有一个空字符,只是没有显示出来而已。

#include <iostream>
using namespace std;

void test()
{
    string str = "abc";
    cout << "str[0]" << str[0] << endl;
    cout << "str[1]" << str[1] << endl;
    cout << "str[2]" << str[2] << endl;
    cout << "str[3]" << str[3] << endl;
}
int main()
{
    test();
    return 0;
}
str[0]a
str[1]b
str[2]c
str[3]
#include <iostream>
using namespace std;

void test()
{
    string str = "abc";
    cout << "str[0]" << (int)str[0] << endl;
    cout << "str[1]" << (int)str[1] << endl;
    cout << "str[2]" << (int)str[2] << endl;
    cout << "str[3]" << (int)str[3] << endl;
}
int main()
{
    test();
    return 0;
}
str[0]97
str[1]98
str[2]99
str[3]0

因为字符串需要用0结尾,所以在声明字符串数组的时候,要预留一个字节用来存放0.

例如:

char name[21]; //声明一个最多存放20个英文字符或10个中文的字符串(中文占两个字节)

1)初始化方法

#include <iostream>
using namespace std;

void test()
{
    char name1[11]; //可以存放1个字符,没有初始化,里面是垃圾值

    for (int i = 0; i < 11; i++)
    {
        cout << (int)name1[i] << " ";
    }
    cout << endl;
}
int main()
{
    test();
    return 0;
}
0 0 0 0 0 0 0 0 0 0 0
只打印name1的时候,输出全部是11个0,看上去是没问题的,但是后面有例子(还有别的打印)就可以看出不初始化不全部都是0.

char name1[11]; //可以存放1个字符,没有初始化,里面是垃圾值,但不影响使用,如果单独打印的时候都是0

char name2[11] = "hello"; //初始化内容为 hello

char name3[] = {"hello"}; //初始化内容为 hello,系统会自动添加\0,数组长度是6.

char name4[11] = {"hello"}; //初始化内容为 hello

char name5[11]{"hello"}; //初始化内容为 hello

char name6[11] = {0}; //把全部的元素初始化为\0 这种方法用的最多

#include <iostream>
using namespace std;

void test()
{
//可以存放1个字符,没有初始化,里面是垃圾值,如果单独打印的时候都是0,
//但是在这个例子中,有别的打印就可以看出有问题了
    char name1[11];
    char name2[11] = "hello";   //初始化内容为 hello
    char name3[] = {"hello"};   //初始化内容为 hello,系统会自动添加\0,数组长度是6.
    char name4[11] = {"hello"}; //初始化内容为 hello
    char name5[11]{"hello"};    //初始化内容为 hello
    char name6[11] = {0};       //把全部的元素初始化为\0
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name1[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name2[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name3[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name4[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name5[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name6[i] << " ";
    }
    cout << endl;
}
int main()
{
    test();
    return 0;
}
0 0 0 96 24 64 0 0 0 0 0 
104 101 108 108 111 0 0 0 0 0 0 
104 101 108 108 111 0 104 101 108 108 111 
104 101 108 108 111 0 0 0 0 0 0 
104 101 108 108 111 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0

可以看出这个时候name1就有问题了

2) 清空字符串

#include <iostream>
#include <cstring>
using namespace std;

void test()
{
    char name[11] = {"hello"};

    //清空字符串

    name[0] = 0; //不规范 有隐患 不推荐
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name[i] << " ";
    }

    memset(name, 0, sizeof(name)); //把全部元素置为0
}
int main()
{
    test();
    return 0;
}
0 101 108 108 111 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 

3)字符串赋值或赋值 strcpy()

char *strcpy(char*dest,const char*src);

C++风格的字符串可以用等号赋值,很方便,但是C风格的不能用,只能用strcpy()

功能:将参数src字符串拷贝至参数dest所指的地址。

返回值:返回参数dest的字符串起始地址。

复制完字符串后,会在dest后追加0.

如果参数dest所指向的内存空间不够大,会导致数组的越界。

#include <iostream>
#include <cstring>
using namespace std;

void test()
{
    char name[11] = {"hello"};

    cout << endl;
    strcpy(name, "world");
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name[i] << " ";
    }
    cout << endl;
    strcpy(name, "worldworldworld");
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name[i] << " ";
    }
    cout << endl;
}
int main()
{
    test();
    return 0;
}
main.cpp: In function 'void test()':
main.cpp:16:11: warning: 'void* __builtin_memcpy(void*, const void*, long long unsigned int)' writing 16 bytes into a region of size 11 overflows the destination [-Wstringop-overflow=]
     strcpy(name, "worldworldworld");
     ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
 
119 111 114 108 100 0 0 0 0 0 0 
119 111 114 108 100 119 111 114 108 100 119 

strncpy()

char* strncpy(char* dest,const char* src,const size_t n);

功能,把src前n个字符的内容赋值到dest中

返回值:dest字符串起始地址

如果src字符串长度小于n,则拷贝完字符串后,在dest后追加0,直到n个。

如果src的长度大于等于n,就截取src的前n个字符,不会在dest后追加0。

如果参数dest所指的内存空间不够大,会导致数组的越界

#include <iostream>
#include <cstring>
using namespace std;

void test()
{
    char name[11];

    memset(name, 0, sizeof(name));

    // strncpy(name, "hello",8);//会自动补0
    strncpy(name, "hello", 3); //不会自动补0,可以用memset(name,0,sizeof(name))先清空name;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name[i] << " ";
    }
    cout << endl;
}
int main()
{
    test();
    return 0;
}
这里有个坑,就是src小于n的时候,不会自动补0,可以先用memset清空
#include <iostream>
#include <cstring>
using namespace std;

void test()
{
    char name[11];

    memset(name, 0, sizeof(name)); //打开注释,name打印,除了hel则3个字符,后面就全部是0了

    // strncpy(name, "hello",8);//会自动补0
    strncpy(name, "hello", 3); //不会自动补0,可以用memset(name,0,sizeof(name))先清空name;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name[i] << " ";
    }
    cout << endl;
    char name2[11] = "hello";   //初始化内容为 hello
    char name3[] = {"hello"};   //初始化内容为 hello,系统会自动添加\0,数组长度是6.
    char name4[11] = {"hello"}; //初始化内容为 hello
    char name5[11]{"hello"};    //初始化内容为 hello
    char name6[11] = {0};       //把全部的元素初始化为\0    这种方法用的最多
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name2[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name3[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name4[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name5[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 11; i++)
    {
        cout << (int)name6[i] << " ";
    }
    cout << endl;
}
int main()
{
    test();
    return 0;
}
104 101 108 0 0 0 0 0 0 0 0 
104 101 108 108 111 0 0 0 0 0 0 
104 101 108 108 111 0 104 101 108 108 111 
104 101 108 108 111 0 0 0 0 0 0 
104 101 108 108 111 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 

5)获取字符串长度 strlen();

 

#include <iostream>
#include <cstring>
using namespace std;

void test()
{
    char name[11] = {"hello\0f"};
    cout << strlen(name) << endl;
    char name1[11] = {"hello"};
    name1[1] = 0;
    cout << strlen(name1) << endl;
}
int main()
{
    test();
    return 0;
}
5
1

6)字符串拼接 strcat()

 

 

 

11)

可以把C风格的字符串用于包含了string类型的赋值拼接等表达式中。

注意事项:

1 字符串的结尾标志是0,按照约定,在处理字符串的时候,会从起始位置开始搜索0,一直找下去,找到为止(不会判断数组是否越界)

2 结尾标志0后面的都是垃圾内容

3 字符串在每次使用前都要初始化,减少入坑的可能,是每次,不是第一次。

4 不要在子函数中对字符指针用sizeof运算符,所以,不能在子函数中对传入的字符串进行初始化,除非字符串的长度也作为参数传入到子函数中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值