数组名的理解,看这一篇就够了!!!

!!!以下是会涉及到的知识的讲解:

一:数组名的理解:

数组名是数组首元素的地址,但是有2个例外:

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

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

除了这两点以外,以外的数组名都是数组首元素的地址!!

二:两个理解(sizeof和strlen)

1、用法不一样

sizeof可以用类型(指针,整形等等)做参数,也可以用数组做参数。

strlen只能用char*做参数,且必须是以''\0''结尾的,才能计算出准确的值,否则,是随机值;另外strlen的参数不能是指针以外的类型(比如整形),否则结果为error(错误)。

2、功能不一样

sizeof的功能能是,获得保证,能容纳实现所建立的最大对象的字节大小。

strlen的功能是返回字符串的长度,该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符 \0 。返回的长度大小不包括 \0 。

3、意思不一样

sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。

strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。

!!!题目讲解:各种数组和sizeof或strlen的结合

 一:

第一种:sizeof+整形一维数组

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

  数组名单独放在sizeof内部,这里的a表示整个数组,计算的是整个数组的大小,单位是字节,总共16个字节。

2,printf("%d\n", sizeof(a+0));

  因为数组名没有单独放在sizeof内部,所以a表示数组首元素的地址,a+0还是数组首元素的地址,是地址,大小就是4/8个字节。

3,printf("%d\n", sizeof(*a));

  a在这里表示数组首元素的地址,*a就是首元素,大小4个字节

4,printf("%d\n", sizeof(a+1));

  数组名a在这里是数组首元素的地址,a+1是第二个元素的地址,地址的大小为4/8。

5,printf("%d\n", sizeof( a[1] ));

  第二个元素的大小就是4个字节

6,printf("%d\n",sizeof(&a));

  &a是整个数组的地址,但是整个数组的地址也是地址,所以大小4/8。

7, printf ( "%d\n" , sizeof ( *& a ));
  sizeof(*&a)中,*&抵消,所以就是sizeof(a),数组名单独放在sizeof内部,这里的a表示整个数组,所以16。(虽然不是sizeof(数组名),但是*&抵消就是了)

8,printf("%d\n",sizeof(&a+1));

  &a+1,相对于&a的地址去跳过了整个数组,但是即使跳过了整个数组,&a+1依然是地址,是地址就是4/8个字节。

9,printf("%d\n",sizeof(&a[0]));

  &a[0]是取出了首元素的地址,是地址大小就是4/8个字节。

10,printf("%d\n",sizeof(&a[0]+1));

  &a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,是地址大小就是4/8。

代码注释:

二: 

第二种:sizeof+字符数组(字符数组不含\0,除非有一个字符为\0)

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

  数组名单独放在sizeof内部,这里的arr表示整个数组,计算的是整个数组的大小,单位是字节,总共6个字节

2,printf("%d\n", sizeof(arr + 0));

 因为数组名没有单独放在sizeof内部,所以arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节

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

  arr表示数组首元素的地址,*arr就是首元素,首元素是'a',大小1个字节

4,printf("%d\n", sizeof(arr[1]));

  arr[1]就是第二个元素'b',大小是1个字节

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

  &arr是数组的地址,但是数组的地址也是地址,是地址就是4/8

6,printf("%d\n", sizeof(&arr + 1));

  &arr + 1是跳过整个数组后的地址,是地址就是4/8个字节

7,printf("%d\n", sizeof(&arr[0] + 1));

  &arr[0]是取出第一个元素的地址,然后+1是第二个元素的地址,是地址大小就是4/8个字节

代码注释:

三: 

第三种:strlen+字符数组(字符数组不含\0,除非有一个字符为\0 )

1,printf("%d\n", strlen(arr));

  随机值,因为字符数组arr中没有\0,arr是首元素地址,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值

2,printf("%d\n", strlen(arr + 0));

  随机值,arr + 0是首元素的地址,和第一个一样,也是随机值

3,printf("%d\n", strlen(*arr));

  error, arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97,strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参,strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了

4,printf("%d\n", strlen(arr[1]));

  error,因为arr[1]也是数组首元素,所以与3一致

5,printf("%d\n", strlen(&arr));

  随机值,&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计,所以也是随机值

6,printf("%d\n", strlen(&arr + 1));

  随机值,&arr + 1代表越过了整个数组后的地址,所以也是随机值,不知道什么时候才能碰上 \0 

7,printf("%d\n", strlen(&arr[0] + 1));

  &arr[0] + 1是第二个元素的地址,结果也是随机值

代码注释:

四:

第四种:sizeof+字符 串 数组(字符串末尾会自带 \0 )

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

  7,因为除开6个元素,\0 也会记入,总计7个元素,每个大小为1个字节

2,printf("%d\n", sizeof(arr + 0));

  arr + 0是首元素的地址 ,是地址所以大小4/8

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

  *arr其实就是首元素,1个字节,所以1,可以理解为*arr--> *(arr+0) -- arr[0]

4,printf("%d\n", sizeof(arr[1]));

  arr[1]是第二个元素,1个字节大小,所以1

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

  &arr虽然是整个数组的地址,但是地址就是4/8个字节

6,printf("%d\n", sizeof(&arr + 1));

  &arr + 1是跳过整个数组的地址,但也是地址,所以是4/8

7,printf("%d\n", sizeof(&arr[0] + 1));

  &arr[0] + 1是第二个元素的地址,是地址大小就是 4/8

代码注释:

五:

第五种:strlen+字符 串 数组(字符串末尾会自带 \0)

1,printf("%d\n", strlen(arr));

  6,因为返回的长度大小不包括 \0 

2,printf("%d\n", strlen(arr + 0));

  6,因为arr+0和arr一样,都是首元素地址。

3,printf("%d\n", strlen(*arr));

  err,因为,strlen的参数不能是指针以外的类型(比如整形,char型),否则结果为error,而*arr是首元素。

4,printf("%d\n", strlen(arr[1]));

  err,因为,strlen的参数不能是指针以外的类型(比如整形,char型),否则结果为error,而arr[1]是第二个元素。

5,printf("%d\n", strlen(&arr));

  6,&arr是整个数组的首地址,对于strlen来说该字符数组的首地址。

6,printf("%d\n", strlen(&arr + 1));

  随机值,因为&arr + 1,这个指针跳过了整个数组,数组以外往后去寻找,不知道什么时候才能找到\0。

7,printf("%d\n", strlen(&arr[0] + 1));

  5,因为&arr[0] + 1是第二个元素的首地址,往后寻找到 \0 刚好5个元素。

代码注释

六:

第六种:sizeof+赋给字符指针的字符串(字符串末尾自带 \0)

char * p="abcdef" 相当于把字符串abcdef的首地址给p了,并不是把"abcdef"放进了p里面

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

  p是一个指针,所以大小就是4/8

2,printf("%d\n", sizeof(p + 1));

  p+1是'b'的地址,是地址大小就是4/8个字节

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

  *p 就是'a',就是1个字节

4,printf("%d\n", sizeof(p[0]));

  p[0]--> *(p+0) --> *p ,就是'a',所以1个字节

5,printf("%d\n", sizeof(&p));

  4/8,&p -- char**,是存放指针p的指针,是地址就是4/8

6,printf("%d\n", sizeof(&p + 1));

  4/8,&p + 1,代表第二个元素的地址,,是地址大小就为4/8

7,printf("%d\n", sizeof(&p[0] + 1));

  4/8 , &p[0] + 1得到是'b'的地址,是地址大小就是4/8

代码注释:

七:

第七种:strlen+赋给字符指针的字符串(字符串末尾自带 \0)

char * p="abcdef" 相当于把字符串abcdef的首地址给p了,并不是把"abcdef"放进了p里面

1,printf("%d\n", strlen(p));

  6,第一个元素开始寻找 \0

2,printf("%d\n", strlen(p + 1));

  5,第二个元素开始寻找 \0

3,printf("%d\n", strlen(*p));

  error,*p是元素,是'a',strlen的参数不能是指针以外的类型(比如整形,char型),否则结果为error

4,printf("%d\n", strlen(p[0]));

  error,p[0]是元素,是'a',strlen的参数不能是指针以外的类型(比如整形,char型),否则结果为error

5,printf("%d\n", strlen(&p));

  随机值,因为&p是存放p这个指针的指针,已经和原来的字符串无关了,我们不知道这个二级指针里面的东西,以及会什么时候遇到 \0

6,printf("%d\n", strlen(&p + 1));

  随机值,因为&p + 1 是存放p这个指针的指针+1,已经和原来的字符串无关了,我们不知道这个二级指针里面的东西,以及会什么时候遇到 \0

7,printf("%d\n", strlen(&p[0] + 1));

  5,第二个元素开始寻找 \0

八:

第八种:sizeof+二维整形数组

        对于二维数组我们要知道,二维数组是一个存放一维数组的数组,将其中的每个一维数组看成一个元素,这样二维数组就可以看成一维数组了,所以对于a[3][4]来说,a就是数组名,其代表首元素的地址,这个时候首元素为第一行数组(也就是一个一维数组),a+1-1,会以一行为单位

        a[0]是这个一维数组的数组名,该数组名当单独放在sizeof中(sizeof(a[0])),或者前面&的时候(&a[0]),满足那两个条件,其所指的整个数组是它所对应的那一行数组,比如a[0]这个时候就代表第一行数组,a[1]这个时候就代表第二行数组.......现在对其进行+1-1,会以一行数组作为单位来跨越。

1,printf("%d\n", sizeof(a));

  3*4*4 = 48,所有元素的大小总和

2,printf("%d\n", sizeof(a[0][0]));

  4,第一行第一列的元素的大小

3,printf("%d\n", sizeof(a[0]));

  a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节

4,printf("%d\n", sizeof(a[0] + 1));

  a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&,a[0]表示数组首元素的地址,也就是a[0][0]的地址,所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节

5,printf("%d\n", sizeof(*(a[0] + 1)))

  4,就是在第四问的基础上加上*进行了解引用,计算的是就是第一行第2个元素的大小

6,printf("%d\n", sizeof(a + 1));

  4 / 8,a是数组首元素的地址,是第一行的地址 int(*)[4],a+1 就是第二行的地址,是地址大小就是4/8

7,printf("%d\n", sizeof(*(a + 1)));

  16,*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小,a+1 --> 是第二行的地址,int(*)[4],*(a+1) 就是解引用之后访问的第二行的数组

8,printf("%d\n", sizeof(&a[0] + 1));

  4/8,&a[0]是第一行的地址 (类型为int(*)[4]),&a[0]+1 是第二行的地址(类型为 int(*)[4]),是地址大小就是4/8

9,printf("%d\n", sizeof(*(&a[0] + 1)));

  16 计算的是第二行的大小,与第8问类似,不过进行了*解引用,对类型为int(*)[4]的解引用,应该得到4个整形的大小总和

10,printf("%d\n", sizeof(*a));

  16,计算的是第一行的大小,因为a就是数组名,其代表首元素的地址,这个时候首元素为第一行数组,对类型为int(*)[4]的解引用,应该得到4个整形的大小总和,*a --> *(a+0) --> a[0]

11,printf("%d\n", sizeof(a[3]));

  16,a[3]--> int [4],a[3]是第四行数组的首地址,虽然越界了,但是正如文中最上面知识点所说:其值在编译时即计算好了,sizeof只会在乎你的类型,然后知道了你的个数就行。

代码注释:

  • 33
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值