C/C++中的C-风格字符串及输入函数cin、cin.getline、cin.get、getline

一、先了解几个函数及概念:

1.空字符

ASCII值为0的字符,用’\0’表示,属于不可见字符

2.不可见字符

也叫ASCII控制字符,常见不可见字符有:上面提到的空字符、Tab键的空格,换行符…(更多见百度)

注意!空格键输入的空格ASCII值为32,属于可见字符!

3.空白

空格、制表符和回车统称为空白(white space)

4.strlen函数:

(1)只计算可见字符;
(2)从第一个字符开始计算,到不可见字符为止的字符数(字符数不含不可见字符,因为到不可见字符就停了)
(3)返回字符串的长度

5.sizeof函数:

指出整个数组的长度(包含中间及结尾不可见字符,结尾那个不可见字符指的是系统帮你加的’\0’,你自己就算写了’\0’那也算中间的)。
如果你像char sample[11] = "aabbccdd\0";这样再sizeof(sample),就等于原来定义的数组长度;
如果你不自己指定数组长度,那就是你字符数组的长度+1(加的这个1是系统帮你加的’\0’)

这里不是很好展开,更多细节及验证可以去这里看一下 字符与字符串中的’\0’, ‘0’, 0;strlen()函数求字符串长度计算方法(sizeof()验证)

二、什么是字符数组,什么是字符串?

(1)这是字符数组,因为没有自己写’\0’

char dog[8] = {'a','b','c'};   		// not a string! 

(2)这是字符串,因为写了’\0’

char cat[8] = {'f','a','t','\0'} 	// it a string! 

当前,谁想写个长点儿的字符串用上面的方法一个个敲啊?

有个更好的将字符数组初始化为字符串的方法——只需要一个引号括起的字符串即可,这种字符串被称为字符串常量(string constant)或字符串字面值(string literal),如下所示:

char bird[11] = "Mr. Cheeps";	// 中间含空格,是个可见字符。strlen(bird)等于10,最后一个char空间留给'\0'
char fish[] = "Bubbles";

用引号括起来的字符串隐式的包括结尾的空字符,因此不用显示的包括它。
注意!在确定存储字符串所需的最短数组时,别忘了将结尾的空字符计算在内!

另外,char boss[8] = "abc";的内存空间是这样的:
在这里插入图片描述
更多细节及验证还是可以去这里看一下 字符与字符串中的’\0’, ‘0’, 0;strlen()函数求字符串长度计算方法(sizeof()验证)

三、单引号’'和双引号""能不能混用,为什么?

python中我们知道是可以的。但是C\C++中不可以。
例如:

char size = 'S';

这个语句的作用是将83赋值给size(在ASCII系统上,'S’只是83的另一种写法)

但是下面这个例子能有相同的作用么?

char size = "S"; 		// illegal type mismatch

很遗憾不能,"S"不是字符常量,它表示的是两个字符(字符S和\0)组成的字符串。更糟的是在这个语句中,"S"实际上表示的是字符串所在的内存地址,也就是试图将一个内存地址赋值给char类型的size。
由于地址在C++中是一种独立的类型,因此C++编译器不允许这种不合理的做法!

四、三个C++输入函数cin()、cin.get()、cin.getline()

istream中类(如cin)提供了一些面向行的类成员函数:getline()和get()。
这两个函数都读取一行输入,直到到达换行符。

1.cin()

简单操作大家都会,高级特性还未使用,留个坑后面再填

2.cin.getline();
  • 作用:读取整行,通过回车键键入的换行符来确定输入结尾
  • 格式:cin.getline(char* s, streamsize n)重载形式下: s :用来存储输入行的数组的名称; n :是要读取的字符数
  • 细节:
    ①在读取指定数目的字符或遇到换行符时停止读取。如果参数 n 为20,则函数最多读取19个字符,余下的空间存储自动在结尾处添加的空字符。
    ②通过回车键键入的换行符来确定输入结尾,读取并丢弃换行符,比如你输入"Jud"后按下了Enter键,Enter键输入的换行符’\n’是不会被保存的,取而代之的是空字符’\0’,最后内存空间也就是"Jud\0"而不是"Jud\n"。丢弃的意思是换行符不仅不保存在内存空间中,也不会留在输入队列中。你下次调用时,看到的第一个字符不再是这个换行符。
  • 特性拓展——拼接方式:cin.getline(name1, size1).getline(name2, size2)
    之所以可以这样做,是由于cin.getline(name, size)返回一个cin对象,该对象随后再被用来调用getline()函数。
3.cin.get()

istream类有另一个名为get()的成员函数,该函数有几种变体(就是函数重载的结果)
(1)第一种变体cin.get(char *s, streamsize n)

  • 作用:读取整行,通过回车键键入的换行符来确定输入结尾
  • 格式:与getline工作方式相似,接受的参数及其参数意义相同
  • 细节:
    ①同上cin.getline()特性①,在读取指定数目的字符或遇到换行符时停止读取。如果参数 n 为20,则函数最多读取19个字符,余下的空间存储自动在结尾处添加的空字符。
    ②不同于cin.getline()特性②,虽然同样通过回车键键入的换行符来确定输入结尾,但是换行符将留在输入队列中,也就是说第2次调用时看到的第一个字符便是这个换行符。因此get()认为已经到达行尾,而没有发现任何可读取的内容。
  • 特性拓展——拼接方式:cin.get(name1, size1).get(name2, size2)

(2)第二种变体cin.get()

  • 作用:读取下一个字符(即使是换行符),是不是有点像C语言中的getchar()?
  • 格式:无参数cin.get(),或者一个参数cin.get(ch)
  • 细节:
    ①不管是无参数还是一个参数,你都可以用来吸收一些字符,最常用就是吸收换行符了
    ②如果是带一个参数的cin.get(ch),你后面也可以合理使用这个字符
  • 特性拓展——拼接方式:cin.get(name1, size1).get()
    这种拼接方式对吸收换行符也很有用
4.为什么不完全使用cin.getline()?他看起来比cin.get()要简单啊

那我先问你一个问题,如何确定停止读取的原因,是由于已经读取了整行,而不是由于数组已经填满呢?
cin.get()可以查看下一个字符,如果是换行符,说明已经读取了整行;否则,说明数组填满,该行中还有其他输入。
而cin.getline()会丢弃该换行符,无法判断。
所以稍微总结下,cin.getline()使用起来更简单,但get()使得检查更仔细

五、我看到有getline(cin, str)这个函数,跟cin.getline()有什么区别么?

这里我们看到没有使用句点表示法,说明这个getline()不是istream类的方法(实际上,不是任何类的方法)。

  • 作用:读取整行,通过回车键键入的换行符来确定输入结尾,并将该输入存在str字符串对象中
  • 格式:getline(cin, string str)
  • 细节:
    ①将cin作为参数,指出到哪里去查找输入。
    ②str实际上是个string对象,不需要指出字符串长度,因为string对象将根据字符串的长度自动调整自己的大小

为什么这个getline不是任何类的方法,而cin.getline()中的getline就是个istream类的方法呢?
因为在引入string类之前很久,C++就有istream类,因此istream的设计没有考虑到string类型,所以在istream类中,没有处理string对象的类方法。

你可能又要问了,既然istream类中没有处理string对象的类方法,为什么cin >> str 可行?
这样处理string对象的代码使用string类的友元函数。这里不详细展开,不想深究的朋友们知道可行也就行了。

顺便推荐下我这篇转载的博文,可以了解下什么样的情况下getline会出现问题getline() 函数用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值