数组和指针之间不得不说的故事

指针和数组

多维"数组"的实现

静态数组

静态指针(指针配合数组)

动态指针(指针配合指针)

行指针(指针配合数组指针)

二级指针的传参

关于指针

两个例子


指针和数组

首先给出结论:数组和指针 在本质类型上是完全不一样的东西。

“数组是常量指针”这种方法只是为了方便理解,因为你可以在功能上利用指针指向数组类型,并进行一些元素的操作,仅此而已

(这也仅仅是因为指针的功能强大,能够到达数组类型的内存单元里)。 

那为什么指针能够与数组相匹配,这就要找编译器:

int *pointer = array;

看上去像是数组作为“指针”赋给了pointer,实际上这里有编译器进行的隐式类型转换,你可以看做

int *pointer = &array[0]

只是把指针 指向了 数组(首元素/变量)的地址。

p[item] == array[item] 也只是方便用户的编译器的把戏。

p[item] 实际上就是*(p+item),即使你写成item[p] 也没关系。

这一点在多维数组上也是一样。

--->关于数组和指针(甚至延伸到了函数指针)

--->二维数组和指针 

——————————————————————

多维"数组"的实现

静态数组

int array[num1][num2] ...

   没什么好说的,数据大小的不确定会导致这种实现浪费很多的内存空间,甚至爆栈。

静态指针(指针配合数组)

通过数组存放指针,而这些指针可以指向一连串 存放数据 的空间,或者继续指向数组地址(首元素)——直到降维到单个元素。

//第二维度
int* arr_1[4] = { 1,2,3,4 }, *arr_2[4] = { 0 }, *arr_3[4] = { 5,6,7 }, *arr_4[4] = { 8 };
//第一维度:指针的指针
int** arr[4] = { arr_1,arr_2,arr_3,arr_4 };

动态指针(指针配合指针)

//声明一个 int* 的指针,并分配 NUM1 个 int 长度的空间
int** arr = (char**)malloc(NUM1 * sizeof(int*));
//令每个元素指向一个指针,此指针其后的内存空间被分配了 NUM2 个 int 长度的空间
for (size_t i = 0; i < NUM1; i++)
{
	arr[i] = (char*)malloc(NUM2 * sizeof(int));
}

行指针(指针配合数组指针)

int* (*arr)[NUM] = NULL;

中括号中的NUM不是要编译器申请足够的空间大小,(它本身是一个指针的大小),而是提醒该指针要位移NUM大小的数据。(数组指针的位移大小与该数组属性有关)

你可以理解为:指向 数组指针 的 指针。

eg:

	int* arr_1[16] = { 1,2,3,4,5,6,7,8 };
	int* (*arr)[4] = arr_1;
	for (size_t i = 0; i < 4; i++)
	{
		for (size_t j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}printf("\n");
	}

---->参考

一个非常基础的地方:malloc申请的指针,或者说需要动态申请空间的指针不能用{ }初始化,因为编译器不能预先知道它的空间。(静态数组,数组指针 →可)

——————————————————————

二级指针的传参

1.实参作为普通数组

void func1(array[num1][num2]);

void func2(array[][num]);

void func3(int (*array)[num]);

//——————————————————————————————————————————————
void main()
{
array[num1][num2]={ ...};
}

2.实参作为二级指针

void func(int **array,int num1,int num2);


//1.分配连续内存 (一长条)
 int **arr=new int*[num1];
 arr[0]=new int[num1*num2];
 delete []arr[0];
 delete []arr;

//2.二级指针 →  指针数组 →原普通数组 的 行
   int n[3][3]={{1,2,3},{4,5,6},{7,8,9}};
    int **arr=new int*[3];
    arr[0]=n[0];
    arr[1]=n[1];
    arr[2]=n[2];
    func(arr,3,3);
    delete []arr;


//3.手动new二级指针

    int **arr=new int*[num1];
    for(int i=0;i<num1;++i)
        arr[num1]=new int[num2]; //在这里有个缺点:数组在内存中的分布不是连续的

    func(arr);

   for(int i=0;i<3;++i)
        delete []arr[num1];//记住new了几个就一定要delete几个
    delete []arr;

3.

int arr[3][3]={{1,2,3},{4,5,6},{7,8,9}};
func((int **)arr,3,3);  //强转,指针退化

————————————————————
for(int i=0;i<n;++i){
  for(int j=0;j<m;++j)
     cout<<*((int *)arr+i*m+j)<<" "; //根据地址进行操作

——————————————————————

关于指针

C语言中,不同数据类型的指针,它的本质区别只是在内存中延伸的内存空间大小。

这个延伸的内存空间大小可以称之为引用范围。(范围和被引用数据大小相同)

像某某数据类型只是相对抽象的方便说法,底层来看都是在字节空间上,配合自身指向的数据位移,没有什么不同。

char*为1,int*为4,double*为8

提到引用范围,有必要提一句 空类型指针void* pointer

该指针不能事先知道指向数据的内存大小,没有确定的引用范围,只能指向内存地址,不能直接解地址使用;故使用时要根据场景,进行强制类型转换。

---->参考

两个例子

eg1:

#include<iostream>
using namespace std;

void memswap(void* arr_1,void* arr_2,size_t size)
{
    void * temp=NULL ;
    temp = realloc(temp,size);
    memcpy(temp,arr_1,size);
    memcpy(arr_1,arr_2,size);
    memcpy(arr_2,temp,size);
    temp = realloc(temp,0);
	free(temp);
}
                                            
void bublesort(void* array,int item,int count,int (*comp_fun)(void*,void*))
{
    int flag=1;
    void *start = array;
    for(int j=0;flag==1;j++)
    {
        flag=0;
        array = start;
        for(int i=0;i<count-1-j;i++,array=(array)+item)
        {
            if(comp_fun(array,(void*)(array+item))>0)
            {
                memswap(array,(void*)(array+item),item);
                flag=1;
            }
        }
    }
}
int comp(void* arr_1,void* arr_2)
{
    return *(int*)arr_1 - *(int*)arr_2;
}
int main()
{
  int arr[10]=  {1,3,8,2,99,54,6,7,3,2};
  bublesort(arr,sizeof(arr[0]),10,comp);
  for (int i = 0;i < 10;i++)printf("%d ",arr[i]);
}

一个用到void*,函数指针的冒泡排序(引用)

eg2:

typedef int (* fp)(void *para, void *end);
typedef int (*p)(char *s);

int print(char *s);
int main()
{
    p pf;

    pf = &print;

    pf("阿星");
    return 0;
} 

int print(char *s)
{
    printf("值为:%s\n",s);
    return getchar();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值