C++ 高级数据类型(二)—— 字符序列

前面基础知识部分讲C++变量类型的时候,我们已经提到过C++的标准函数库提供了一个string类来支持对字符串的操作。然而,字符串实际就是一串连续的字符序列,所以我们也可以用简单的字符数组来表示它。

例如,下面这个数组:

char jenny [20];

是一个可以存储最多20个字符类型数据的数组。你可以把它想象成:

理论上这数组可以存储长度为20的字符序列,但是它也可以存储比这短的字符序列,而且实际中常常如此。例如,jenny 在程序的某一点可以只存储字符串"Hello" 或者"Merry christmas"。因此,既然字符数组经常被用于存储短于其总长的字符串,就形成了一种习惯在字符串的有效内容的结尾处加一个空字符(null character)来表示字符结束,它的常量表示可写为0 或'\0'。

我们可以用下图表示jenny (一个长度为20的字符数组) 存储字符串"Hello" 和"Merry Christmas" :

注意在有效内容结尾是如何用空字符null character ('\0')来表示字符串结束的。 后面灰色的空格表示不确定数值。


初始化以空字符结束的字符序列(Initialization of null-terminated character sequences)

因为字符数组其实就是普通数组,它与数组遵守同样的规则。例如,如果我们想将数组初始化为指定数值,我们可以像初始化其它数组一样用:

char mystring[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

在这里我们定义了一个有6个元素的字符数组,并将它初始化为字符串Hello 加一个空字符(null character '\0')。

除此之外,字符串还有另一个方法来进行初始化:用字符串常量。

在前几章的例子中,字符串常量已经出现过多次,它们是由双引号引起来的一组字符来表示的,例如:

"the result is: "

是一个字符串常量,我们在前面的例子中已经使用过。

与表示单个字符常量的单引号(')不同,双引号 (")是表示一串连续字符的常量。由双引号引起来的字符串末尾总是会被自动加上一个空字符 ('\0') 。

因此,我们可以用下面两种方法的任何一种来初始化字符串mystring:

char mystring [ ] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char mystring [ ] = "Hello";

在两种情况下字符串或数组mystring都被定义为6个字符长(元素类型为字符char):组成Hello的5个字符加上最后的空字符('\0')。在第二种用双引号的情况下,空字符('\0')是被自动加上的。

注意:同时给数组赋多个值只有在数组初始化时,也就是在声明数组时,才是合法的。象下面代码现实的表达式都是错误的:

mystring = "Hello";
mystring[ ] = "Hello";
mystring = { 'H', 'e', 'l', 'l', 'o', '\0' };

因此记住:我们只有在数组初始化时才能够同时赋多个值给它。其原因在学习了指针(pointer)之后会比较容易理解,因为那时你会看到一个数组其实只是一个指向被分配的内存块的常量指针(constant pointer),数组自己不能够被赋予任何数值,但我们可以给数组中的每一个元素赋值。

在数组初始化的时候是特殊情况,因为它不是一个赋值,虽然同样使用了等号(=) 。不管怎样,牢记前面标下画线的规则。


给字符序列的赋值

因为赋值运算的lvalue 只能是数组的一个元素,而不能使整个数组,所以,用以下方式将一个字符串赋给一个字符数组是合法的:

mystring[0] = 'H';
mystring[1] = 'e';
mystring[2] = 'l';
mystring[3] = 'l';
mystring[4] = 'o';
mystring[5] = '\0';

但正如你可能想到的,这并不是一个实用的方法。通常给数组赋值,或更具体些,给字符序列赋值的方法是使用一些函数,例如strcpy。strcpy (string copy) 在函数库cstring (string.h) 中被定义,可以用以下方式被调用:

strcpy (string1, string2);

这个函数将string2 中的内容拷贝给string1。string2 可以是一个数组,一个指针,或一个字符串常量constant string。因此用下面的代码可以将字符串常量"Hello"赋给mystring:

strcpy (mystring, "Hello");

例如:

// setting value to string
#include <iostream.h>
#include <string.h>

int main () {
char szMyName [20];
strcpy (szMyName,"J. Soulie");
cout << szMyName;
return 0;
}
J. Soulie

注意:我们需要包括头文件才能够使用函数strcpy

虽然我们通常可以写一个像下面setstring一样的简单程序来完成与cstring 中strcpy同样的操作:

// setting value to string
#include <iostream.h>

void setstring (char szOut [ ], char szIn [ ]) {
int n=0;
do {
szOut[n] = szIn[n];
} while (szIn[n++] != '\0');
}

int main () {
char szMyName [20];
setstring (szMyName,"J. Soulie");
cout << szMyName;
return 0;
}
J. Soulie

另一个给数组赋值的常用方法是直接使用输入流(cin)。在这种情况下,字符序列的值是在程序运行时由用户输入的。

当cin 被用来输入字符序列值时,它通常与函数getline 一起使用,方法如下:

cin.getline ( char buffer[], int length, char delimiter = ' \n');

这里buffer 是用来存储输入的地址(例如一个数组名),length 是一个缓存buffer 的最大容量,而delimiter 是用来判断用户输入结束的字符,它的默认值(如果我们不写这个参数时)是换行符newline character ('\n')。

下面的例子重复输出用户在键盘上的任何输入。这个例子简单的显示了如何使用cin.getline来输入字符串:

// cin with strings
#include <iostream.h>

int main () {
char mybuffer [100];
cout << "What's your name? ";
cin.getline (mybuffer,100);
cout << "Hello " << mybuffer << ".\n";
cout << "Which is your favourite team? ";
cin.getline (mybuffer,100);
cout << "I like " << mybuffer << " too.\n";
return 0;
}
What's your name? Juan
Hello Juan.
Which is your favourite team? Inter Milan
I like Inter Milan too.

注意上面例子中两次调用cin.getline 时我们都使用了同一个字符串标识 (mybuffer)。程序在第二次调用时将新输入的内容直接覆盖到第一次输入到buffer 中的内容。

你可能还记得,在以前与控制台(console)交互的程序中,我们使用extraction operator (>>) 来直接从标准输入设备接收数据。这个方法也同样可以被用来输入字符串,例如,在上面的例子中我们也可以用以下代码来读取用户输入:

cin >> mybuffer;

这种方法也可以工作,但它有以下局限性是cin.getline所没有的:

  • 它只能接收单独的词(而不能是完整的句子),因为这种方法以任何空白符为分隔符,包括空格spaces,跳跃符tabulators,换行符newlines和回车符arriage returns。
  • 它不能给buffer指定容量,这使得程序不稳定,如果用户输入超出数组长度,输入信息会被丢失。

因此,建议在需要用cin来输入字符串时,使用cin.getline来代替cin >>。


字符串和其它数据类型的转换(Converting strings to other types)

鉴于字符串可能包含其他数据类型的内容,例如数字,将字符串内容转换成数字型变量的功能会有用处。例如一个字符串的内容可能是"1977",但这一个5个字符组成序列,并不容易转换为一个单独的整数。因此,函数库cstdlib (stdlib.h) 提供了3个有用的函数:

  • atoi: 将字符串string 转换为整型int
  • atol: 将字符串string 转换为长整型long
  • atof: 将字符串string 转换为浮点型float

所有这些函数接受一个参数,返回一个指定类型的数据(int, long 或 float)。这三个函数与cin.getline 一起使用来获得用户输入的数值,比传统的cin>> 方法更可靠:

// cin and ato* functions
#include <iostream.h>
#include <stdlib.h>

int main () {
char mybuffer [100];
float price;
int quantity;
cout << "Enter price: ";
cin.getline (mybuffer,100);
price = atof (mybuffer);
cout << "Enter quantity: ";
cin.getline (mybuffer,100);
quantity = atoi (mybuffer);
cout << "Total price: " << price*quantity;
return 0;
}
Enter price: 2.75
Enter quantity: 21
Total price: 57.75

字符串操作函数(Functions to manipulate strings)

函数库cstring (string.h) 定义了许多可以像C语言类似的处理字符串的函数 (如前面已经解释过的函数strcpy)。这里再简单列举一些最常用的:

  • strcat: char* strcat (char* dest, const char* src); //将字符串src 附加到字符串dest 的末尾,返回dest。
  • strcmp: int strcmp (const char* string1, const char* string2); //比较两个字符串string1 和string2。如果两个字符串相等,返回0。
  • strcpy: char* strcpy (char* dest, const char* src); //将字符串src 的内容拷贝给dest,返回dest 。
  • strlen: size_t strlen (const char* string); //返回字符串的长度。

注意:char* 与char[] 相同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 高级数据类型(三)—— 指针

我们已经明白变量其实是可以由标识来存取的内存单元。但这些变量实际上是存储在内存中具体的位置上的。对我们的程序来说&#xff0c;计算机内存只是一串连续的单字节单元(1byte cell)&#xff0c;即最小数据单位&#xff0c;每一个单元有一个唯一地址。 计算机内存就好像城市中…

C++ 高级数据类型(四)—— 动态内存分配

到目前为止&#xff0c;我们的程序中我们只用了声明变量、数组和其他对象&#xff08;objects&#xff09;所必需的内存空间&#xff0c;这些内存空间的大小都在程序执行之前就已经确定了。但如果我们需要内存大小为一个变量&#xff0c;其数值只有在程序运行时 (runtime)才能确…

C++ 高级数据类型(六)—— 自定义数据类型

前面我们已经看到过一种用户&#xff08;程序员&#xff09;定义的数据类型&#xff1a;结构。除此之外&#xff0c;还有一些其它类型的用户自定义数据类型&#xff1a; 定义自己的数据类型 (typedef) C 允许我们在现有数据类型的基础上定义我们自己的数据类型。我们将用关键字…

JSF 2.0/2.1 生命周期简介

2019独角兽企业重金招聘Python工程师标准>>> 标准的生命周期划分为六个阶段&#xff1a;恢复视图、应用请求值、验证、更新模型值、调用应用程序、渲染响应&#xff0c;每一个阶段都可以直接跳转到最后一个阶段或者结束。 转载于:https://my.oschina.net/koulikoro/…

C++ 面向对象(一)—— 类(Classes)

类(class)是一种将数据和函数组织在同一个结构里的逻辑方法。定义类的关键字为class &#xff0c;其功能与C语言中的struct类似&#xff0c;不同之处是class可以包含函数&#xff0c;而不像struct只能包含数据元素。 类定义的形式是&#xff1a; [cpp] view plaincopy class cl…

Seen.js – 使用 SVG 或者 Canvas 渲染 3D 场景

Seen.js 渲染3D场景为 SVG 或者 HTML5 画布。Seen.js 包含对于 SVG 和 HTML5 Canvas 元素的图形功能的最简单的抽象。所有这个库的其它组件都是不用关心将要渲染的上下文的类型。 您可能感兴趣的相关文章你见过吗&#xff1f;9款超炫的复选框&#xff08;Checkbox&#xff09;效…

C++ 面向对象(三)—— 类之间的关系

友元函数(Friend functions) 在前面的章节中我们已经看到了对class的不同成员存在3个层次的内部保护&#xff1a;public&#xff0c; protected 和 private。在成员为 protected 和 private的情况下&#xff0c;它们不能够被从所在的class以外的部分引用。然而&#xff0c;这个…

五年后存储会是什么样子

原文&#xff1a;http://chucksblog.emc.com/chucks_blog/2013/06/what-storage-might-look-like-in-five-years.html注明&#xff1a;本文内容基于 VMware VSAN beta 版本撰写&#xff0c;请访问http://www.vmware.com/products/virtual-san/获得有关正式版本的更新信息。有时…

java.lang.NoClassDefFoundError: javax/transaction/Synchronization (jUnit测试报错)

测试hibernate报错原因项目缺少包在 hibernate 解压目录下找到 jta.jar 文件往项目中添加该 jar 包&#xff0c;即可解决添加方法&#xff1a;【右击项目】-->【构建路径】....来自为知笔记(Wiz)转载于:https://www.cnblogs.com/zhanyao/p/3711322.html

yarn oom问题一例

线上部分job运行失败&#xff0c;报OOM的错误:因为是maptask报错&#xff0c;怀疑是map数量过少&#xff0c;导致oom&#xff0c;因此调整参数&#xff0c;增加map数量&#xff0c;但是问题依然存在。看来和map的数量没有关系。通过jobid查找jobhistory中对应的日志信息&#x…

C++ 高级篇(三)—— 出错处理

本节介绍的出错处理是ANSI-C 标准引入的新功能。如果你使用的C 编译器不兼容这个标准&#xff0c;则你可能无法使用这些功能。 在编程过程中&#xff0c;很多时候我们是无法确定一段代码是否总是能够正常工作的&#xff0c;或者因为程序访问了并不存在的资源&#xff0c;或者由…

C++ 高级篇(一)—— 模板(Templates)

模板(Templates)是ANSI-C 标准中新引入的概念。如果你使用的 C 编译器不符合这个标准&#xff0c;则你很可能不能使用模板。 函数模板( Function templates) 模板(Templates)使得我们可以生成通用的函数&#xff0c;这些函数能够接受任意数据类型的参数&#xff0c;可返回任意类…

PPT到底是天使还是魔鬼?

说老实话&#xff0c;我非常不喜欢那些PPT的培训者一味地鼓吹PPT的重要性&#xff0c;视觉化思维的重要性&#xff0c;PPT在演讲中的重要性等等&#xff0c;我很清楚他们这么说是因为他们必须这么说&#xff0c;因为如果不把PPT的重要性强调一下&#xff0c;谁来上他的课呢&…

ultraedit正则表达式

一般使用ultraedit中的Perl风格的正则表达式&#xff0c;下面是perl正则的基本语法 perl中的元字符如下&#xff1a; ^ 表示一行的开头&#xff1b; $ 表示一行的结尾&#xff1b; ( ) 表示一个匹配块的&#xff0c;可以对匹配上的块通过$1,$2...进行读取&#xff0c;…

微软云介绍

微软云介绍 http://msdn.microsoft.com/zh-cn/ff380142 什么是云开发&#xff1f;&#xff08;概述&#xff09; 云计算是指远程运行并通过 Internet 访问的计算机和应用程序。在云计算中&#xff0c;虚拟机在大型数据中心中运行&#xff0c;并取代了物理 PC 和服务器。通过将许…

IO端口和IO内存的区别及分别使用的函数接口

IO端口和IO内存的区别及分别使用的函数接口 每个外设都是通过读写其寄存器来控制的。外设寄存器也称为I/O端口&#xff0c;通常包括&#xff1a;控制寄存器、状态寄存器和数据寄存器三大类。根据访问外设寄存器的不同方式&#xff0c;可以把CPU分成两大类。一类CPU&#xff08…

Win8 HTML5与JS编程学习笔记(二)

近期一直受到win8应用的Grid布局困扰&#xff0c;经过了半下午加半个晚上的奋斗&#xff0c;终于是弄明白了Grid布局方法的规则。之前我是阅读的微软官方的开发教程&#xff0c;书中没有详细说明CSS3的布局规则&#xff0c;自己鼓捣了半天也是一头雾水&#xff0c;于是又找到了…

Windows下的Qt Creator的安装

采用Qt和Qt creator分别下载和安装的方式&#xff1a;&#xff08;需要手动设置关联Qt和Qt Creator&#xff09; 一、软件下载 从http://qt-project.org/downloads分别下载Qt和Qt Creator&#xff1a; Qt使用4.7.2版本&#xff1a;qt-win-opensource-4.7.2-mingw.exe Qt Creato…

进程 、进程组、会话、控制终端之间的关系

一个进程组可以包含多个进程 进程组中的这些进程之间不是孤立的&#xff0c;他们彼此之间或者存在者父子、兄弟关系&#xff0c;或者在功能有相近的联系。 那linux为什么要有进程组呢&#xff1f;其实提供进程组就是方便管理这些进程。假设要完成一个任务&#xff0c;需要同时并…

Angularjs 通过asp.net web api认证登录

Angularjs 通过asp.net web api认证登录 Angularjs利用asp.net mvc提供的asp.net identity&#xff0c;membership实现居于数据库的用户名/密码的认证登录 环境 Vs.net 2013 Asp.net mvc web api Individual user accounts Angularjs Underscore 新建一个asp.net mvc web api …