前言
自己琢磨问题的时候更喜欢在代码里面写记录,反而不喜欢在MarkDown记录,每次会将完整版源码放在最后,其实源码前面的内容我也不是很想写
C++中的数组
随手写了,可能有概念上的错误,大多也是大白话,毕竟自己也是小白,说不了多么高大尚的话语,通俗易懂就是最好的。
-
数组
数组:是用来存储一系列数据,但它往往被认为是一系列相同类型的变量
。它可以存储一个固定大小
的相同类型元素
的顺序集合
。 -
一维数组的声明方式:
// 1.使用未初始化的内存,不会补0
type arrayName [ arraySize ];
// 2.使用初始化的内存,会补0
type arrayName [ arraySize ] = {}; // 会有 arraySize 个 0
type arrayName [ arraySize ] = { val1, val2 ...}; // 没有定义的话会自动补 0
// 3.长度会依据输入的数据个数而定
type arrayName[] = { val1, val2 ...};
不再讲二维的原因是,我想快点讲指针。
- 数组名
cout << arr << endl; // 可以直接查看 arr数组 首地址 // 十六进制
cout << (int)arr << endl; // 可以直接查看 arr数组 首地址 // 十进制
cout << &arr[0] << endl; // 查看 arr数组 第一个数据的 首地址
// arr数组 首地址 == arr数组 第一个数据的 首地址
在此你会发现,数组名好像就是一个指针,的确,在此很明确的告诉你,数组名就是一个指针,指向的就是数组第一个数据的首地址。
- 注意:
数组名一旦创建,就是一个常量,指向一个首地址,因此不能够再进行赋值,会报错。
指针
在此直接说结论吧,具体请看最后的源代码,里面更为详细。
指针分为很多种,这是介绍两种,地址均用十进制表示,不带类型的指针和带类型的指针。
- 不带类型的指针
假如一个指针是 p,指向一个地址:100;
那么p++;
后,指针的地址会指向:101;
换句话说,p
指向100,p+1
指向的就是101;
加深理解,不带类型的指针就是一个 int
,这个int
指向就是内存地址
- 带类型的指针
众所周知,1个字节(Byte)有8个字符(Bit),…当我没说,我说这个干嘛
重来:
一个内存地址(例如100)就对应一个字节,有很多数据类型都不止一个字节,比如32位系统中一个int
型占4个字节,64位系统中一个int
型占8个字节。
以32为系统为例,每四个字节代表一个整数,那么如果采用指针来获取数据,每次就需要+4
对否,当然这里指的是不带类型的指针,但是我们就会认为+1
就应该取下一个整数,这么人性化的需求当然是要满足的呀。
所以C++提供了带类型的指针。
如果是int
型指针,换个字母,ip
,这个ip
是一个int
型指针,指向的地址是100
,如果ip+1
,你觉得应该指向多少?它就是指向了104
。
带类型的指针+num,就是+num*(类型所占字节大小)
,因此如果能分别指针的类型,那么就很容易理解数组名和数组指针之间的关系了,包括一些面试题,也不在话下了!
数组名和指针
- 直接上结论
创建一个数组int b[] = {1,2,3};
,数组名b
就是一个指针,指向这个数组的首地址,解指针就会获取数组的第一个数*b
,*(b+1)
就会获取数组的第二个数哟。
注意区分*(b+1)
和*b+1
!
*(b+1)
:是指针移到数组第二个数的首地址然后解指针获取到2
这个数
*b+1
:是指针数组第一个数的首地址被解压获取到1
这个数然后 1+1 =2
,怎么一样了?怪我例子没举好,再来一遍!
创建一个数组int a[] = {10,20,30};
,数组名a
就是一个指针,指向这个数组的首地址,解指针就会获取数组的第一个数*a
,*(a+1)
就会获取数组的第二个数哟。
注意区分*(a+1)
和*a+1
!
*(a+1)
:是指针移到数组第二个数的首地址然后解指针获取到20
这个数
*a+1
:是指针数组第一个数的首地址被解压获取到10
这个数然后 10+1 =11
- &a
int a;
创建一个整型对象a
,&a
就是取a对象的地址,也就是指向a
的指针
如果是数组int a[] = {10,20,30};
呢?在此不深入追究,a
本身就是一个带类型的int指针
了,&a
就是将a
指针变为a这整个对象的指针,也就是说(&a+1) == a+sizeof(a)/sizeof(a[0])
。
源代码
// 数组中的指针:对象指针和元素指针
void array_index_001()
{
int b[] = { 1,2,3,4,5 };
cout << "查看一下array的内存地址:" << &b << endl;
// 但是b也是可以创建array的地址的
cout << "直接用数组变量名查看地址:" << b << endl;
// 但是这两个指针是有区别的
// &b 是对象 b 这整个对象的(起始)地址;
// b 是对象 b 中第一个元素的地址;
// 如何验证:分别将两个地址+1,既可以看出区别
cout << "对象指针+1结果:" << &b + 1 << endl;
cout << "元素指针+1结果:" << b + 1 << endl;
// 一个相差 20 一个相差 4,;因此对元素取址,多用数组变量名
// 加深理解,其实变量名b 相当于 &b[0]
cout << "验证&b[0]+1:" << &b[0] + 1 << endl;
cout << "---" << endl;
// 换成整数看更为直观
cout << "换成整数看更为直观" << endl;
cout << "查看一下array的内存地址:" << int(b) << endl;
cout << "对象指针+1结果:" << int(&b + 1) << endl;
cout << "元素指针+1结果:" << int(b + 1) << endl;
cout << "验证&b[0]+1:" << int(&b[0] + 1) << endl;
}
// 数组中的指针:剖析数组索引
void array_index_002()
{
int a[] = { 1,2,3,4,5 };
// 分别看看输出:a、a[0]、a+1、a[1]
cout << "a: " << a << endl;
cout << "a[0]: " << a[0] << endl;
cout << "a+1: " << a+1 << endl;
cout << "a[1]: " << a[1] << endl;
// 可以得出怎样的结论呢?
// 数组名就是一个指针,a 和 a+1 均输出的是元素的地址
// 我们换一个方式来输出同样的内容
cout << "---" << endl;
cout << "使用纯指针来输出同样的结果" << endl;
cout << "a: " << a << endl;
cout << "*a: " << *a << endl;
cout << "a+1: " << a + 1 << endl;
cout << "*(a+1): " << *(a+1) << endl;
//由此可见:a[num] 其实就是 *(a+num) // 指针偏移后取索引
// a[0] 其实就是 *(a+0) 也就是 *a
// python中a[-1]就是最后一个数,可以负数索引,C++中可以吗?
//cout << "---" << endl;
//cout << "看看负索引是个啥 a[-1]: " << a[-1] << endl;
看来是未初始化的空间:-858993460
虽然能运行,但是编译器已经把我给“绿了”,所以弄懂就OK了
}