C-style string一些笔记

标签(空格分隔): C++ 编程语言


介绍:

C++中字符串分为两种,分别为:

  • C-style string
  • string类库的string

对于前者,是一个char类型的数组,但是最后一位一定是’\0’
(这一点我们可以用’\0’来截断字符串);
我们可以简单定义一个样例:

char test[5] = {’t’, ‘e’, ’s’, ’t’, ‘\0’};

这里’\0’的机制让我想了好久,在下面输出的地方细说

但是如上定义起来很麻烦,要一个一个字符加单引号敲上去,所以就可以定义一个叫做字符串常量(string constant)或者叫做字符串字面值(string literal)的字符串:

char test[5] = “test”; //预留一个’\0’的位置
char test[] = “test” //让编译器去数,然后开空间

然而还有一种情况是,我们开的空间富余下来,比如:

char test[10] = “test”;
char test[10] = {'t', 'e', 's', 't'};

这样剩下的空字符会自动被补位’\0’

BTW我这里突发奇想做一个小实验:

char test_1[10] = {'t', 'e', 's', 't'};
char test_2[10] = "test";
if (test_1 == test_2) {
    cout << "equal" << endl;
}

编译的时候g++告诉我:

warning: array comparison always evaluates to false [-Wtautological-compare]

运行的时候果真是false,Tell me why。。。。。
这里同学后来提醒我,数组名是指向数组首地址的指针,拿内存了两个不同的地址相比,怎么可能正确……
——————————————————————
(另起下一个话题)

去查C-style string的原因是看到一篇博文,说到

定义

void print(const char*);

然后调用的时候是精确匹配:

print("a");//精确匹配,调用print(const char*)

查阅了书之后才发现,“test”这个常量字符串,表示的是字符串所在的内存地址,所以应该是const char*类型的变量
所以

char test[] = “test”

我们是将“test”的内存地址赋给了test
那么cout的时候

cout << test[] << endl;

是过不了的,但是

cout << test << endl;

是可以的

另外如果“test”表示的是地址

cout << “test” << endl;

也是可以过的

说明C++在输出常量字符串的时候,传入cout和’<<’的参数是常量字符串的内存地址,有点诧异,cout不忠于数据而去解析地址了呀
———————————————————————————

再做一个实验:

const char* test = "test";
cout << test << endl;

结果输出的是test

const char* test = "test";
cout << *test << endl;

结果就只能输出首字母t

————————————

char* test = "test";
cout << test << endl;

这个时候编译器给我了一个警告:
warning: conversion from string literal to ‘char *’ is deprecated

说明我在这里做了一个字符串面值到字符类型的指针的一个转换,那么我忽略警告去运行呢,
就发现输出的还是test

那么说明,const 在这里不是简简单单的常量不可变的意思
const char* 单独列出,成为了一种数据类型,就是叫做常量字符串。

操作:

cout 拼接:

cout << “hello” “world” << end; 
cout << "hello"
"world" << endl;

两种都是可以过的,结果就是helloworld

头文件:

单独使用时不需要头文件,但是如果需要调用一些C-style string的函数,我们就需要

# include<cstring>

老式的是:

# include<string.h>

常见的strlen,strcmp, strcpy等等,这些函数其实用到的时候去百度一下就好,或者自己做一下小实验,理解更清晰
….好吧我懒得总结
简单写下:

strlen:
原理应该是从首地址开始计数,到最后一个不是’\0’的字符位置字符串的长度

strcmp:
原型为

int strcmp(const char *s1, const char *s2);

字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。strcmp()首先将s1 第一个字符值减去s2 第一个字符值,若差值为0 则再继续比较下个字符,若差值不为0 则将差值返回。例如字符串”Ac”和”ba”比较则会返回字符”A”(65)和’b’(98)的差值(-33)。

strcpy:
把字符串s2中的内容copy到s1中,连字符串结束标志也一起copy.

strcat:
strcat() 函数用来连接字符串,其原型为:

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

strcat() 会将参数 src 字符串复制到参数 dest 所指的字符串尾部;dest 最后的结束字符 NULL 会被覆盖掉,并在连接后的字符串的尾部再增加一个 NULL。

至于其他的一些函数,或者这些函数的一些特殊情况的处理, 当真正用到的时候,还需要我们去查阅和试验;

输出:

这里先不管书上的内容,我自己做了一些实验:

实验一:

char test01[3] = {'a', 'b', 'c'};
char test[3] = {'t', 'e', ’s'};

cout << test << endl;
cout << *(test+3) <<endl;

结果是tesabc和’a’

问题:

  • 直接定义一个字符数组,编译器会不会自动加’\0’?
  • 如果1是会的话,为什么我test01会将test的’\0’覆盖?

(后来发现其实是不加’\0’, 但是cout来访问机制会不一样)

实验二:

const char* test01 = "abc";
const char* test = "tes";

cout << test << endl;
cout << *(test+3) <<endl;

结果是”tes“和空

第一个理解为纯粹的字符数组,那么第二个为字符串常量,看来自动加上了’\0’并且不会被覆盖

后来和同学讨论了一下,字符数组不是字符串,因为在上面的例子中字符数组的内存开在一起,直接通过cout数组名来访问,本身就是一个不合适的操作,所以难免会出一些问题,但是这一块确实会容易搞混(字符数组和字符串),辨析的时候还是要理清思路。

输入:

常量肯定不能通过输入来定义了,我们定义变量字符串的时候,cin在在输入一个字符串或者字符数组的时候不能有空格,其次,cin会在输入结束的时候不读取’\n’,但是会自动加’\0’

如果想输入整行,可以用getline函数。

总结:

容易混淆的有三种类型:
字符数组
变量字符串(就是末尾为’\0’的字符数组)
常量字符串(用双引号引起来的字符串)

前两者的指针类型为char*
常量字符串的指针类型为const char*

容易混淆的操作,比如说如上的

char test[] = “test”;

“test”为常量字符串, 而test为变量字符串, 实现的机制是:
在构造test的时候,我们在常量表里找到”test“, 然后逐个字符复制到test中,最后加’\0’

引用:在C++中,std::string是一个类模板,用于表示字符串。可以使用它来声明和操作字符串变量。使用std::string声明一个字符串的方法有多种。一种常见的方法是使用std::string的构造函数来初始化字符串变量,例如:std::string str {"这是一个字符串"}; 另一种方法是使用赋值操作符将字符串连接起来,例如:str = str + "哈哈哈"; 但是在C++中,直接将两个字符串字面量连接起来是错误的写法,例如:str = "123" + "456"; 这是因为字符串字面量是常量字符数组,不支持直接进行连接操作。 引用:std::string是C++标准库提供的字符串类型,可以使用#include <string>来引入std::string的定义。有多种方法可以初始化std::string变量。一种方法是使用花括号初始化列表来初始化字符串变量,例如:std::string str { "这是一个字符串" }; 另一种方法是使用构造函数并指定要截取的长度,例如:std::string str2 { "abcde", 3 }; 这将截取字符串的前3个字符。 引用:std::string还提供了一些方法来处理字符串。例如,可以使用std::stringstream类将其他类型的数据转换为字符串。通过将数据插入到std::stringstream对象中,然后使用std::stringstream.str()方法将其转换为std::string类型。例如:std::stringstream strSt; strSt << "你好" << 123; std::string _str = strSt.str(); 这样就可以将"你好"和123转换为一个字符串"你好,123"。 综上所述,string8和string16是指定字符串的编码方式。std::string是以ASCII字符编码方式存储字符串的类型,而string8和string16分别指定了使用UTF-8和UTF-16编码方式存储字符串的类型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C/C++笔记:std::string(一)](https://blog.csdn.net/Nine_Yao/article/details/123706441)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值