KeyPoint:
- 数组和指针两者的关系如何?
- 数组也有迭代器,比起vector迭代器有哪些不同?
- 数组长度计算的几种方法?
1.数组与指针的关系
- 在编译器层面,数组就是指针
- 可以通过取数组元素的地址符来获得数组的元素
- int arr[] = {1,2,3};
- int *p = &arr[0];
- 但是更加一般的做法直接使用数组名字来赋值给指针
- int *p2 = arr;
- 上面的表达式就是表示指针p2直接指向的是arr首元素的地址
- 可以通过取数组元素的地址符来获得数组的元素
- 在很多情况下对于数组的操作实际上就是对指针的操作
- auto推断为指针而非数组
- int arr[] = {1,2,3};
- auto a2(arr); ==>auto a2(&arr[0]);
- a2 = 10; //err
- 如下图:编译器会将其定义为指针
- 需要注意的地方使用decltype的时候不会发生转成指针的情况
- 这个会将其转换成数组,而不是指针
- auto推断为指针而非数组
2.指针就数组的迭代器
数组的迭代器
- 指针就是数组的迭代器
- 支持类似于vector与string迭代器的运算
- 指针指向的首地址就是首个元素的地址,尾地址是数组最后一个元素的下一个位置
- int arr[] = {1,2,3,4,5};
- 尾地址就是 arr[5]; 千万不要对其进行读取或者赋值,会造成不可估量的error
- 编译的时候是可以通过,但是使用中会导致崩溃的情况
- 支持类似于vector与string迭代器的运算
- 指针指向的首地址就是首个元素的地址,尾地址是数组最后一个元素的下一个位置
- int arr[] = {1,2,3,4,5};
- 尾地址就是 arr[5]; 千万不要对其进行读取或者赋值,会造成不可估量的error
- 编译的时候是可以通过,但是使用中会导致崩溃的情况
标准库函数begin和end (C++11)
- 为什么要引入begin和end
- 为了避免使用尾后指针带来错误
- 主要使得指针使用更加安全和简单
- 使用方法
- 功能与vector同名函数类似
- 但是类型不同,vector是对应的iterator,而数组类型的begin和end是对应的指针类型
- int arr[] = {1,2,3};
- int *beg = begin(arr);
- int *en = end(arr);
- 注意的地方
- 尾后指针不能执行解引用和递增操作
- 因为其已经是数组最后一位的下一位了
- 尾后指针不能执行解引用和递增操作
指针运算
- 指针运算就如同string 或者vector 迭代器的运算,如上图
- 数组大小计算 end 和begin
- auto n = end(arr) - begin(arr);
- n的类型是ptrdiff_t类型
- 两个指针的比较
- 针对数组的时候可以比较指向同一个数组元素或者尾后元素指针
- 针对不同数组的时候不可以比较指针
解引用和指针运算的交互
- 指针加上一个整数所得的结果还是一个指针
- int arr[] = {1,2,3}
- int a = *(arr + 2);
- int b = *arr + 2;
- 上述的过程中解引用与圆括号的位置关系
下标和指针
- 其实数组的名字就是一个指向数组首元素的指针
- int arr[] = {1,2,3,4,5};
- int a = arr[2];
- int *p = ia;
- a = *(p+2);
- 下标的使用可以是使用在指针指向的数组元素
- 下标的使用与string和vector中是相似
- 如果是数组类型是内置的类型,下标可以是有符号类型
实例练习:
- auto 推断数组和指针的关系,decltype 推断关系
- 重写利用指针循环获取数组的值,尤其注意尾部指针的概念
- 利用begin 和end函数来循环一个数组
- 指针运算实例 ,begin 和end
- 解引用和指针交互运算(*)
- 下标的使用,注意有符号类型
#include<iostream>
#include<string>
#include<vector>
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::begin;
using std::end;
void main()
{
#pragma region auto 推断数组和指针的关系,decltype 推断关系
//数组在某些时候就是指针
int arr[] = { 1, 2, 3, 4, 5 };
int *p = &arr[0]; //p就是指向数组首元素的指针
int *p1 = arr; //这个是最常见的形式
//如何证明数组在某些时候就是指针
int arr1[] = { 1, 2, 3, 4, 5 };
auto parr(arr1);
// parr = 50; //err
cout << endl;
//decltype的使用
decltype(arr1) p2;
//p2 = parr; //err将指针赋值给数组
p2[1] = 0;
#pragma endregion
#pragma region 重写利用指针循环获取数组的值,尤其注意尾部指针的概念
int b_arr[] = { 1, 2, 3, 4, 5 ,6};
int *b_p = b_arr;
int *b_e = &b_arr[6]; //尾后指针,就是指向数组最优一个元素的下一个位置
for (; b_p != b_e; b_p++)
{
cout << *b_p << endl;
}
//切记,不要试图对尾后元素进行操作
/*b_arr[6] = 100;
cout << "b_arr[6] = "<<b_arr[6] << endl;*/
#pragma endregion
#pragma region 利用begin 和end函数来循环一个数组
int c_arr[] = { 1, 2, 3, 4, 5 };
int *ben = std::begin(c_arr);
int *en = std::end(c_arr); //*en 就相当于c_arr[5],是尾后指针,
//切记,不要试图对尾后元素进行操作
/**en = 100;
cout << "*en = " << *en << endl;*/
for (int *cur = ben; cur!=en; cur++)
{
cout << *cur << endl;
}
#pragma endregion
#pragma region 利用begin 和end函数来计算数组长度
int d_arr[] = { 1, 2, 3, 4, 5 };
//计算数组长度C方法
int d_arrLen = sizeof(d_arr) / sizeof(d_arr[0]);
cout << "d_arrLenC = " << d_arrLen << endl;
//计算数组长度C++方法
auto d_arrLen2 = end(d_arr) - begin(d_arr);
cout << "d_arrLenCPP = " << d_arrLen2 << endl;
#pragma endregion 指针运算中的比较方法使用
#pragma region 指针运算中的比较方法使用
int e_arr[] = { 1, 2, 3, 4, 5 };
int *e_p1 = e_arr;
int *e_p2 = e_arr + 2;
if (e_p1 > e_p2)
{
cout << *e_p1 << endl;
}
else
{
cout << *e_p2 << endl;
}
int e_arr2[] = { 2, 3, 4, 5 };
int *e_p3 = e_arr2;
//这个比较毫无意义可言,而且结果是错误的
//针对不同数组的时候不可以比较指针
if (e_p1 > e_p3)
{
cout << *e_p1 << endl;
}
else
{
cout << *e_p3 << endl;
}
#pragma endregion
#pragma region 解引用和下标
int f_arr[] = { 1, 2, 3, 4, 5 };
//这里要注意解引用的指针所指向的位置关系
int *f_p = f_arr;
int f_a = *f_p + 2; // f_arr[0] +2
int f_b = *(f_p + 2); // f_arr[2];
cout << "*f_p + 2 = " << f_a << endl;
cout << "*(f_p + 2)" << f_b << endl;
int *f_p2 = f_arr + 3;
//下标是可以为负数的,主要是针对内置类型是可以这样的,这个是与vector有点不同
cout << " f_p2[-1] = "<<f_p2[-1] << endl;
#pragma endregion
system("pause");
return;
}
3.C风格字符串
简介
- 并不是一种类型,而是一种约定写法
- 该写法是中字符串数组最后一位必须是空字符结束
- 最后一个字符后面跟着一个空字符('\0')
- 一般使用指针来操作这些字符
- 在C++尽可能不要使用C风格类型
C标准String函数
- 需要注意的地方
- 使用上面的函数是,要保证字符串是以空字符作为结束的
字符串比较
- C++(> , <, ==)
- C风格使用(>,<)
- 实际上市用指向数组首元素的指针
- strcmp 函数使用
- 相等返回 0
- 前者较大返回正值
- 后者较大返回负值
- 两个迭代器最差运算 it1 - it2
- 返回值为difference_type类型,其为带符号的整数
字符串添加
- C++(直接使用+)
- C风格使用 strcat 和strcpy来添加合并字符串
- 必须要要保证一个足够大的字符串以及末尾为空字符
- 所以计算其存放字符串的大小非常重要
- 这个也是非常容易出错的地方
- C风格字符串函数使用注意要点
- 比较两种字符串比较的方法C++和C风格
3.字符串与旧代码的接口
string对象与C风格字符串混用
- 允许使用空字符结束符的字符数组来初始化string对象
- string加法运算中允许以空字符结束的字符作为运算对象
- c_str函数的使用
- string s("abc");
- char *str = s;
- const char *str = s.c_str()
使用数组初始化vector对象
- 数组是不允许直接赋值或者初始化另外一个数组
- 也不允许使用vector来初始化数组
- 可以使用数组来来初始化vector对象
- c_str 函数的使用
- 以上实例
#include<iostream>
#include<string>
#include<vector>
#define _CRT_SECURE_NO_WARNINGS
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::begin;
using std::end;
void main()
{
#pragma region C风格字符串函数使用注意要点
char a_s[] = { 'a', 'b', 'c' };
char * a_ps = a_s;
//这个时候会有一个严重的错误,因为字符串s并没有以\0结束,无法获得正确的长度
while (*a_ps)
{
cout << *a_ps << endl;
a_ps++;
}
cout << "len = " << strlen(a_s) << endl;
//切记利用指针或者数组来构成字符串时,一定要记得在末尾加上\0
char a_s2[] = { 'a', 'b', 'c' ,'\0'};
char * a_ps2 = a_s2;
while (*a_ps2)
{
cout << *a_ps2 << endl;
a_ps2++;
}
cout << "len = " << strlen(a_s2) << endl;
#pragma endregion
#pragma region 字符串指针的比较
char b_s1[] = "I am Wall.E";
char b_s2[] = "I am Wall.F";
//这个比较仅仅是比较两个指针的地址,并不是比较字符串
if (b_s1 > b_s2)
{
cout << b_s1 << endl;
}
//正确的比较方法strcmp
if (strcmp(b_s1, b_s2)>0)
{
cout << b_s1 << endl;
}
else
{
cout << b_s2 << endl;
}
#pragma endregion
#pragma region 字符串指针的拼接
char c_s1[] = "Hello";
char c_s2[] = "Cpp";
//相当于两个指针相加,并没有什么意义,所以以后指针的运算中一定小心
//char c_s3[] = c_s1 + c_s2;
//使用strcat尤其注意使用其长度的使用
char c_s3[20] = {};
strcat(c_s3, c_s1);
strcat(c_s3, " ");
strcat(c_s3, c_s2);
cout << c_s3 << endl;
#pragma endregion
#pragma region c_str的使用
string d_s = "we are family.";
const char *d_ps = d_s.c_str();
#pragma endregion
#pragma region 使用数组初始化vector对象
int e_arr[] = { 1, 2, 3, 4, 5, 6 };
vector<int> e_v(begin(e_arr), end(e_arr));
for (auto i : e_v)
{
cout << i << endl;
}
#pragma endregion
system("pause");
return;
}