上一文我们介绍到了 C++ 数组,本文从 C++ 字符串开始,抓住时间的尾巴,继续学习,不能这么早就夭折
字符串
C++ 提供了以下两种类型的字符串表示形式:
- C 风格字符串
- C++ 引入的 string 类类型
C 风格字符串
C 风格的字符串起源于 C 语言,字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
对于使用 “ ”(字符串常量)来初始化字符串数组时,不需要把 null 字符放在末尾,C++ 编译器会自动把 '\0' 放在字符串的末尾。
char greeting[] = "Hello";
而对于使用 { } 或 数组下标来初始化字符串数组时是需要将 null 字符 '\0' 字符放在末尾的,且字符数组的大小的设置= 字符串长度+1:
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
C++ 中可以用来操作以 null 结尾的字符串的函数
函数 | 描述 |
strcpy(s1, s2); | 复制字符串 s2 到字符串 s1。 |
strcat(s1, s2); | 连接字符串 s2 到字符串 s1 的末尾。 |
strlen(s1); | 返回字符串 s1 的长度。 |
strcmp(s1, s2); | 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。 |
strchr(s1, ch); | 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 |
strstr(s1, s2); | 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。 |
C++ 中的 String 类
C++ 标准库提供了 string 类类型,支持上述所有的操作。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "hello,";
string str2 = "world";
string str3;
int len ;
// 复制 str1 到 str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接 str1 和 str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,str3 的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}
指针
首先我们明确,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
指针变量声明的一般形式为:
type *var-name;
type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 是用来指定一个变量是指针。
使用指针
使用过程中的频繁操作:
- 定义一个指针变量
- 把变量地址赋值给指针
- 访问指针变量中可用地址的值
这些是通过使用一元运算符 *来返回位于操作数所指定地址的变量的值:
#include <iostream>
using namespace std;
int main ()
{
int var = 20; // 实际变量的声明
int *ip; // 指针变量的声明
ip = &var; // 在指针变量中存储 var 的地址
cout << "Value of var variable: " << var << endl;
// 输出在指针变量中存储的地址
cout << "Address stored in ip variable: " << ip << endl;
// 访问指针中地址的值
cout << "Value of *ip variable: " << *ip << endl;
return 0;
}
Null 指针
变量声明时,如果没有确切的地址可以赋值,要为指针变量赋为 NULL 值。该指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量:
define NULL 0
大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 的指针表明不指向一个可访问的内存位置。所以,如果指针包含空值(零值),则假定它不指向任何东西。
因此,如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针,可以防止出现垃圾值。
指针的算术运算
指针支持四种算术运算:++、--、+、- 。
变量指针可以递增递减,而数组不能递增递减,因为数组名是指向数组开头的常量指针,因为数组是一个常量指针。对指针进行递增递减运算,即把值加上减去其数据类型的字节数,指针指向下一或上一内存位置。
指针还可以用关系运算符进行比较,如 ==、< 和 >:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// 指针中第一个元素的地址
ptr = var;
int i = 0;
while ( ptr <= &var[MAX - 1] ){
cout << "Address of var[" << i << "] = " << ptr << endl;
cout << "Value of var[" << i << "] = " << *ptr << endl;
// 指向上一个位置
ptr++;
i++;
}
return 0;
}
指针数组
指针数组的声明:
type *arrName[capacity]
指针数组中的每一个元素是指向 type 类型值的指针。用一个指向字符的指针数组来存储一个字符串列表:
#include <iostream>
using namespace std;
const int MAX = 4;
int main ()
{
const char *names[MAX] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
for (int i = 0; i < MAX; i++){
cout << "Value of names[" << i << "] = " << names[i] << endl;
}
return 0;
}
指向指针的指针
这是一种多级间接寻址的形式,或者说是一个指针链。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。指向指针的指针变量声明:
type **pointer;
通过查看 var,ptr,*pptr 的地址可以更加清晰的理解多级间接寻址的寻址过程:
#include <iostream>
using namespace std;
int main ()
{
int var = 3000,*ptr,**pptr;
// 获取 var 的地址
ptr = &var;
// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;
// 使用 pptr 获取值
cout << "var 值为 :" << var << endl;
cout << "*ptr 值为:" << *ptr << endl;
cout << "**pptr 值为:" << **pptr << endl;
cout << "var 地址为 :" << &var << endl;
cout << "ptr=&var 值为var的地址:" << ptr << endl;
cout << "ptr地址为:" << &ptr << endl;
cout << "*pptr=ptr=&var 值为var的地址:" << *pptr << endl;
cout << "pptr 地址为:" << &pptr << endl;
return 0;
}
传递指针给函数
简单地声明函数参数为指针类型即可传递指针给函数,调用函数时,将变量地址传递作为参数传入。因此,能接受指针作为参数的函数,也能接受数组作为参数(数组名就是地址)。
从函数返回指针
C++ 允许声明一个返回指针的函数。C++ 不支持在函数外返回局部变量的地址,而返回局部变量指针相当于返回局部变量的地址,此时需要定义为 static 局部变量如下所示:
int * myFunction(){...}
引用
引用变量是一个别名。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
引用 vs 指针
区别如下:
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
创建引用
变量名称是变量附属在内存位置中的标签,引用当成是变量附属在内存位置中的第二个标签。可以通过原始变量名称或引用来访问变量的内容。创建方式:
type& quoteName = varName;
& 读作引用。因此,可以读作 "quoteName 是一个初始化为 varName 的 type 型引用" ,引用通常用于函数参数列表和函数返回值。
C++ 支持把引用作为参数传给函数,这比传一般的参数更安全。
C++ 支持函数返回一个引用(一个指向返回值的隐式指针)。这样,函数就可以放在赋值语句的左边。
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6};
double& setValues( int i ){
return vals[i]; // 返回第 i 个元素的引用
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = 0; i < 2; i++ ){
cout << "vals[" << i << "] = " << vals[i] << endl;
}
setValues(1) = 20.23; // 改变第 2 个元素
cout << "改变后的值" << endl;
for ( int i = 0; i < 2; i++ ){
cout << "vals[" << i << "] = " << vals[i] << endl;
}
return 0;
}
注意:被引用的对象不能超出作用域。
所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。