一维数组和二维数组的使用和偏移

数组

常用的数组就是一维数组和二维数组。

一维数组

初始化

char str1[8] = {0};//数组每个元素都是char型,占一个字节
short str1[8] = {0};//数组每个元素都是short型,占两个字节
int str2[8] = {0};//数组每个元素都是int型,占四个字节

char str4[8] = {0}; //完全初始化。数组每个元素都是0
char str5[8] = {1,2,3}; //部分初始化,数组前三个元素是1,2,3,其他为0
char str6[] = {1,2,3,4,5,6}; //由元素来确定数组大小

数组传参

#include <stdio.h>

void fun(char buff1[],char buff2[],char size);
void main(void)
{
    char i,str1[]={1,2,3,4,5,6,7,8};
    char str2[8]={0};
    
    fun(str1,str2,8); 
    fun(&str1[0],&str2[0],8);
     
     for(i=0;i<8;i++)
     printf("str2[%d]=%d\r\n",i,str2[i]);
}

void fun(char buff1[],char buff2[],char size) 
void fun(char *buff1,char *buff2,char size)
{
     char i=0;
     for(i=0;i<size;i++)
    {
        buff2[i] = buff1[i]+1;
    }
}
 fun(str1,str2,8); 
 fun(&str1[0],&str2[0],8);

这两个传参方式是一样的,因为srt 和 &str[0] 都是表示数组首元素的地址。数组名str 其实是表示 数组首地址,不过数组首地址和数组首元素地址是同一个。

void fun(char buff1[],char buff2[],char size) 
void fun(char *buff1,char *buff2,char size)

这两个函数是一样的,都能接收数组地址进行操作。

二维数组

初始化

//2行3列
char str1[2][3] ={0}; //数组每个元素都是char型,占一个字节
short str2[2][3] ={0}; //数组每个元素都是short型,占两个字节
int str3[2][3] ={0}; //数组每个元素都是int型,占四个字节
  
int str4[2][3] = { {1, 2, 3}, {4, 5, 6} }; //完全初始化,每个元素都复值
int str5[2][3] = {0}; //所有元素都初始化为0 
int str6[2][3] = {1}; //只有数组第一个值为1(arr1[0][0]为1),其他所有元素都初始化为0 
int str7[][3] = {1,2,3,4,5,6};//确定列,然后行由元素决定

int str7[][3] = {1,2,3,4,5,6}; //正确写法,确定列了可以由元素确定行
int str7[2][] = {1,2,3,4,5,6}; //错误写法,不可以确定行由元素确定列
int str7[][3] = {1,2,3,4,5,6,7}; //正确写法,不足整行的元素会自动补0

数组传参

#include <stdio.h>

void fun(char buff1[2][3],char buff2[2][3],char row,char col);

void main(void)
{
    char i,j,str1[][3]={1,2,3,4,5,6};
    char str2[2][3]={0};
    
    fun(str1,str2,2,3);
    fun(&str1[0],&str2[0],2,3);
    fun(&str1[0][0],&str2[0][0],2,3);//错误用法
     
     for(i=0;i<2;i++)
     for(j=0;j<3;j++)
     printf("str2[%d][%d]=%d\r\n",i,j,str2[i][j]);
}

void fun(char buff1[2][3],char buff2[2][3],char row,char col)
void fun(char buff1[][3],char buff2[][3],char row,char col)
void fun(char (*a)[3],char(*b)[3],char row,char col)
void fun(char **buff1,char **buff2,char row,char col) //错误
{
     char i=0,j=0;
     for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        buff2[i][j] = buff1[i][j]+1;
    }
}
   
fun(str1,str2,2,3);
fun(&str1[0],&str2[0],2,3);
fun(&str1[0][0],&str2[0][0],2,3);//错误用法

前两种传参方式是一样的,第一种是二维数组首地址,第二种是第0行首元素地址,是同一个地址。第三种是第0行第0列元素地址,也是同一个地址,而且执行效果是一样的,但是有警告,语法有问题,不建议使用。

void fun(char buff1[2][3],char buff2[2][3],char row,char col)
void fun(char (*a)[3],char(*b)[3],char row,char col)
void fun(char buff1[][3],char buff2[][3],char row,char col)
void fun(char buff1[2][],char buff2[2][],char row,char col) //错误
void fun(char **buff1,char **buff2,char row,char col) //错误

跟初始化时候一样,传参时也只可以确定列不确定行,不可以确定行不确定列。

在使用多维数组时,初始化或者传参时,第一维的数量是可以不写的,其他维度必须写

那为什么不能用二维指针直接指二维数组呢?
因为二级指针是指向一级指针的指针,一级指针是取一次地址,二级指针是取两次地址。根据二维数组是连续存放的特性,取了一次地址之后,所有元素的地址就全部知道了,只需要指针的移动就可以遍历所有的元素了,不需要再取一次地址了。

数组的地址偏移问题
一维数组
#include <stdio.h>

void main(void)
{
   int a[10]={0};
   printf("   &a=%p\r\n",&a);
   printf("    a=%p\r\n",a);
   printf(" &a[0]=%p\r\n",&a[0]);
   //printf("a[0]=%p\r\n",a[0]);
   
   printf(" &a+1=%p\r\n",&a+1);
   printf("  a+1=%p\r\n",a+1);
   printf("&a[0]+1=%p\r\n",&a[0]+1);
   //printf("a[0]+1=%p\r\n",a[0]+1);
}
  
   

在这里插入图片描述从各个地址可以看出,&a、a、&a[0]表示的是同一地址,但是表示的含义不一样。

&a+1地址与&a相比,偏移了40个字节,即声明数组的空间大小。
a+1地址与a相比,偏移了4个字节,即数组中一个元素的空间大小。
&a[0]+1地址与&a[0]相比,偏移了4个字节,即数组中一个元素的空间大小。

&a指向整个数组的地址,偏移也是按照整个数组大小偏移的。
a 数组名表示的是数组首元素地址,按照一个元素大小偏移。
&a[0]表示数组首元素地址。按照一个元素大小偏移。

二维数组
#include <stdio.h>

void main(void)
{
   int a[2][3]={0};
   printf("   &a=%p\r\n",&a);
   printf("    a=%p\r\n",a);
   printf(" &a[0]=%p\r\n",&a[0]);
   printf("a[0]=%p\r\n",a[0]);
   printf("&a[0][0]=%p\r\n",&a[0][0]);
  // printf("a[0][0]=%p\r\n",a[0][0]);
   
   printf(" &a+1=%p\r\n",&a+1);
   printf("  a+1=%p\r\n",a+1);
   printf("&a[0]+1=%p\r\n",&a[0]+1);
   printf("a[0]+1=%p\r\n",a[0]+1);
   printf("&a[0][0]+1=%p\r\n",&a[0][0]+1);
   //printf("a[0][0]+1=%p\r\n",a[0][0]+1);
}

在这里插入图片描述

&a、a、&a[0]、a[0]、&a[0][0]表示的是同一地址,但是表示的含义不同。

&a+1地址与&a相比,偏移了24个字节,即声明数组的空间大小。
a+1地址与a相比,偏移了12个字节,即数组中一行元素的空间大小。
&a[0]+1地址与&a[0]相比,偏移了12个字节,即数组中一行元素的空间大小。
a[0]+1地址与a[0]相比,偏移了4个字节,即数组中一个元素的空间大小。
&a[0][0]+1地址与&a[0][0]相比,偏移了4个字节,即数组中一个元素的空间大小。

&a 指向整个数组的地址,偏移也是按照整个数组大小偏移的。
a 数组名表示的是数组首行地址,按照一行大小偏移。
&a[0] 表示数组首行地址。按照一行大小偏移。
a[0] 表示的是首行首元素的地址,按照一个元素大小偏移。
a[0][0] 表示的是首行首列的元素地址,按照一个元素大小偏移。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值