C++疑惑解答总结(一)
C++现在是我很常用的一门编程语言,不过使用也限于oj、leetcode等描述算法的方面,真正用于工程的时候较少,导致对C++的部分用法并不熟悉,下面就是我在用C++常常会有的疑惑及解答吧:(参考《C++ Primer Plus》第六版)
目录:
一、字符串
二、共用体
三、枚举
四、指针
一、字符串
疑惑:可能是Java最开始学的,导致在写算法时,用C++对字符串进行处理时用得太不熟悉
C++处理字符串的方式有两种。第一种来自C语言,常被成为C-风格字符串;另一种基于string类库
首先介绍第一种:
字符串是存储在内存的连续字节中的一系列字符,意味着可以将字符串存储在char数组中。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'}; //是一个字符串
将字符数组初始化为字符串的方法(隐式地包含结尾的空字符):
char bird[11]="Mr. Cheeps";(因此,这里只能到10,而不能到11,因为有隐含的空字符)
所以在确定存储字符串所需的最短数组时,别忘了将结尾的空字符包含在内
char fish[]="Bubbles";
下面这种情况是不被允许的:
char shirt_size="S";
"S"不是字符常量,它表示的是两个字符(字符S和\0)组成的字符串,更糟的是,"S"实际上表示的是字符串所在的内存地址
而用string类时,遍历string时,也不能使str[i]与""的进行比较,也只能与单引号进行比较,否则会报ISO C++ forbids comparison between pointer and integer [-fpermissive]错误,原因是一样的!!!
在数组中使用字符串:
#include <iostream>
#include<cstring>
using namespace std;int main()
{char bird[11];cin>>bird;cout << "Hello " <<bird<< endl;cout<<"Size of:"<<sizeof(bird)<<endl;cout<<"Length:"<<strlen(bird)<<endl;return 0;
}
注:sizeof()运算符指出整个数组的长度,而strlen()函数返回的是存储在数组中的字符串的长度,strlen()只计算可见的字符,不把空字符计算在内
存储在char数组中的字符串可以用下标方式来访问数组中的每个字符
探讨cin:
看下面的程序及输出:
#include <iostream>
#include<cstring>
using namespace std;int main()
{const int ArSize=20;char name[ArSize];char dessert[ArSize];cout<<"输入你的名字:"<<endl;cin>>name;cout<<"输入你最喜爱的点心的名字:"<<endl;cin>>dessert;cout<<"我有一些"<<dessert<<"给你:"<<name<<endl;
}
我们发现输入完名字后程序直接运行完毕,而Dreeb被当作点心的名字了
cin是如何确定已完成字符串输入呢?由于不能通过键盘输入空字符,因此cin需要用别的方法来确定字符串的结尾位置。cin使用空白(空格、制表符和换行符)来确定字符串的结尾位置。因此这个例子的实际结果就是,cin把Alistair放到name数组,被当作第一个字符串,将Dreeb留在输入队列中。
解决方案有:
1、cin.getline(数组名称,要读取的字符数)读取整行,以回车键输入的换行符确定结尾
如果要读取的字符数为20,则getline最多读取19个字符
2、cin.get()
一种格式是与getline一样的参数,一种是空的,可以用来处理多次读入之间的换行符的处理:
假设我们连续两次调用get:
cin.get(name,ArSize);
cin.get(dessert,ArSize);
由于第一次调用后,换行符留在输入队列中,因此第二次调用时看到的第一个字符便是换行符,因此get认为已经到达行尾,而没有任何可读取的内容。
解决方案是:
cin.get(name,ArSize);
cin.get();
cin.get(dessert,ArSize);
另一种解决方案是cin.get(name,ArSize).get();
介绍第二种:string类
要使用string类,必须#include<string>
基本使用:
string str1;
cin>>str1;
若想输入带空格的string,可用string类中的getline(cin,string)与上面的cin.getline()不同,注意使用的对象
从理论上说,可以将char数组视为一组用于存储一个字符串的char存储单元,而string类变量是一个表示字符串的实体
常用到的比如str.length(),string的遍历也可以像char数组一样根据下标来进行
最近在网上又看到了有关string字符串拼接效率的问题:
这里推荐大家看一下这位博主写的https://blog.csdn.net/xiaobaismiley/article/details/25962483
主要说的是不同操作对应的是对象的操作还是引用的操作,下面附上该博主所写的主要内容:
二、共用体
共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。
例如:
union one4all{
int int_val;
long long_val;
double double_val;
};
可以使用one4all变量来存储int、long或double,条件是在不同的时间进行
one4all pail;
pail.int_val=15;
pail.double_val=1.38;此时int值已经丢失了
由于共用体每次只能存储一个值,因此它必须有足够的空间来存储最大的成员,因此它的长度为最大成员的长度。
共用体的用途之一是,当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间。
匿名共用体:
struct widget{
char brand[20];
int type;
union{
long id_num;
char id_char[20];
};
}
widget prize
由于共用体是匿名的,因此id_num和id_char被视为prize的成员,它们的地址相同
三、枚举
见菜鸟教程https://www.runoob.com/w3cnote/cpp-enum-intro.html吧,因为一直好像没用过枚举类,不太懂其用途。
菜鸟教程上这段代码挺好的:
口袋中有红、黄、蓝、白、黑五种颜色的球若干个,每次从口袋中取三个不同颜色的球,统计并输出所有的取法。
分析:由于球只能是五种颜色之一,故可用枚举类型表示球的颜色。设取出的球为i、j、k,根据题意,i、j、k分别可以有五种取值,且i≠j≠k。可以用穷举法,逐个检验每一种可能的组合,从中找出符合要求的组合并输出。
#include<iostream>
#include<iomanip>
using namespace std;
int main(){enum color_set {red,yellow,blue,white,black}; //声明枚举类型colorcolor_set color; int i,j,k,counter=0,loop; //counter是累计不同颜色的组合数for(i=red;i<=black;i++) {for(j=red;j<=black;j++) {if(i!=j){ //前两个球颜色不同for(k=red;k<=black;k++)if(k!=i&&k!=j){ //第三个球不同于前两个,满足要求counter++;if((counter)%22==0){ //每屏显示22行cout<<"请按回车键继续";cin.get();}cout<<setw(15)<<counter;/*下面输出每种取法,一行为一种取法的三个颜色*/for(loop=1;loop<=3;loop++){switch(loop){case 1: color=(color_set) i; break; //第一个是icase 2: color=(color_set) j; break; //第二个是jcase 3: color=(color_set) k; break; //第三个是k}switch(color){case red: cout<<setw(15)<<"red"; break;case yellow:cout<<setw(15)<<"yellow";break;case blue: cout<<setw(15)<<"blue"; break;case white: cout<<setw(15)<<"white"; break;case black: cout<<setw(15)<<"black"; break;}}cout<<endl; //输出一种取法后换行}}}}cout<<"共有:"<<counter<<"种取法"<<endl;return 0;
}
在这里感觉枚举类是可以方便代替int表达更具体明了的含义的
四、指针
C++的指针一直都是很重要的!极具特色!
指针是一个变量。其存储的是值的地址,而不是值本身。
我们先介绍一下&(地址运算符)和*(间接值或解除引用运算符):
int home;&home是它的地址
将*用于指针,可以得到该地址处存储的的值
面向对象编程和过程性编程:
这俩的区别在于OOP强调在运行阶段进行决策,而过程性编程在编译阶段将需求与计划确定下来
1、声明和初始化指针
指针声明时必须指定指向的数据的类型:
char与double的地址看上去没什么区别,但char和double使用的字节数是不同的,它们存储值时使用的内部格式也不同
例:int * p;
* p的类型为int类型,因此我们可以把* p看作一个整体表示一个int值,而*被用于指针,因此p变量本身是指针(地址)是指向* p的地址
声明:
int higgens=5;
int * pt=&higgens;
在这种情况下,被初始化的是指针,而不是它指向的值。也就是说上面的语句将pt(而不是*pt)的值设置为&higgens
这种声明也可以:
int updates=6;
int *p;
p=&updates;
2、指针的危险
在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存,为数据提供空间是一个独立的步骤。
例:
long *fellow;
*fellow=223323;
fellow是一个指针,上述代码没有将地址赋给fellow,而223323被存在哪里了我们也将不会知道,由于fellow没有被初始化,它可能指向任何值,并且程序都将它解释为存储223323的地址。
3、指针和数字
例:
int * pt;
pt=0XB8000000;
0XB8000000一看是地址格式,但这样赋值的话是不对的,
因为其实质上是整数,所以需要将数字转化为适当的地址类型:
pt=(int *)0XB8000000;
4、使用new来分配内存
在程序运行时分配内存
例:
int * pn=new int;
new int告诉程序,需要适合存储int的内存。new运算符根据类型来确定需要多少字节的内存。然后它找到这样的内存,并返回其地址。
声明和赋值:
int *pt=new int;
*pt=1001;
对于指针,需要指出的另一点是,new分配的内存块通常与常规变量声明分配的内存块不同,常规变量和指针所指向的值都存储在被称为栈的内存区域,而new从被称为堆或自由存储区的内存区域分配内存。
5、使用delete释放内存
delete释放的内存块最初是用new分配的
int * ps=new int;
delete ps;
这将释放ps指向的内存,但不会删除指针ps本身,可以将ps指向另一个新分配的内存块。
例如:
int test=10;
int *pt=new int;
*pt=10001;
delete pt;
pt=&test;
cout<<*pt;
根据上面这个例子我们就可以清晰地知道:
new其实就是找一块内存块给指针用,用来存地址,和前面的几种指针声明是一样的,只不过这个内存块在堆或自由存储区中,然后删除了这个内存块,指针(是一种指向)并没有被删除,然后又可以为其找到归宿。
1、一定要配对使用new和delete,否则将会发生内存泄漏;
2、不要尝试释放已经释放的内存块;
3、不能使用delete来释放声明变量所获得的内存(即不是new出来的);
6、使用new来创建动态数组
①使用new创建动态数组
int *psome=new int [10];
new元素返回第一个元素的地址,该地址被赋给指针psome
删除:delete [] psome;
方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素。
②使用动态数组
对于第i个元素,可以使用psome[i]
7、指针、数组
double wages[3] ={10000.0,20000.0,30000.0};
double * pw=wages;//这里的数组名表示数组首元素的地址
double * pw=&wages[0];
8、“->”和“.”的区别
对于访问结构体中的成员变量来说
举个例子:
struct p1{
int year;
};
1、若以这种方式创建变量:
p1 t1;
则访问year时只能是:
t1.year
2、而以这种方式创建变量:
p1 *t1=&temp;
则访问year时只能是t1->year
3、若创建了个数组变量
p1 t2[10];
则访问方式有:
①t2[0].year
②由于数组名是一个指针,则可以采用这种方式(t2+1)->year;(类似于t2[1].year)
不断更新!!!
C++疑惑解答总结(一)相关推荐
- [网摘]---有关int,Int32的疑惑解答
有关int,Int32的疑惑解答 疑惑1:int.System.Int32和int32的区别 1. int32是IL中的基元类型(primary type),int和System.Int32是对int ...
- 有关int,Int32的疑惑解答
疑惑1:int.System.Int32和int32的区别 1. int32是IL中的基元类型(primary type),int和System.Int32是对int32进行了封装. 2. int和S ...
- pd.get_dummies的使用和疑惑解答
pd.get_dummies的使用 参考pandas官网 pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, c ...
- Comparator类中的compare(T o1,T o2)和compareTo()的使用与疑惑解答
这几天做项目刚好遇到需要排序的需求,大概就是你查询一个list,然后list中保存的是map数据,你需要根据map中的若干个数据排序,比如说 List<Map<String, Object ...
- 栈与队列8——求最大子矩阵的大小
题目 给定一个整形矩阵map,其中的值只有0和1,求其中全是1的所有矩形区域中,最大的矩形区域中1的数量,例如:1 1 1 0,其中最大的矩形区域有3个1,返回3. 再如: 1 0 1 1 1 1 1 ...
- 54. spring boot日志升级篇—logback【从零开始学Spring Boot】
在<44. Spring Boot日志记录SLF4J>章节中有关相关的介绍,这里我们在深入的了解下logback框架. 为什么要使用logback ? --在开发中不建议使用System. ...
- Lucene教程具体解释
注明:本文是由本人在开发有关基于lucene资源检索系统时的一点总结,当中一部分是自己依据开发过程自己总结的,也有部分是摘自网络,因无法获取当时摘文的地址,所以在此没有写源地址. 转载请声明出处 Lu ...
- 三菱fb功能块手册中文_技成周报33期 | 三菱、西门子全系列这34个问题值得一看!...
私信小编 " 电工全套 " 获取 三菱+西门子+电工全套电子学习资料(软件.案例.文档.电子书)! 本周学员咨询的常见问题已经汇总好啦,快来看看你的疑惑解答了吗?如果你有其他解决方 ...
- Java程序员从笨鸟到菜鸟全部博客目录
本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.NET/csh624366188 欢迎关注微信账号:java那些事:csh624366188.每天一篇java相关的文章 大 ...
最新文章
- Oracle的分区操持
- 秘钥对使用_使用gitactions持续集成项目实例
- Kubernetes对象中的PersistentVolume、PersistentVolumeClaim和StorageClass的概念关系
- 为什么资本主义生产的一般趋势是资本有机构成的提高?2017-12-26
- 一直想说的,技术职业化
- 如何配置Smarty模板
- 【翻译】 Video Object Tracking using Improved Chamfer Matching and Condensation Particle Filter
- 组态王怎么做超级曲线_组态王显示数据并绘制曲线
- ai交互剧本_AI可以制作音乐,剧本和诗歌。 电影呢?
- AddressBook
- html图片查看代码实现,如何用HTML5实现图片预览和查看原图的功能
- spring boot新闻管理系统毕业设计源码211113
- Mac版本的夜神模拟器
- DOS命令:systeminfo
- word或wps的相关API脚本js操作
- mysql 1044_mysql重置密码和mysql error 1044(42000)错误
- 数独(SuDoku)介绍
- 除了编程语言本身,你如果还懂这 7 点,绝对可以在北上深杭拿到 15k
- 个人邮箱Outlook登录入口在哪?遇到登录邮箱服务器配置错误的解决办法
- 【图像重建】基于正交匹配追踪(OMP)算法结合小波变换是图像重建含Matlab源码