首页 > 其他分享 >第4章 复合类型

第4章 复合类型

时间:2023-02-15 21:55:06浏览次数:28  
标签:string get 复合 C++ cin 字符串 数组 类型

创建和使用数组。
创建和使用C-风格字符串,string类字符串。
使用方法getline()和get()读取字符串。
混合输入字符串和数字。
创建和使用结构,共用体,枚举,指针。
使用new和delete管理动态内存。
创建动态数组,动态结构。
自动存储、静态存储和动态存储。
vector和array类简介。

4.1 数组

数组(array)是一种数据格式,能够存储多个同类型的值。
创建数组使用声明语句,即元素类型 数组名[元素数目]。元素数目必须是整型常量,或 const 值,或常量表达式。
在C++中,可以通过修改简单变量的声明,添加中括号(其中包含元素数目)来完成数组声明。
可以单独访问数组元素。方法是使用下标或索引来对元素进行编号。 C++数组从0开始编号。C++使用带索引的方括号表示法来指定数组元素。

C++允许在声明语句中初始化数组元素。只需提供一个用逗号分隔的值列表(初始化列表),并将它们用花括号括起即可。
列表中的空格是可选的。
如果没有初始化函数中定义的数组,则其元素值将是不确定的,这意味着元素的值为以前驻留在该内存单元中的值。

        int yams[3];
	yams[0] = 7;
	yams[1] = 8;
	yams[2] = 6;

	int yamcosts[3] = { 20, 30, 5 };
	cout << "Total yams = " << yams[0] + yams[1] + yams[2] << endl;    //21
	cout << "The package with " << yams[1] << " yams costs";            //8
	cout << yamcosts[1] << " cents per yam. \n";                        //30

	int total = yams[0] * yamcosts[0] + yams[1] * yamcosts[1];         //140 + 240
	total = total + yams[2] + yamcosts[2];                             //380 + 11
	cout << "The total yam expense is " << total << " cents.\n";

	cout << "\n Size of yams array = " << sizeof yams << " bytes.\n";   //12
	cout << "Size of one element = " << sizeof yams[0] << " bytes.\n";  //4

sizeof运算符返回类型或数据对象的长度(单位为字节)。
注意,如果将sizeof运算符用于数组名,得到的将是整个数组中的字节数。但如果将sizeof用于数组元素,则得到的将是元素的长度(单位为字节)。
这表明yams是一个数组,而yams[1]只是一个int变量。

4.1.2 数组的初始化规则
只有在定义数组时才能使用初始化,此后就不能使用了,也不能将一个数组赋给另一个数组:
如果只对数组的一部分进行初始化,则编译器将把其他元素设置为0。
如果初始化为{1}而不是{0},则第一个元素被设置为1,其他元素都被设置为0。
如果初始化数组时方括号内([])为空, C++编译器将计算元素个数。

int cards [4] = {3, 6, 8 10}; // okay
int hand[4];                   //okay
hand [4] = {s, 6, 7, 9} ;     //not allowed
hand= cards;                 // not allowed

4.1.3 C++11数组初始化方法
C++11中的列表初始化新增了一些功能。
首先,初始化数组时,可省略等号(=):
其次,可不在大括号内包含任何东西,这将把所有元素都设置为零:
第三,列表初始化禁止缩窄转换。

C++标准模板库(STL)提供了一种数组替代品 —— 模板类vector,而C++11新增了模板类array。

4.2 字符串

字符串是存储在内存的连续字节中的一系列字符。
C++处理字符串的方式有两种。
第一种来自C语言,常被称为C-风格字符串(C-stylestring)。
另一种基于string类库的方法。

字符串存储在 char 数组中,以空字符(null character)结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾。
第一种的第一是使用大量单引号,且必须记住加上空字符。
第一种的第二是将字符数组初始化为字符串的方法—只需使用一个用引号括起的字符串即可,这种字符串被称为字符串常量(string constant)或字符串字面值(string literal)

char dog [8] = { 'b', 'e', 'a'};    // not a string!
char cat[B] = {'f','a','t','\0'} ;  // a string!

char bird [11] = "Mr. Cheeps" ;
char fish(] = “Bubblesir";

注意,字符串常量(使用双引号)不能与字符常量(使用单引号)互换。字符常量(如'S')是字符串编码的简写表示。
在ASCII系统上, 'S'只是83的另一种写法。但"S"不是字符常量,它表示的是两个字符(字符S和\0)组成的字符串。

char shirt_size = 'S';
cahr shirt_size = "S";

更糟糕的是, "S"实际上表示的是字符串所在的内存地址。因此,上面的语句试图将一个内存地址赋给shirt_size:
由于地址在C++中是一种独立的类型,因此C++编译器不允许这种不合理的做法。

4.2.1 拼接字符串常量
任何两个由空白(空格、制表符和换行符)分隔的字符串常量都将自动拼接成一个。
注意:拼接时不会再被拼接的字符串之间添加空格。第一个字符串中的\0字符将被第二个字符串的第一个字符取代。

4.2.2 在数组中使用字符串
一种是将数组初始化为字符串常量、将键盘或文件输入读入到数组中。
另一种是它将一个数组初始化为用引号括起的字符串,并使用cin将一个输入字符串放到另一个数组中。

        const int Size = 9;
	char name1[Size];
	char name2[Size] = "C++owboy";

	cout << "Howdy! I`m " << name2 << "What`s your name?\n" ;
	cin >> name1;
	cout << "Well,  " << name1 << "  , your name has "<< strlen(name1) << " Letters and is stored\n" ;
	cout << "in an array of" << sizeof(name1) << " bytes.\n" ;
	cout << "Your initial is " << name1[0] << ".\n";
	name2[3] = '\0';
	cout << "Here are the first 3 characters of my name: "<< name2 << endl;

sizeof运算符指出整个数组的长度:9字节,
但strlen()函数返回的是存储在数组中的字符串的长度,而不是数组本身的长度。
另外,strlen()只计算可见的字符,而不把空字符计算在内。

Howdy! I`m C++owboyWhat`s your name?
abcdefghij                                                            //cin 10个字符
Well,  abcdefghij  , your name has 10 Letters and is stored
in an array of  9   bytes.
Your initial is  a .
Here are the first 3 characters of my name: C++

4.2.3 字符串输入

        const int ArSize = 20;
	char name[ArSize];
	char dessert[ArSize];

	cout << "Enter your name: \n";
	cin >> name;
	cout << "Enter your favorite dessert:\n";
	cin >> dessert;
	cout << "I have some delicious " << dessert << "  for you, " << name << ".\n";

cin使用空白(空格、制表符和换行符)来确定字符串的结束位置,cin在获取字符数组输入时只读取一个单词。
读取该单词后,cin将该字符串放到数组中,并自动在结尾添加空字符。

Enter your name:
yyds
Enter your favorite dessert:
apple
I have some delicious apple  for you, yyds.

Enter your name:
yyds apple
Enter your favorite dessert:
I have some delicious apple  for you, yyds.

4.2.4 每次读取一行字符串输入
istream中的类(如cin)提供了一些面向行的类成员函数:getline()和get()。
这两个函数都读取一行输入,直到到达换行符。
然而,随后getline()将丢弃换行符,而get()将换行符保留在输入序列中。

getline()成员函数在读取指定数目的字符 遇到 换行符时 停止读取。
getline()函数每次读取一行。它通过换行符来确定行尾,但不保存换行符。相反,在存储字符串时,它用 空字符 来替换换行符。

istream类有另一个名为get()的成员函数,该函数有几种变体。
其中一种变体的工作方式与getline()类似,它们接受的参数相同,解释参数的方式也相同,并且都读取到行尾。

但get并不再读取并丢弃换行符,而是将其留在输入队列中。

假如连续两次调用get(),它便不能跨过该换行符读取第二次输入的字符串。

另一种变体使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符),因此可以用它来处理换行符,为读取下一行输入做好准备。

cin.get(name, ArSize);
cin.get();
cin.get(dessert, ArSize);

最精妙是将两个类成员函数拼接起来(合并),cin.get(name,ArSize)返回一个cin对象,该对象随后将被用来调用get()函数。
与两次调用 cin.getline()效果相同。

cin.get(name, ArSize).get();
cin.qetline(namel, ArSize).qetline(name2, ArSize);

注意,C++允许函数有多个版本,条件是这些版本的参数列表不同。
如果使用的是cin.get(name,ArSize),则编译器知道是要将一个字符串放入数组中,因而将使用适当的成员函数。
如果使用的是cin.get(),则编译器知道是要读取一个字符。

3.空行和其他问题
当getline()或get()读取空行时,将发生什么情况?最初的做法是,下一条输入语句将在前一条getline()或get()结束读取的位置开始读取;
但当前的做法是,当get()(不是getline())读取空行后将设置失效位(failbit)。
这意味着接下来的输入将被阻断,但可以用下面的命令来恢复输入:

cin.clear();

另一个潜在的问题是,输入字符串可能比分配的空间长。
如果输入行包含的字符数比指定的多,则getline()和get()将把余下的字符留在输入队列中,而getline()还会设置失效位,并关闭后面的输入。

4.2.5 混合输入字符串和数字

        cout << "What year was your house built?\n";
	int year;
	cin >> year;
	cout << "What is its street address?\n";
	char address[80];
	cin.getline(address, 80);
	cout << "Year built: " << year << endl;
	cout << "Address: " << address << endl;
	cout << "Done!\n";

cin.getline()看到换行符后,将认为是一个空行,并将一个空字符串赋给address数组。

What year was your house built?
1977 1978 1999
What is its street address?
Year built: 1977
Address:  1978 1999
Done!

解决之道是,在读取地址之前先读取并丢弃换行符。
一种是使用 get() 过渡
一种是接受一个 char 参数的get()

C++程序常使用指针(而不是数组)来处理字符串。

4.3 string 类简介

ISO/ANSI C++98标准通过添加 string 类扩展了C++库,因此现在可以 string类型的变量(使用C++的话说是对象)而不是字符数组来存储字符串。
string类使用起来比数组简单,同时提供了将字符串作为一种数据类型的表示方法。
要使用string类,必须在程序中包含头文件string。 string类位于名称空间std中,因此您必须提供一条using编译指令,或者使用std::string来引用它。 string类定义隐藏了字符串的数组性质,让您能够像处理普通变量那样处理字符串。

string对象字符数组之间的主要区别是,可以将 string 对象声明为简单变量,而不是数组:

char charr1[20];
char charr2[20] = "jaguar";
string str1;
string str2 = "panther";

cout << "Enter a kind of feline: ";
cin >> charr1;
cout << "Enter another kind of feline: ";
cin >> str1;                                  //类设计让程序能够自动处理string的大小。
cout << "Here are some felines:\n";
cout << charr1 << "  " << charr2 << "  " << str1 << " " << str2 << "\n";
cout << "The third letter in " << charr2 << " is  " << charr2[2] << endl;
cout << "The third letter in  " << str2 << "  is  " << str2[2] << endl;

占位符???并没有#include 难道是内置 或是 ?

Enter a kind of feline: ocelot
Enter another kind of feline: tiger
Here are some felines:
ocelot  jaguar  tiger panther
The third letter in jaguar is  g
The third letter in  panther  is  n

4.3.1 C++11 字符串初始化
C++11也允许将列表初始化用于C-风格字符串和string对象:
string类时,可以把 string 对象赋给另一个 string 对象;
可以使用运算符 + 将两个 string 对象合并起来,还可以使用运算符 += 将字符串附加到 string 对象的末尾。

#include <String>
#include <cstring>
// 比较string对象和字符数组技术
char charr1[20];
char charr2[20] = "jaguar";
string str1;
string str2 = "panther";

str1 = str2;				//str1 = "panther"
strcpy(charr1, charr2);		

str1 += "paste";			//str1 = "pantherpaste"
strcat(charr1, "juice");

auto len1 = str1.size();
auto len2 = strlen(charr1);

cout << "The string " << str1 << "  contains " << len1 << "  characters.\n";
cout << "The string " << charr1 << "  cintains " << len2 << "  characters.\n";

将上述 strcpy 替换成 srcpy_s
strcat 替换成 strcat_s 即可。。。。

The string pantherpaste  contains 12  characters.
The string jaguarjuice  cintains 11  characters.

函数strcat()试图将全部12个字符复制到数组site中,这将覆盖相邻的内存。这可能导致程序终止,或者程序继续运行,但数据被损坏。string类具有自动调整大小的功能,从而能够避免这种问题发生。
C函数库确实提供了与strcat()和strcpy()类似的函数strncat()strncpy(),它们接受指出目标数组最大允许长度的第三个参数,因此更为安全,但使用它们进一步增加了编写程序的复杂度。

两种确定字符串中字符数的方法
函数strlen( )是一个常规函数,它接受一个C-风格字符串作为参数,并返回该字符串包含的字符数。
str1是一个对象,而size()是一个类方法。方法是一个函数,只能通过其所属类的对象进行调用。
在这里, str1是一个string对象,而size()是string类的一个方法。

C函数使用参数来指出要使用哪个字符串,而C++ string 类对象使用对象名和句点运算符来指出要使用哪个字符串。

标签:string,get,复合,C++,cin,字符串,数组,类型
From: https://www.cnblogs.com/yiweshen/p/17124868.html

相关文章

  • vue3数据类型ref,Reactive,shallowRef,shallowReactive基本用法
    1.ref用于创建基础类型的响应式,也可以创建引用类型的响应式.2.ref对于引用类型,底层也是转换为reactive来进行响应式处理3.ref创建的响应式数据在脚本中需要通过.......
  • APS.NET Core 6.0Json任何类型读取到字符串属性The JSON value could not be converte
    在升级.netsdk到6.0版本后出现TheJSONvaluecouldnotbeconvertedtoSystem.String.原因是我代码定义的类型是string,但是传参的时候写了int,publicoverridevoidC......
  • 复合数据类型
    (1)枚举类型定义:type枚举类型标识符=(标识符1,标识符2,…,标识符n)枚举元素只能是标识符;定义枚举类型时列出的所有枚举元素构成了这种枚举类型的值域(取值范围)。例如......
  • HTML 元素类型
    一、按块级元素、行级元素和行内块级元素分类HTML元素可以分为块级元素和行内元素(又称行级元素),它们的主要区别在于它们在文档流中所占据的空间和如何与其他元素相互作用。......
  • [经验] 使用python列出文件夹下指定类型的文件
    要列出文件夹下指定类型的文件,可以使用Python的内置模块os和glob。下面是一个列出指定类型文件的示例:importosimportglobfolder_path="/path/to/folder"#文件......
  • 无法确定条件表达式的类型,因为'lambda expression'和'lambda expression'之间没有隐
    无法确定条件表达式的类型,因为'lambdaexpression'和'lambdaexpression'之间没有隐式转换Ric*_*d77  5 c# linq 我收集了一些笔记.根据请求这些笔记的UI,我想......
  • 重学Java-第五章 Java数据类型
    5.1概述​ Java语言的数据类型可以分为基本数据类型(primitivedatatype)和引用型数据类型(referencedatatype)5.2基本数据类型5.2.1整数类型​ Java语言提供了......
  • elasticsearch之日期类型有点怪
    一、Date类型简介elasticsearch通过JSON格式来承载数据的,而JSON中是没有Date对应的数据类型的,但是elasticsearch可以通过以下三种方式处理JSON承载的Date数据符合特定格......
  • JavaSE5️⃣核心类 - 包装类型
    1、包装类型Java数据类型基本类型:byte,short,int,longfloat,doublechar,boolean引用类型:八种基本类型之外的所有数据类型。包含所有class和interface类型。......
  • golang 复杂数据类型
    1.指针一个指针变量指向了一个值的内存地址,类似于变量和常量,在使用指针前你需要声明指针。每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。使用&字符......