C++学习(八)入门篇——复合类型

数组(需要声明以下三点):

(1)存储在每个元素中值的类型

(2)数组名

(3)数组中的元素数

声明数组的通用格式如下:

typeName arrayName[arraySize];arraySize不能是变量;

float loans[20]表示loans数组是使用float类型创建的,C++数组从0开始编号。

编译器不会检查使用的下标是否有效,如果将一个值赋给不存在的元素months[101]编译器不会指出错误,但会引发问题,破坏数据或代码或使程序异常终止。

程序清单4.1 arrayone.cpp
//arrayone.cpp - - small arrays of integers
#include<iostream>
int main()
{
    using namespace std;
    int yams[3];
    yams[0] = 7;
    yams[1] = 8;
    yams[2] = 6;
    int yamcosts[3] = { 20, 30, 5 };             //只要提供一个用逗号分隔的值列表,并用花括号括起来即可

    cout << "Total yams = ";
    cout << yams[0] + yams[1] + yams[2] << endl;
    cout << "The package with " << yams[1] << " yams costs ";
    cout<<yamcosts[1]<<    " cents per yam.\n";
    int total = yams[0] * yamcosts[0] + yams[1] * yamcosts[1] + yams[2] * yamcosts[2];
    total = total + yams[2] * yamcosts[2];
    cout << "The total yam expense is " << total << " cents.\n";

    cout << "\nSize of yams array = " << sizeof yams;      //整个数组字节数
    cout << " bytes.\n";
    cout << "Size of one elements = " << sizeof yams[0];   //一个元素字节数
    cout << "bytes.\n";
    cin.get();

}

得到:

1.数组的初始化规则

只有在定义数组时才能初始化

int cards[4] = {3,6,8,10};

int hand [4];

hand [4] = {5,6,7,9};    不允许

hand =cards;               不允许

初始化数组时,提供的值可以少于数组的元素数目,其他元素将被设置为0,将数组所以元素都初始化为0,只要让第一个元素为0即可

long totals[500] = {0};

如果初始化数组时方括号为空,C++编译器将计算元素个数

short things[] ={1,5,3,8}

编译器将使things数组包含4个元素

如果主要关心的是程序,而不是自己知道数组的大小,可以这样做

short things [ ] ={1,5,3,8};

int num_elements = sizeof things / sizeof (short);

C++初始化新增了一些新功能

比如省略=

double earning[4] {1.2e4, 1.6e4, 1.1e4,1.7e4};

其次可不在大括号里包含任何东西,这将把所有元素都设置为零

unsigned int counts [10] = { };

float balances [100] { };

第三,列表初始化禁止缩窄转换

long plifs [ ] ={25,92,3.0};     不行,因为浮点数转化为整型是缩窄

char slifs [4] {‘h‘,‘i‘,1122011, ‘\0‘};    不行,因为1122011超过了char的取值范围

char tlifs  [4] {‘h‘,‘i‘,112,‘\0‘};     可以

2.字符串

C++处理字符串的方式有两种,C风格字符串和基于string类库的方法。

C字符串具有一种特殊的性质,以空字符结尾,空字符被写作\0,ASCII码为0,用来标记字符串的结尾。

看以下两个声明:

char dog[8] = {‘b’,‘e’,‘a’,‘u’,‘x’,‘ ’,‘I’,‘I’};   是字符串

char cat[8] ={‘f ‘, ‘a‘, ‘t‘, ‘e‘, ‘s‘ , ‘s‘, ‘a‘, ‘\0‘};                 不是字符串

空字符对C风格字符串至关重要,用cout显示cat字符串,将显示前7个字符,遇到空格后停止,而dog将打印8个,并接着将内存中随后各个字节解释为要打印的字符,知道遇到空字符为止。

也可以使用以下方法:

char bird[11] ="Mr.Cheeps";

char fish[ ] ="Bubbles";

用引号括起的字符串隐式的包括结尾的空字符

在确定存储字符串所需的最短数组时,别忘了将结尾的空字符计算在内。

注意:字符串常量(使用双引号)不能与字符常量(使用单引号)互换

‘S‘只是字符串编码的简写方式,在ASCII只是83的另一种写法

char shirt_size =‘S’;

将83赋给了shirt_size

“S”不是字符常量,而是S和\0组成的字符串,“S”实际表示字符串所在的内存地址

char shirt_size = "S";

将一个内存地址赋给shirt_size。

由于地址在C++中属于一个独立的类型,C++编译器不允许这种不合理的做法

C++允许拼接字符串字面值,即将两个用引号括起的字符串合并为一个。

任何两个由空白(空格、制表符、换行符)分隔的字符串常量都将拼接成一个(不考虑\0)

3.在数组中使用字符串

最常用的两个方法——将数组初始化为字符串常量,将键盘或文件输入读入到数组中。

标准头文件cstring提供了该函数以及很多与字符串相关的其他函数的声明

程序清单4.2  string.cpp
//strings.cpp - - storing strings in an array
#include<iostream>
#include<cstring>
int main()
{
    using namespace std;
    const int Size = 15;
    char name1[Size];
    char name2[Size] = "C++owboy";

    cout << "Howdy!I‘m " << name2;
    cout << "! What‘s your name?\n";
    cin >> name1;
    cin.get();
    cout << "Well, " << name1 << ",your name has ";
    cout << strlen(name1) << " lettrs 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:";
    cout << name2 << endl;
    cin.get();
}

输出:

sizeof运算符指的是整个数组的长度,而strlen函数返回的是存储在数组中的字符串的长度,而且是突然类只计算可见的字符,不把空字符计算在内

程序清单4.3  instr1.cpp
//instr1.cpp - - reading more than one string
#include<iostream>
int main()
{
    using namespace std;
    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;
    cin.get();
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name <<".\n";
    cin.get();

}

得到输出:

可以看到,这个程序有个小缺陷,cin使用空白(空格、制表符和换行符)来确定字符串的结束位置。意味着cin在获取字符数组输入时只读取一个单词,并在结尾自动添加空字符。

采用每次读取一行字符串输入来解决(需要面向行而不是面向单词)

面向行的类成员函数:get()和getline()

这两个函数都读取一行输入,直到到达换行符,getline()将丢弃换行符,get()将换行符保留在输入序列中

这里先讨论getline()

通过回车键输入的换行符来确定结尾,cin.getline(name,20)第一个存储输入行的数组名称,第二个是要读取的字符数

如果参数为20,则函数最多读取19个字符,余下空间用来存储自动在结尾处添加的空字符

程序清单4.4  instr2.cpp
//instr2.cpp - - reading more than one word with getline
#include<iostream>
int main()
{
    using namespace std;
    const int ArSize=20;
    char name[ArSize];
    char dessert[ArSize];

    cout<<"Enter your name:\n";
    cin.getline(name, ArSize);
    cout << "Enter your favorite dessert:\n";
    cin.getline(dessert, ArSize);
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << " .\n";
    cin.get();
}

输出结果:

cin.getline()读取字符串并将换行符替换成空字符,不保存换行符

如果使用get()输入

连续两次调用get()时,第一次调用后,换行符将留在输入队列中,第二次调用时遇到第一个字符就是换行符,那么get()认为已到达行尾,无法读取任何内容。

因此采用以下的方式:

cin.get(name,ArSize);  //要将一个字符串放入数组中

cin.get();                         //处理换行符,读取一个字符

cin.get(dessert,ArSize);

另一种使用get()方式将两个类成员函数拼接起来

cin.get(name,ArSize).get();返回一个cin对象,随后被用来调用get()函数,处理掉换行符

cin.getline(name1,ArSize).getline(name2,ArSize);调用效果与两次调用cin.getline()相同

程序清单4.5  instr3.cpp
//instr3.cpp - - reading more than one word with get()&get()
#include<iostream>
int main()
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char dessert[ArSize];

    cout << "Enter your name:\n";
    cin.get(name, ArSize).get();
    cout << "Enter your favorite dessert:\n";
    cin.get(dessert, ArSize).get();
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << ".\n";
    cin.get();
}

得到输出:

get()和getline()相比,输入更仔细,它可以根据查看下一个字符是换行符或者不是来判断,停止读取的原因是已经读取了整行而不是数组已填满。

当get()读取空行侯江设置失效位,意味着接下来的输入将被阻断,可用以下命令恢复:

cin.clear();

当输入字符串比分配空间长,则getline()和get()将余下的字留在输入队列中,而getline还会设置失效位,并关闭后面的输入。

当混合输入数字和面向行的字符串会导致问题

程序清单4.6  numstr.cpp
//numstr.cpp - - following number input with line input
#include<iostream>
int main()
{
    using namespace std;
    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.get();
}

得到结果为:

当cin读取年份,将回车键生成的换行符留在了输入队列中,后面的cin.getline()看到换行符后认为是一个空行

所以在读取地址之前应该先丢弃换行符

可以在

cin >> year;后加
cin.get();

或者(cin.year).get();

则可以正常工作

时间: 2024-10-13 10:59:46

C++学习(八)入门篇——复合类型的相关文章

Vue学习笔记入门篇——组件的内容分发(slot)

本文为转载,原文:Vue学习笔记入门篇--组件的内容分发(slot) 介绍 为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板.这个过程被称为 内容分发 (或 "transclusion" 如果你熟悉 Angular).Vue.js 实现了一个内容分发 API,使用特殊的 'slot' 元素作为原始内容的插槽. 编译作用域 在深入内容分发 API 之前,我们先明确内容在哪个作用域里编译.假定模板为: <child-component> {{ messa

Vue学习笔记入门篇——组件的通讯

本文为转载,原文:Vue学习笔记入门篇--组件的通讯 组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B.它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件.然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的.这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性.在 Vue 中,父子组件的关系可以总结为 props down, events up.父组件通过 props 向下传递

storm学习之入门篇(一)

海量数据处理使用的大多是鼎鼎大名的hadoop或者hive,作为一个批处理系统,hadoop以其吞吐量大.自动容错等优点,在海量数据处理上得到了广泛的使用.但是,hadoop不擅长实时计算,因为它天然就是为批处理而生的,这也是业界一致的共识.否则最近这两年也不会有s4,storm,puma这些实时计算系统如雨后春笋般冒出来.先抛开s4,storm,puma这些系统不谈,我们首先来看一下,如果让我们自己设计一个实时计算系统,我们要解决哪些问题: 1.低延迟.都说了是实时计算系统了,延迟是一定要低的

Swift入门篇-基本类型(1)

博主语文一直都不好(如有什么错别字,请您在下评论)望您谅解,没有上过什么学的 今天遇到了一个很烦的事情是,早上10点钟打开电脑,一直都进入系统(我的系统  mac OS X Yosemite 10.10 系统),一直卡在登陆界面上进不去,心里想苹果新系统这么脆弱,现在很多软件不兼容就算了,搞的我还进不了系统,真是郁闷.然后在google 上搜索,google也打不开(真是悲催, 据说"组织" 要开会,大家先不要用google).然后用"度娘"搜索,搜了半天,终于找到

PHP学习笔记——入门篇(1)——语法&变量

基础 PHP 语法 PHP 脚本可放置于文档中的任何位置. PHP 脚本以 <?php 开头,以 ?> 结尾: PHP 文件通常包含 HTML 标签以及一些 PHP 脚本代码. 注释:PHP 语句以分号结尾(;).PHP 代码块的关闭标签也会自动表明分号(因此在 PHP 代码块的最后一行不必使用分号). PHP 支持三种注释: //单行注释 #单行注释 /*多行注释*/ PHP 大小写敏感区分: 在 PHP 中,所有用户定义的函数.类和关键词(例如 if.else.echo 等等)都对大小写不

Swift入门篇-基本类型(3)

一:元组 格式 变量或常量关键字 元组变量 = ( 变量,变量, -) 说明: 1: 元组变量还是一个变量,只不过表现方式和其他变量不一样 2:()括号里面可以放入N个变量组成 例子: import Foundation /* A是元组变量,()里面放着 整形 和字符串 元组类型为 整形和字符串 组成 */ var A = (1,"swift")//元组变量A 由 整形和字符串 组成 println(A) 运行结果 (1, swift) mport Foundation var B =

Swift入门篇-基本类型(2)

现在我也在学习Swift语言,常常去逛很多苹果社区和论坛,看到了圈子很多奇怪的现象,发现很多人都赶忙去翻译 Swift书籍 和 发布Swift的视频 .他们这种对新知识的探索精神我本人是很佩服的.但是我也觉得语言都没有发布几天,就赶忙去翻译书籍和Swift视频,然后讲SWift语言多么优美和多么好.我个人觉得他们都没有静下心来,去敲代码和研究Swift语言到底好在那里,而急于去翻译 未免也太草率了. 今天主要分享的是 swift中基本类型的 下半部分.如果您对 SWift 中变量和常量 不是很清

Vue学习笔记入门篇——组件的使用

本文为转载,原文:Vue学习笔记入门篇--组件的使用 组件定义 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展. 组件使用 注册 注册一个全局组件,你可以使用 Vue.component(tagName, options).组件在注册之后,便可以在父实例的模块中以自定义元素 的形式使用.

storm学习之入门篇(二)

Strom的简单实现 Spout的实现 对文件的改变进行分开的监听,并监视目录下有无新日志文件添加. 在数据得到了字段的说明后,将其转换成tuple. 声明Spout和Bolt之间的分组,并决定tuple发送给Bolt的途径. Spout中open.nextTuple和delcareOutputFields方法的逻辑: declareOutputFileds()决定了tuple发射的格式,这样的话Bolt就可以用类似的方法将tuple译码.Spout持续对日志文件的数据的变更进行监听,一旦有添加