【C语言】指针和数组的联系与区别

指针:

一,指针的概念 :

指针首先是一种数据类型,使用它定义的变量称为指针变量,指针变量是专门用来存放地址的。以int* a为例:a就是一个指针变量,a变量存放一个int类型数据的地址。a变量的大小根据编译器使用32位方式编译还是64位方式编译分别对应4个字节和8个字节。

二,关于指针的运算:

(1)指针 + / - 整数:
以int* a为例 a + 10,不是增加10个字节,而是增加10个int类型变量的大小也就是 4 * 10 = 40个字节。a - 10与加操作类似:减去40个字节。 同理 a++ 和 a-- 操作分别是加上和减去4个字节。
(2)指针 + / -指针:
指针 + 指针:没有任何意义。
指针1 - 指针2:表示指针1 与 指针2之间相差多少个元素个数例如:

int arr[] = { 1, 2, 3, 4, 5 };
	int* pa1 = &arr[0];
	int* pa2 = &arr[10];
	printf("%d", pa1 - pa2);

输出结果是 -10;

三, 野指针:

野指针,也就是指向不可用内存区域的指针。通常对这种指针进行操作的话,将会使程序发生不可预知的错误。
野指针的产生方式:
(1)未初始化:
指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
(2)指针越界访问:

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 int *p = arr;
 int i = 0;
 for(i=0; i<=11; i++)
 {
 //当指针指向的范围超出数组arr的范围时,p就是野指针
 *(p++) = i;
 }
 return 0;
}

(3)指针指向的空间释放
指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。free 和 delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。

数组:

一,数组的概念:

数组是一组相同类型元素的序列,底层空间连续。如果要将某个有限相同类型的序列命名,我们称之为数组名。例如:

int arr[10] = {0};

数组名为arr,数组的类型是 int [10]。数组元素类型是int。需要注意的是数组名arr是不能改变的。也就是说不能进行++和–操作,数组名只有在sizeof(arr) 和 & arr 的时候代表整个数组,其他的时候会被降级处理成指向首元素的指针常量。

二,数组的传参

(1)一维数组的传参:
数组传参的时候永远不会以值传递,假如传递数组int arr[10],实参arr会被降级处理成指针常量。形参的形式如下:

void test(int* arr);
void test(int arr[]);
void test(int arr[5]);

上边形参的几种声明方式都是完全等价的,因为在一维数组传参时,形参不会真实的创建数组,虽然看上去是定义了int arr[5] ,但是实际上arr会降级处理成一个指向首元素的指针,首元素的类型是int,所以相当于只是定义了一个int* 的指针变量。例如下边代码:

void test1(int arr[5]){
	cout << sizeof(arr) << endl;
	cout << ++arr <<endl;
}
int main(){
	int arr[] = { 1, 2, 3 };
	test1(arr);
	return 0;
}

程序的输出结果是4, 和一个地址。说明函数并没有建立int [5]类型的数组,而且arr是可变的。
(2)二维数组的传参:
与一维数组相同,形参并不会建立一个二维数组,就算是定义二维数组,也会降级处理成一个指向首元素的指针。二维数组的首元素也是一个数组,所以形参的指针类型是一个数组指针。所以下边这几种二维数组的声明方式没有区别:
void f(int **);
void f(int *arr[]);
void f(int *arr[5]);

//传参正确
//表明二维数组的大小,三行五列.
void test1(int arr[3][5])
{}

//传参不正确
//二维数组的两个方括号,不能全部为空,也不能第二个为空,只能第一个为空
void test(int arr[][])
{}

//传参正确
//可以写成如下这样传参形式,但是不能写int arr[3][]
void test(int arr[][3], int Rows)
{}

//传参不正确
//arr是一级指针,可以传给二维数组,但是不能正确读取,
void test(int *arr,int iRows,int iCols)
{
 for(int i=0;i<iRows;i++)  
    {  
        for(int j=0;j<3;j++)  
        {  
            cout<<*(arr+i*iRows+j)<<" ";  
        }  
        cout<<endl;  
    }  
    cout<<endl; 
}

//传参正确
//传过去的是二维数组的数组名,即数组首元素的地址,也就是第一行的地址,第一行也是个数组,用一个数组指针接收
void test(int (*arr)[5], int Rows)
{}

//传参不正确
//可以传参,但是在读取的时候会有级别不同的问题
void test(int **arr)
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}

三, 数组指针和指针数组:

指针数组和数组指针:
指针数组是数组,数组里边存放的是指针变量。
数组指针是指针,是指向数组的指针。
那么下边的p1和p2分别是什么?
int *p1[10];
int (p2)[10];
p1: 指针数组 。 []的优先级高于 * 的优先级 所以p先于[]结合说明他是一个数组然后再与 * 结合说明他是一个存放 int
类型指针的数组
p2: 数组指针。p2和 * 被括号括起来,说明他首先是一个指针,是指向int [10]类型的指针。然后int[10]是一个数组所以 p2是一个数组指针。

数组和指针的区别和联系:

首先数组和指针是两个完全不同的数据类型。他们之间的联系在于数组名的降级处理,也就是数组名在大多数情况下会被当做一个指向数组首元素的常量指针来处理,比如在传参,赋值,算数运算等操作的时候。例如 int arr[10] = {0}; arr + 1加四个字节。并不是 40个字节。
只有 sizeof(arr), 和 & arr 的时候 arr会被当做int [10] 类型的数组来处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值