!!!以下是会涉及到的知识的讲解:
一:数组名的理解:
数组名是数组首元素的地址,但是有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。
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只会在乎你的类型,然后知道了你的个数就行。
代码注释: