自学内容网 自学内容网

【C++ Primer Plus】4

2 字符串

字符串是存储在内存的连续字节中的一系列字符;C++处理字符串的方式有两种,

  1. c-风格字符串(C-Style string)
  2. string 类

2.1 c-风格字符串(C-Style string)

2.1.1 char数组存储字符串(c-风格字符串)

将字符串存储在char数组中,每个字符都位于自己的数组元素中

以空字符(null character)结尾,空字符被写作\0,ASCII 为0,用于标记字符串的结尾。

不应将字符串的字符数组当做字符串来处理,末尾相差一个’\0’
在这里插入图片描述

缺点:
(1)造容易出现因’\0’造成的输出错误
(2)大量引号带来的输入压力;

2.1.2 字符串常量(string constant)

字符数组初始化为字符串,自动加上结尾的空字符:char boss[8]="Bozo" //隐式地包括结尾的空字符;
在这里插入图片描述

字符串常量(使用双引号)不能与字符常量(单引号)互换
char shirt_size = ‘S’; //fine 字符
char shirt_size = “S” // illegal
char shirt_size[ ]= “S” // fine 字符串

2.1.3 数组中 定义与初始化 字符串常量

  1. 定义与初始化
// 定义的同时初始化
char  bird[]="Mr. Hellen"
cout << bird;

//先定义再初始化
char name1[20]; 
​cin >> name1;  
// input:lihua
​cout << "hello"<< name1 << ", good morning!"

  1. 将键盘或文件输入读入到数组中(cin; getline; get)

cin :以空格、制表符和换行符确定字符串结束位置,这意味着(1)cin在获取字符数组输入时只能读取一个单词;读取后,cin将该字符串放到数组中,并自动在结尾添加空字符;(2) 无法防止输入溢出

getline(): 读取整行,在读取指定数目的字符 或 通过回车键输入的换行符来输入结尾;
cin.getline( arrayName , charNamber);
两个参数:第一个参数用来存储输入行的数组的名称。第二个参数要读取字符数;
e.g. cin.getline(name,20); 将姓名读取到一个包含20个元素的name数组中,这行包含的字符不超过19个。
在这里插入图片描述

  • get():istream类中的一个函数
//用法1:类似于getline,但get不再读取或丢弃换行符,而是留在输入队列中;
const int Arsize = 20;
cin.get(name, ArSize);
cin.get(dessert,Arsize); //problem;读取到第一个字符是换行符,以为到行尾,无法跨过换行符继续输入;

//解决方案
//不带任何参数的cin.get(),可读取下一个字符;
cin.get(name, ArSize);
cin.get();  //read newline
cin.get(dessert,Arsize);
//合并写法:
cin.get(name, ArSize).get()

tips:使用建议使用get(),而不是getline,get()使输入更仔细,并且,老式实现没有getline;
get可以知道读取的原因是已经读取了整行,而不是由于数组已经填满;如果出现这种情况,查看下一个字符,如果是换行,那么说明读取了整行,否则,说明还有其他输入;

  • 空行问题
cin >>year;  // 输入 2024 回车;
cin.getline(address,80// Wallstreet
//无法获得地址,因为getline读取到换行符后会以为是空行,并将空字符串赋给address
// 解决方案
cin >> year;
cin.get(); // or cin.get(ch);

(cin >> year).get(); //or (cin >> year).get(ch) 

2.1.4 输出(访问)字符串

输出

使用cout 来显示string 对象。
cout << name1[ ];

访问存储在 string 对象中的字符

//获取字符数组元素值
cout << name1[0];

2.1.5 复制、拼接、附加字符串:

  • 复制
strcpy(charr1,charr2);
  • 拼接:注意目标存储过小,拼接溢出问题;
//拼接时不会在被连接的字符串之间添加空格
cout << "hel" << "lo, world!";
// cstring头文件
strcat(charr1,charr2);
strcat(charr1,"hello"); 

//strncat;strncopy;

2.1.6 sizeof 计算数组长度

// sizeof(name);  
// strlen( )返回存储在数组中的字符串的长度,而不是数组本身的长度;

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main()
{
char name1[20]="lihua";  
cout << name1 << endl;
cout << "the length of name1 is (sizeof) "<< sizeof(name1) << endl;
cout << "the length of name1 is (strlen) "<< strlen(name1) << endl;
   return 0;
}
lihua
the length of name1 is (sizeof) 20
the length of name1 is (strlen) 5

2.2 string 类

包含在头文件string中;string类位于命名空间std中;

2.2.1 初始化


string str1;  //声明创建一个长度为0的string对象 
cin >> str1; 

string str2 =  "happy"

2.2.2 输出 cout

2.2.3 复制/赋值、拼接和附加

复制/赋值: str1 = str2; 一个string对象合一赋给另一个对象
拼接:str3=str1 +str2 ;
附加:str3 += “pro max”;
长度:int len1 = str1.size();
// str1不是作为参数,而是位于函数名前;str1是一个对象,size是一个类方法,方法是一个函数,只能通过其所属类的对象进行调用。

2.2.4 string的I/O

cin >> str; // read a word into the str string object;

getlline(cin,str) // 这里的getlinge不是类方法,而是将cin作为参数,指出到哪里查找输入;

R"( 和) " 作为定界符
cout << R"(Jim “King” Tutt uses “\n” instead endl.) "
//可在结果中显示’’ ‘’ () ;而不用 ‘’
输出:Jim “King” Tutt uses “\n” instead endl.

3 结构体

6 指针

指针是一个变量,其存储的是(所指向元素的)地址,而不是值本身。
&——获取变量的地址;
* ——运算符被称为间接值或解除引用运算符,

*pointer 可得到该指针存储地址的值
指针manly ; manly表示一个地址,*many表示存储在该地址出的值。

指针的定义:type *pointer;
初始化 int home=100; int *pointer = &home;

  1. 声明指针

TypeName * pointerName

double *pd;
char *pc;
  1. 初始化指针
double *pd;
double *pa
char *pc;

double pi =3.14;
pd = &pi;

pc=new char;
pa =new double[30];

int *fellow;
*fellow =23333; //dangerous!野指针!
fellow = 0x1234567//mismatch!等号两边一边是地址,一遍是数值;
fellow = (int *) 0x1234567;// match !等号两边均为地址,但是不提倡;
  1. 对指针解除引用:获得指针指向的值

cout << *pd; // 输出pd存储的地址所指向的元素的值;输出结果为3.14;
*pc = 's'; // 修改pc存储的地址所指向的元素的值为s;

note:决不要对未被初始化为适当地址的指针解除引用,形成野指针;
所以一定要在对指针应用解除引用运算符*之前,将指针初始化为一个确定的、适当的值;
可以采用赋值法或者通过new来分配内存

  1. 区分指针和指针所指向的值

double pi =3.14;
pd = π //地址;

cout << pd; //地址,输出的是pd存储的地址,即pi的地址;
cout <<*pd;// 值,输出pd存储的地址所指向的元素的值,即pi的值3.14;

  1. 数组名

在非字符串数组的情况下,C++将数组没那个视为数组的第一个元素的地址, 即array = &array[0];

int array[20];  
`cout << sizeof(array);` //返回整个数组的长度;
`cout << sizeof(pointer)` // 返回指针所占存储空间大小

cout << array

// 数组名被解释为第一个元素的地址;等价于&array[0], 得到的是一个四字节内存块的地址;
//array+1 将地址值+4;
// array 可视为一个int指针(*int);

cout << &array
//得到的是整个数组的地址,一个20*4 =80字节内存块的地址;
//&array+1 将地址加80;
// &array可视作一个数组指针;

  1. 指针算术

指针和整数相加,等于在原来的地址值上加上指向的对象占用的总字节数。double 指针+1,指针数值增加8;
两个指向同一数组的指针相减,得到的是两个指针之间的元素个数

int tacos[10] = {0,1,2,3,4,5,6,7,8,9};
int *pt = tacos;
pt =pt +1;  // pt存储/指向tacos[1],即1; 

// tacos = tacos +1  是非法的;

int *pe =&tacos[9]; 
pe =pe -1; //指向tacos[8];
int diff = pe -pt;  // diff 为7 tacos[8]和tacos[1]差了7个元素;
  1. 数组的动态联编和静态联编;

静态联编:通过数组声明创建数组,即数组的长度在编译时确定;
动态联编(动态数组):使用new[]运算符创建数组,即在运行时为数组分配空间,其长度也将在运行时设置。使用后,应使用delete[]释放所占用的内存;
int size;
cin >> size;
int *pz = new int [size];

delete [] pz;

  1. 数组表示法和指针表示法

c++ 将数组名解释为地址(首元素地址,数组地址);

tacos[1] == *(tacos + 1)  == *(pt +1) == pt[1]; 

原文地址:https://blog.csdn.net/weixin_45603902/article/details/131872396

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!