(1)计算机把数组是以一组连续的内存块保存的。
(2)如:int myArray[3]={1,2,3};在内存中的存储形式:
(3)数组拥有很多个地址,每个地址对应着一个元素(地址0存储1,地址4存储2,地址8存储3)。
(4)数组的名字 其实也是一个指针:指向数组的首地址。
(即:数组的名字同时也是一个指向其第一个元素(基地址)的指针)
//下面两个语句是同一个意思
int *ptr1=&myArray[0];
int *ptr2=myArray;//数组名指向数组的首地址
(5)通过指针访问其他元素:ptr1++; //指向下一个元素
并不将地址值简单 +1 处理,它是按照指向的数组的数据类型来递增的,
也就是 +sizeof(int) =4个字节。
(6)案例:
#include <iostream>
using namespace std;
int main()
{
const unsigned short ITEMS=5;
int intArray[ITEMS]={1,2,3,4,5};
char charArray[ITEMS]={'F','i','s','h','c'};
int *intPtr=intArray;
char *charPtr=charArray;
cout<<"整型数组输出:"<<"\n";
for(int i=0;i<ITEMS;i++)
{
cout<<*intPtr<<"at"<<intPtr<<'\n';
intPtr++;
}
cout<<"字符型数组输出:"<<"\n";
for(int i=0;i<ITEMS;i++)
{
cout<<*charPtr<<"at"<<charPtr<<'\n';
charPtr++;
}
return 0;
}
为什么会出现这样的结果呢?
对于 cout 输出指针这部分,在C++里它有不同的处理方式。
- 先看 int* 类型指针, cout 默认不能直接输出 int* 指针代表的地址数值,cout 会尝试将其转换为 void* 类型并以十六进制的形式输出地址。直接 cout << intPtr; 这种写法在不同编译器和环境下可能表现不一样,有的会报错,有的可能显示出奇怪的内容。所以一般要先把 int* 指针用 reinterpret_cast 转换为 unsigned long long 类型再输出,这样就能正确显示地址数值了。
- 再看 char* 类型指针, cout 对它有特殊处理,会把它当作指向字符串(以 '\0' 结尾的字符序列)的指针来处理。你的 charArray 里存的字符 {'F', 'i', 's', 'h', 'c'} 没有 '\0' 结尾,当 cout << charPtr; 时, cout 就会从 charPtr 指向的地址开始一直读取内存,直到遇到 '\0' 为止。而这期间读到的内存数据如果正好被解释成了字符,就可能出现一些看起来像中文或乱码的内容,因为它读取到了不属于你 charArray 预期范围的内存区域的数据。
- reinterpret_cast<unsigned long long>(intPtr):是一个类型转换表达式 ,将 intPtr指针(一个内存地址)转换为 unsigned long long类型的值 。
#include <iostream> using namespace std; int main() { const unsigned short ITEMS=5; int intArray[ITEMS]={1,2,3,4,5}; char charArray[ITEMS]={'F','i','s','h','c'}; int *intPtr=intArray; char *charPtr=charArray; cout<<"整型数组输出:"<<"\n"; for(int i=0;i<ITEMS;i++) { cout<<*intPtr<<" at "<<reinterpret_cast<unsigned long long>(intPtr)<<'\n'; // cout<<*intPtr<<" at "<<reinterpret_cast<unsigned long >(intPtr)<<'\n'; // cout<<*intPtr<<" at "<<intPtr<<'\n'; intPtr++; } cout<<"字符型数组输出:"<<"\n"; for(int i=0;i<ITEMS;i++) { cout<<*charPtr<<" at "<<reinterpret_cast<unsigned long long>(charPtr)<<'\n'; // cout<<*charPtr<<" at "<<reinterpret_cast<unsigned long >(charPtr)<<'\n'; // cout<<*charPtr<<" at "<<charPtr<<'\n'; charPtr++; } return 0; }
为什么不用unsigned long?
- int类型占用4个字节,若改成long,win里是4个字节32位,所以long不够, 得用long long,long long是8个字节64位。
- 将int转换为longlong可以避免在Windows系统中因字节数不足导致的报错,因为longlong在32位系统中提供8个字节的存储空间用于表示64位地址。
reinterpret_cast:
语法:reinterpret_cast<类型>(变量);
C++中的一种强制类型转换运算符,用于执行不相关类型之间的转换这种转换;
它会产生一个新的值,这个值与原始参数有完全相同的比特位
是一种非常底层、高度依赖于实现的操作,简单来说就是直接对内存位模式进行重新解释。
- 用在任意指针(或引用)类型之间的转换;
- 以及指针与足够大的整数类型之间的转换;
- 从整数类型(包括枚举类型)到指针类型,无视大小。
注:“足够大的整数类型”,取决于操作系统的参数,如果是32位的操作系统,就需要整型(int)以上的;如果是64位的操作系统,则至少需要长整型(long)。具体大小可以通过sizeof运算符来看。
(7) *ptr + 1; *(ptr + 1);两者有何区别 ?
如有:int Array[5] = {1, 2, 3, 4, 5};
int *ptr = Array;
则
*ptr + 1;
*(ptr + 1);#include<iostream> using namespace std; int main(){ int Array[5]={1,26,3,4,5}; int *ptr=Array; cout<<*ptr+1<<"\n"; cout<<*(ptr+1)<<"\n"; return 0; }
这两个表达式 *ptr + 1 和 *(ptr + 1) 有明显的区别,主要体现在运算顺序和结果上:
1. *ptr + 1 :
- 首先, *ptr 表示对指针 ptr 进行解引用操作,即获取 ptr 所指向的内存地址中的值。在这个例子中, ptr 指向数组 Array 的第一个元素 Array[0] ,所以 *ptr 的值是 1 。
- 然后, *ptr + 1 就是将 *ptr 的值(也就是 1 )加上 1 ,最终结果是 2 。但这个表达式只是进行了计算,并没有修改 ptr 所指向的数组元素的值。
2. *(ptr + 1) :
- 这里先计算 ptr + 1 ,这是指针的算术运算。在 C 和 C++ 中,当对指针进行算术运算时, ptr + n 的结果是 ptr 向后移动 n 个其所指向类型(这里是 int 类型)的大小的内存位置。因为 int 类型通常占用 4 个字节(具体取决于编译器和系统),所以 ptr + 1 会指向数组 Array 的下一个元素 Array[1] 。
- 接着, *(ptr + 1) 对 ptr + 1 这个新的地址进行解引用操作,获取该地址中的值,所以 *(ptr + 1) 的值是 26 ,也就是数组 Array 的第二个元素的值。
总结来说, *ptr + 1 是先取值再对值进行加法运算,而 *(ptr + 1) 是先移动指针到下一个元素的位置,然后再取值。
(8)数组和指针的应用举例
重载
#include <iostream>
void print( int *pBegin, int *pEnd )
{
while( pBegin != pEnd )
{
std::cout << *pBegin;
++pBegin;
}
}
void print( char *pBegin, char *pEnd )
{
while( pBegin != pEnd )
{
std::cout << *pBegin;
++pBegin;
}
}
int main()
{
int num[5] = { 0, 1, 2, 3, 4 };
char name[5] = { 'F', 'i', 's', 'h', 'C' };
print( num, num+5 );
std::cout << '\n';
print( name, name+5 );
std::cout << '\n';
return 0;
}
泛型设计
#include <iostream>
template <typename elemType>
void print( elemType *pBegin, elemType *pEnd )
{
while( pBegin != pEnd )
{
std::cout << *pBegin;
++pBegin;
}
}
int main()
{
int num[5] = { 0, 1, 2, 3, 4 };
char name[5] = { 'F', 'i', 's', 'h', 'C' };
print( num, num+5 );
std::cout << '\n';
print( name, name+5 );
std::cout << '\n';
return 0;
}
(9)数组可以是任何一种数据类型,这意味着我们完全可以创建一个以指针为元素的数组。
未完待续。。。