c语言字节数组比较,C语言回顾——指针与数组

本文详细介绍了C语言中指针与数组的关系,包括数组的存储方式、指针与整数的运算、通过指针访问数组的方法。还探讨了二维数组的存储特性、矩阵转置的实现,以及如何在函数中使用数组形参。通过实例代码,阐述了数组与指针的交互,帮助读者深入理解C语言的基础概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天萌新博主来给大家介绍C语言指针中指针与数组部分,在这一块也是非常难以理解的,闲言少叙,咱们开始吧!

大家都知道数组与指针有着紧密的联系,数组是由一组若干个元素构成,我们在访问数组的时候,采用的是循环体的方式,就是把数组的下标逐步的循环一次,这样我们就可以读出所有数组元素的值。那么重点来了,数组下标与地址的之间的关系,如果我们掌握好,大家学起来指针与数组就会非常的吃力,萌新博主与大家也是感同身受啊!

【数组的存储方式】

475904c0f98c57f8bc3bf38cba4f1ecc.png

数组的三个特点:

1.数组有若干个元素

2.元素的数据类型必须相同

3.数组中的数据元素是有序排列的

arr1[4]={1,2,3,4}

arr2[4]={4,3,2,1}

//这两个数组不一样

数组元素占用的字节长度都是相等的;

指向数组的指针的初始值就是数组的首地址;

int arr[4]={1,2,3,4}

每个元素占用的字节长度为:sizeof(int);

若sizeof(int)==2,假设数组的第一个元素a[0]的地址为0x00000001,则数组的第二个元素a[1]的地址为0x00000003,则数组的第三个元素a[2]的地址为0x00000005

所以说数组中的数据元素是有序排列的,那我们在查找数组元素的时候,只需要查找到第一个元素的地址,就能按照顺序找到相应的元素了。

#include

int main(void)

{

int arr[4]={1,2,3,4};

printf("arr[0]=%p\n",&arr[0]);

printf("arr[1]=%p\n",&arr[1]);

printf("arr[2]=%p\n",&arr[2]);

printf("arr[3]=%p\n",&arr[3]);

return 0;

}

运行结果:

fa7fce6e41e91b3b10b1026423501628.png

那我们再来看指针的性质:

【指针与整数的运算】

指针加n=指针原来的值+n*sizeof(指针所指变量类型)

指针减n=指针原来的值-n*sizeof(指针所指变量类型)

int *p=NULL

p=&arr[0]

p=0x000001

p+1=0x000001+1×sizeof(int)

p+2=0x000001+2×sizeof(int)

p+3=0x000001+3×sizeof(int)

#include

int main(void)

{

int arr[4]={1,2,3,4};

int *p=NULL;//声明一个指针

int i=0;

p=&arr[0];//等价于p=arr;

printf("sizeof(int)=%d\n",sizeof(int));

printf("arr[0]=%p\n",&arr[0]);

printf("arr[1]=%p\n",&arr[1]);

printf("arr[2]=%p\n",&arr[2]);

printf("arr[3]=%p\n",&arr[3]);

for(i=0;i<=3;i++)

{

printf("p+%d=%p\n",i,p+i);//循环输出指针的值

}

}

结果:

sizeof(int)=4

arr[0]=0019FF20

arr[1]=0019FF24

arr[2]=0019FF28

arr[3]=0019FF2C

p+0=0019FF20

p+1=0019FF24

p+2=0019FF28

p+3=0019FF2C

我们不难发现,我们可以通过指针来访问一维数组053eccdf68660f005aa0447548e57ff0.png

注意:以上对应关系的成立,指针p必须指向数组元素的首地址。

【那指针是如何访问数组的呢?】

#include

int main(void)

{

int arr[8]={1,2,3,4,5,6,7,8};

int i=0;

int *p=NULL;

p=arr;//指针指向首地址

printf("arr[i]\n");

for(i=0;i<8;i++)

{

printf("arr[%d]=%d\n",i,arr[i]);

}

printf("p+i\n");

for(i=0;i<8;i++)

{

printf("p+%d=%d\n",i,*(p+i));

}

return 0;

}

运行结果:

1e4ffad9324cf5a413a7b7d4cdec7aed.png

【访问指针的四种方法】

1.直接下标法

有一个数组a[i]

int *p=a等价于int *p=&a[0]

2.首地址自加法*(a+i)

数组名就是首地址:a等价于p

3.指针自加法*(p+i)

4.指针下标法p[i]

ceea6bfb3025a852f317037d1fe90f33.png

通过指针可以修改数组元素

int arr1[8]={省略};

int arr2[8]={省略};

int i=1;

int *p1=arr1;//使指针p指向arr的首地址

int *p2=arr2;

p1=p2;//改变指针指向

p++;//让指针指向下一个元素

注意:指针可以自加,但是数组名不可以自加,如arr1++,同时数组名也不能相互赋值,如arr1=arr2;

【用数组访问与用指针访问的区别】

1.访问方式不同

使用数组名访问时直接访问,使用指针是间接访问;

下标从0开始的原因:因为下标的实质是地址偏移量

2.占用空间不同

系统为arr分配了“sizeof(类型)*元素个数”个字节,给指针分配了“sizeof(类型)”个字节

换句话说使用指针可以降低空间复杂度,我们来看个程序:

#include

int main(void)

{

int arr[8]={1,2,3,4,5,6,7,8};

int *p=NULL;

p=arr;//指针指向首地址

printf("sizeof(arr)=%d\n",sizeof(arr));

printf("sizeof(*p)=%d\n",sizeof(*p));

return 0;

}

运行结果:

8e7f33039c65551d8b2aa880e7eef29f.png

很明显,系统为arr分配了32个字节,给指针分配了4个字节。

【让我们来回顾二维数组】

二维数组a[i][j],具有两个下标:行下标与列下标。

存储方式:先存储行下标,再存储列下标

即先在一个行下标内把a[0]列存满,再存a[1]列的元素。

a[0][0],a[0][1],a[0][2],a[0][3]

a[1][0],a[1][1],a[1][2],a[1][3]

【二维数组arr[ ][ ]的首地址有多种表达形式】

1.将二维数组看成元素是一维数组的元素

2.数组中第0行第0列的地址,&arr[0][0]

3.由于二维数组先存储行,所以第一行的第一个元素的地址,即&a[0]也是首地址

二维数组的元素个数:i×j

arr[2][3]={(1,2,3),(4,5,6)}

arr[2][3]={arr1[3],arr2[3]}

二维数组的首地址:&arr[0][0],&arr[0]

二维数组的数组名,不是首地址

int arr[i][j];

int *p=&arr[0][0];

此时p指向第一行第一个元素,即arr[0][0],而列指针是arr[i],指向第(i+1)列的元素。

不允许操作:p=arr或声明的时候使用int *p=arr(arr会指向一整行的地址)

那我们从a[0][0]跳到a[2][2],如何操作?

#include

int main(void)

{

int a[3][3]={1,2,3,4,5,6,7,8,9};

int i=0;

int j=0;

for(i=0;i<3;i++)

{

for(j=0;j<3;j++)

{

printf("a[%d][%d]=%d\t",i,j,a[i][j]);

}

printf("\n");

}

}

运行结果:

5c3af4de1cfdf9d90cf0f3a88872e3ef.png

a[0][0]是第一行第一列的元素 ,p=&[0][0]

a[2][2]是第三行第三列的元素

有一个指针p指向二维数组的首地址:&a[0][0]

指针的偏移量为:p+行数×行下标+列下标;

我们来看个例子:

#include

int main(void)

{

int a[3][3]={1,2,3,4,5,6,7,8,9};

int i=0;

int j=0;

int *p=NULL;

p=&a[0][0];

for(i=0;i<3;i++)

{

for(j=0;j<3;j++)

{

printf("a[%d][%d]=%d\t",i,j,a[i][j]);

}

printf("\n");

}

for(i=0;i<3;i++)

{

for(j=0;j<3;j++)

{

printf("p+N*%d+%d\t",i,j,*(p+3*i+j));

}

printf("\n");

}

printf("p+N*i+j\n");

}

运行结果:

da77edd10bee3cd14500eb68bc22d845.png

于是我们得到二维数组的四种表现形式,如下图

0bcd1ac5aa23ebe9b2b26ad7d3ced279.png

【二维数组的矩阵转置】

#include

int main(void)

{

int a[3][3]={1,2,3,4,5,6,7,8,9};

int i=0;

int j=0;

int *p=NULL;

p=&a[0][0];//p指向首地址

printf("转置前:\n");

for(i=0;i<3;i++)

{

for(j=0;j<3;j++)

{

printf("a[%d][%d]==%d\t",i,j,*(p+3*i+j));

}

printf("\n");

}

printf("转置后:\n");

for(j=0;j<3;j++)

{

for(i=0;i<3;i++)

{

printf("a[%d][%d]==%d\t",i,j,*(p+3*i+j));

}

printf("\n");

}

}

运行结果:

762c44bba8a8dc3494bc5516bdf1de4f.png

在for循环中,我们只需要把i换成j,j换成i就可以实现矩阵的转置,而不需要中间变量。

【二维数组形参的形式】

另外当我们用数组作为函数的形式参数,我们需要给函数传递一个数组首地址和一个数组长度

【将数组和数组长度分别作为形参】

void function(int array[],int size)

void function(int *arry,int size)

我们再来一个例子

【在一个升序数组中查找大于3的元素】

#include

void printarray(int *arr,int n)

{

int i=0;

for(i=0;i

{

printf("%4d",arr[i]);

}

printf("\n");

}

int main(void)

{

int arr[9]={1,2,3,4,5,6,7,8,9};

int *p=NULL;

p=arr;

while(*p<3)//while循环对指针p进行取值

{

p++;//如果p的值<3,则将地址下移,再继续与3比较

}

printarray(p,9-(p-arr));//经过3次自加后,指针由指向元素1到指向元素4

//那么指针p将以arr[3]为首地址传到函数中,(p-arr)为arr[3]与首地址arr[0]的差值,也就之间的个数

return 0;

}

运行结果:

7126a77ff86dd1cf7886fa7a0bfe30cb.png

【用二维数组形参函数来完成矩阵倒置】

#include

void function1(int *p,int M,int N)

{

int i,j;

for(i=0;i

{

for(j=0;j

{

printf("%d",*(p+i*N+j));//也可以用*p++:输出当前值,地址下移

}

printf("\n");

}

}

void function2(int *p,int M,int N)

{

int i,j;

for(j=0;j

{

for(i=0;i

{

printf("%d",*(p+i*N+j));//*(p+i*N+j)是指针偏移量法

}

printf("\n");

}

}

//注意形参M,N是行列长度,不是下标

int main(void)

{

int arr[3][3]={1,2,3,4,5,6,7,8,9};

int *p=NULL;

p=&arr[0][0];

function1(p,3,3);

printf("\n");

function2(p,3,3);

return 0;

}

运行结果:

6b836e9fe7e3df4fa5d113a3adaa7d51.png

二维数组形参的其他形式

55700d756c7a06cc4195c8f707509b4a.png

数组首地址表示法

fc60ae4cae144f7cdf9482835ea528bc.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值