创建和使用数组。
创建和使用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类的一个方法。
标签:string,get,复合,C++,cin,字符串,数组,类型 From: https://www.cnblogs.com/yiweshen/p/17124868.htmlC函数使用参数来指出要使用哪个字符串,而C++ string 类对象使用对象名和句点运算符来指出要使用哪个字符串。