数组与地址,数组名到底是什么?

简介: 数组与地址,数组名到底是什么?

数组与地址,数组名到底是什么?

1.问题引出

2.分析错误代码

3.数组名是什么?

4.错误分析与修改

错误分析:

修改:

5.总结

1.问题引出


案例:设计一个函数,可以将整形数组的次序调换

例如:arr[5] = {1,2,3,4,5},输出形式为:arr[5] = {5,4,3,2,1}.


案例代码:


//能否可以正常排序?
#include <stdio.h>
void reverse(int* arr)
{
  int len = sizeof(arr) / sizeof(arr[0]);
  int top = 0;
  int tail = len - 1;
  while (top < tail)
  {
  int tmp = 0;
  tmp = arr[top];
  arr[top] = arr[tail];
  arr[tail] = tmp;
  top++;
  tail--;
  }
}
int main()
{
  int arr[] = { 1,2,3,4,5 };
  int len = sizeof(arr) / sizeof(arr[0]);
  reverse(arr);
  for (int i = 0; i < len; i++)
  {
  printf("%d ", arr[i]);
  }
  return 0;
}



我们来运行一下:

30bfda4ca7224971907f6f0ef3a5cfbd.png

我们发现结果并不是和我们想象的一样输出 5 4 3 2 1 ,而是对于原数组来说没有变化,这是为什么呢?


2.分析错误代码


首先3f19b3babf334ee6885182b08196ca95.png,按F10,点击调试——>窗口——>监视


在监视窗口中输入arr,这时是运行在主函数中,所以监控的是主函数中的arr


96213c4c085f4b358c21485d26e431cb.png



这里能够看到,arr中储存着5值


然后按F11进入函数内部,这时的监视窗口是这样:



1ce000cfa4914a27a6b878fcc84ce2ff.png


这里有个技巧:需要在监视中输入arr,5才能正常监视到:



9a905aab6fe2436c8934fe74cdbef71f.png


代码再往下走,我们发现len的值为1


98903d38100c400fb4573aefbc9fe1f4.png



但是int len = sizeof(arr) / sizeof(arr[0]),len的值应该为arr数组的长度啊,应该是5,为什么是1呢,这就需要了解数组名到底是什么


3.数组名是什么?


先探究数组名与数组元素首元素地址:


int main()
{
  int arr[10] = { 0 };
  printf("%p\n", arr);    //数组名
  printf("%p\n", &arr[0]);//数组首元素地址
  return 0;
}


结果:

9eb764848e5d4236a110de9c57633678.png


所以得出结论:数组名是数组首元素的地址

但是有两个例外:

1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节

2.&数组名,这里的数组名表示整个数组,&数组名取出的是数组的地址


验证一下sizeof(数组名):

int main()
{
  int arr[10] = { 0 };
  printf("%d", sizeof(arr));
  return 0;


结果:f90e360355d643ee85bed9eec52f839c.png


数组长度为10,int类型一个元素4个字节,所以输出40,这就说明:

sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小


验证 &数组名:


int main()
{
  int arr[10] = { 0 };
  printf("%p\n", arr);    //数组名
  printf("%p\n", &arr[0]);//数组首元素地址
  printf("%p\n", &arr);   //数组名取地址
  return 0;
}

e77ceebf6cb349c8a90a1955a4f17c42.png

结果:


发现这三个输出的地址都相同,它们有什么区别呢?我们再来探究一下


12f194a41b984226b2bbe201a87aaf23.png


arr与·&arr[0]一样,都是指向数组首元素地址,他们的类型都是int*

而&arr是整个数组的地址,&arr的类型为:int(*)[10]

由于这个数组的地址由数组首元素地址开头,所以这三个地址值从表面上看起来一样,但可以从他们的指针类型去区别他们


再对比一下:


int main()
{
  int arr[10] = { 0 };
  printf("arr:       %p\n", arr);    
  printf("arr+1:     %p\n", arr+1);
  printf("&arr[0]:   %p\n", &arr[0]);
  printf("&arr[0]+1: %p\n", &arr[0]+1);
  printf("&arr:      %p\n", &arr);  
  printf("&arr+1 :   %p\n", &arr+1);
  return 0;
}

cd75afd89302472381f60bef25e77081.png

结果:


分析:

165db43d7fca423482fe4d2de2687440.png

arr与&arr[0]都跳四个字节,也就是数组下一个元素地址

而&arr跳过了40个字节,它跳过了整个数组

从这里的计算,也可以体会出arr与&arr[0]的类型是int*,而&arr的类型是int(*)[10]


4.错误分析与修改


错误分析:

前面的内容我们知道了数组名是数组首元素地址,本质上是个指针

所以在函数中,就需要用int*去接收这个指针变量


void reverse(int* arr)
{
  int len = sizeof(arr) / sizeof(arr[0]);
  int top = 0;
  int tail = len - 1;
  while (top < tail)
  {
  int tmp = 0;
  tmp = arr[top];
  arr[top] = arr[tail];
  arr[tail] = tmp;
  top++;
  tail--;
  }
}


而在reverse内部,sizeof(arr)中的arr被判定成了指针,而不是一个数组,所以sizeof(arr)的值为4,sizeof(arr[0])也为4,所以len的值为1,而top=0,tail = len-1 = 0,top = tail,根本进不去下面的循环,所以数组才不会改变


修改:

因为数组作为参数,它的长度不可以在函数内部被计算出来,所以就要在主函数中把数组的长度计算出来,将数组长度作为参数传到函数中


#include <stdio.h>
void reverse(int* arr,int len)
{
  int top = 0;
  int tail = len - 1;
  while (top < tail)
  {
  int tmp = 0;
  tmp = arr[top];
  arr[top] = arr[tail];
  arr[tail] = tmp;
  top++;
  tail--;
  }
}
int main()
{
  int arr[] = { 1,2,3,4,5 };
  int len = sizeof(arr) / sizeof(arr[0]);
  reverse(arr,len);    //两个参数,一个是数组首地址,一个是数组长度
  for (int i = 0; i < len; i++)
  {
  printf("%d ", arr[i]);
  }
  return 0;
}


结果正确:

7ba9137966da4df59a48de25cb79f508.png


因为我们知道数组名其实就是一个指针,所以在函数的参数列表中,可以使用int arr[]去接受,也可以用int* arr去接受收


//这两种形式都可以
void reverse(int* arr,int len);
void reverse(int arr[],int len);


5.总结

1.一般情况下,数组名就是数组首元素的地址

2.有两个特殊情况:

sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

&数组名,这里的数组名表示整个数组,&数组名取出的是数组的地址。

3.有数组作为参数传入的函数中,想要计算这个数组的长度,在函数内部做不到,需要在主函数中将数组长度计算出来,将数组长度作为参数传入函数中,这才可以在函数中使用


目录
相关文章
|
2月前
|
C语言 C++
数组元素的指针
数组元素的指针
10 0
|
3月前
数组名
【2月更文挑战第3天】数组名。
22 2
|
10月前
数组名不表示首元素地址的两个特例
数组名不表示首元素地址的两个特例
|
5月前
|
存储 并行计算 C++
指针详解(二级指针、指针数组和数组指针、字符指针、二维数组传参、函数指针变量)(二)
指针详解(二级指针、指针数组和数组指针、字符指针、二维数组传参、函数指针变量)(二)
数组作为函数参数传参&数组名到底代表什么意义?
数组作为函数参数传参&数组名到底代表什么意义?
【学习笔记之我要C】详解数组名
【学习笔记之我要C】详解数组名
78 0
|
C语言
指针数组和数组指针的区别
指针数组和数组指针的区别
110 0
指针数组和数组指针的区别
|
Linux 编译器 C语言
C++中的一维数组与指针、一维数组用于函数参数
C++中的一维数组与指针、一维数组用于函数参数
140 0
C++中的一维数组与指针、一维数组用于函数参数