复杂的数据类型03--指针和数组

发布于:2025-04-02 ⋅ 阅读:(20) ⋅ 点赞:(0)
(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)数组可以是任何一种数据类型,这意味着我们完全可以创建一个以指针为元素的数组。

未完待续。。。 


网站公告

今日签到

点亮在社区的每一天
去签到