一、一维整型数组
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//16
sizeof(数组名),数组名表示的是整个数组,计算的就是以字节为单位的整个数组的大小
printf("%d\n",sizeof(a+0));//4
a不是单独放在数组奈布,也没有取地址,因此表示的是数组首元素的地址,a+0还是首元素的地址,地址大小是4/8个字节,具体大小取决于平台(32位平台4个字节,64位平台8个字节)
printf("%d\n",sizeof(*a));//4
数组名a代表的是首元素的地址,对a解引用得到的是数组首元素,int整型数据大小是4个字节
printf("%d\n",sizeof(a+1));//4
a不是单独放在数组奈布,也没有取地址,因此表示的是数组首元素的地址,a+1是第二个元素的地址,地址大小是4/8个字节,具体大小取决于平台(32位平台4个字节,64位平台8个字节)
printf("%d\n",sizeof(a[1]));//4
计算的是数组第二个元素的大小,int整型数据4个字节
printf("%d\n",sizeof(&a));//4
&a取出的是数组的地址,只要是地址,大小就是4/8个字节
printf("%d\n",sizeof(*&a));//16
&a取出的是数组的地址,对数组指针解引用找到的是整个数组,求的是整个数组的大小(*&抵消)
printf("%d\n",sizeof(&a+1));//4
&a取出的是数组的地址,&a+1相当于从数组首元素地址的位置向后跳过一个数组大小,计算的仍然是地址的大小,只要是地址,大小就是4/8个字节
printf("%d\n",sizeof(&a[0]));//4
第一个元素的地址大小
printf("%d\n",sizeof(&a[0]+1));//4
第二个元素的地址大小,等价于&a[1]
总结:对数组名的理解,指针类型和指针运算的意义
二、一维字符数组(1)
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//6
sizeof(数组名),数组名表示的是整个数组,计算的就是以字节为单位的整个数组的大小,char整型数据大小是1个字节
printf("%d\n", sizeof(arr+0));//4
arr不是单独放在数组奈布,也没有取地址,因此表示的是数组首元素的地址,arr+0还是首元素的地址,地址大小是4/8个字节,具体大小取决于平台(32位平台4个字节,64位平台8个字节)
printf("%d\n", sizeof(*arr));//1
数组名arr代表的是首元素的地址,对arr解引用得到的是数组首元素,char整型数据大小是1个字节
printf("%d\n", sizeof(arr[1]));//1
计算的是数组第二个元素的大小,char整型数据大小是1个字节
printf("%d\n", sizeof(&arr));//4
&arr取出的是数组的地址,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&arr+1));//4
&arr取出的是数组的地址,&arr+1相当于从数组首元素地址的位置向后跳过一个数组大小,计算的仍然是地址的大小,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//4
第二个元素的地址大小
printf("%d\n", strlen(arr));//随机值
strlen计算字符串长度的时候,数到'\0'为止,因为在初始化字符串的时候就没有在结尾放'\0',所以不知道什么时候会停止读取
printf("%d\n", strlen(arr+0));//随机值
依然是从字符数组首元素地址向后找'\0'
printf("%d\n", strlen(*arr));//err
strlen只能接收地址,会把首元素当成地址,会发生野指针问题,进行非法访问报错
printf("%d\n", strlen(arr[1]));//err
将数组第二个元素当做地址传给strlen。依然是非法地址报错
printf("%d\n", strlen(&arr));//随机值
&arr取出的是数组的地址传给strlen,strlen将传入的任何地址当做字符地址去解读
printf("%d\n", strlen(&arr+1));//随机值-6
&arr取出的是数组的地址,&arr+1相当于从数组首元素地址的位置向后跳过一个数组大小,相较于之前得到的随机值会减少字符数组的元素个数的长度(-6),但仍然是随机值
printf("%d\n", strlen(&arr[0]+1));//随机值-1
将数组第二个元素的地址传给strlen,相较于之前得到的随机值会减少数组第一个元素的长度(-1),但仍然是随机值
三、一维字符数组(2)
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7
sizeof(数组名),数组名表示的是整个数组,计算的就是以字节为单位的整个数组的大小,char整型数据大小是1个字节,这种初始化方式会在结尾放一个'\0',因此大小要+1
printf("%d\n", sizeof(arr+0));//4
arr不是单独放在数组奈布,也没有取地址,因此表示的是数组首元素的地址,arr+0还是首元素的地址,地址大小是4/8个字节,具体大小取决于平台(32位平台4个字节,64位平台8个字节)
printf("%d\n", sizeof(*arr));//1
数组名arr代表的是首元素的地址,对arr解引用得到的是数组首元素,char整型数据大小是1个字节
printf("%d\n", sizeof(arr[1]));//1
计算的是数组第二个元素的大小,char整型数据大小是1个字节
printf("%d\n", sizeof(&arr));//4
&arr取出的是数组的地址,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&arr+1));//4
&arr取出的是数组的地址,&arr+1相当于从数组首元素地址的位置向后跳过一个数组大小,计算的仍然是地址的大小,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//4
第二个元素的地址大小
printf("%d\n", strlen(arr));//6
strlen计算字符串长度的时候,数到'\0'为止,因为在初始化字符串的时候在结尾放了'\0',所以读到最后一个字符就停止了
总结:1.strlen是求字符串长度的库函数,关注的是字符串中的'\0',统计的是'\0'之前出现的字符个数
2.sizeof只关注操作符,关心的是占用内存空间的大小,不在乎其中放了设么内容
printf("%d\n", strlen(arr+0));//6
依然是从字符数组首元素地址向后找'\0'
printf("%d\n", strlen(*arr));//err
strlen只能接收地址,会把首元素当成地址,会发生野指针问题,进行非法访问报错
printf("%d\n", strlen(arr[1]));//err
将数组第二个元素当做地址传给strlen。依然是非法地址报错
printf("%d\n", strlen(&arr));//6
&arr取出的是数组的地址传给strlen,strlen将传入的任何地址当做字符地址去解读
printf("%d\n", strlen(&arr+1));//随机值
&arr取出的是数组的地址,&arr+1相当于从数组首元素地址的位置向后跳过一个数组大小,由于不知道内存中字符串后面的内容是什么,自然也不知道何时会碰到'\0'停下来
printf("%d\n", strlen(&arr[0]+1));//5
将数组第二个元素的地址传给strlen,相较于之前得到的长度会减少数组第一个元素的长度(-1)
四、字符串
char *p = "abcdef";
看似将常量字符串存入p中,实际放入的是常量字符串的首元素地址
printf("%d\n", sizeof(p));//4
计算的是常量字符串首地址的大小,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(p+1));//4
计算的是常量字符串中第二个字符所在的地址的大小,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(*p));//1
计算的是常量字符串中第一个元素的大小,char整型数据大小是1个字节
printf("%d\n", sizeof(p[0]));//1
计算的是常量字符串中第一个元素的大小,char整型数据大小是1个字节
printf("%d\n", sizeof(&p));//4
取的是字符指针的地址,二级指针也是一个指针,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&p+1));//4
取出的是p后面的一个字节的地址,只要是地址,大小就是4/8个字节
printf("%d\n", sizeof(&p[0]+1));//4
计算的是常量字符串中第二个元素的大小,只要是地址,大小就是4/8个字节
printf("%d\n", strlen(p));//6
相当于从字符串首地址向后数,又因为这种初始化方式默认在字符串末尾放了'\0',所以计算的就是该字符串的长度
printf("%d\n", strlen(p+1));//5
相当于从字符串中第二个元素的位置向后数,相较于之前得到的长度会减少字符串第一个字符的长度(-1)
printf("%d\n", strlen(*p));//err
strlen只能接收地址,会把首元素当成地址,会发生野指针问题,进行非法访问报错
printf("%d\n", strlen(p[0]));//err
将数组首元素当做地址传给strlen。依然是非法地址报错
printf("%d\n", strlen(&p));//随机值
从字符首地址的地址向后读,因为不知道字符首地址的地址的内容,所以不知道什么时候会停止
printf("%d\n", strlen(&p+1));//随机值
从字符首地址的下一个字节的地址向后读,因为不知道内容,所以不知道什么时候会停止,仍然是随机值
printf("%d\n", strlen(&p[0]+1));//5
相当于从字符串中第二个元素的位置向后数,相较于之前得到的长度会减少字符串第一个字符的长度(-1)
五、二维数组
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));//48
sizeof(数组名),数组名表示的是整个数组,计算的就是以字节为单位的整个数组的大小
printf("%d\n",sizeof(a[0][0]));//4
计算的是数组第一行第一列的元素的大小,int整型数据4个字节
printf("%d\n",sizeof(a[0]));//16
a[0]是第一行一维数组的数组名,单独放在sizeof内部,a[0]表示整个一维数组,计算的是第一行的总大小
printf("%d\n",sizeof(a[0]+1));//4
没有取地址,也没有单独放在sizeof内部,a[0]代表的是第一行首元素的地址,即第一行第一列元素的地址,加1计算的是第一行第二个元素的地址大小,只要是地址,大小就是4/8个字节
printf("%d\n",sizeof(*(a[0]+1)));//4
计算的是第一行第二个元素的大小,int整型数据4个字节
printf("%d\n",sizeof(a+1));//4
a虽然是二维数组的地址,但是没有取地址,也没有单独放在sizeof内部,所以a表示的是首元素的地址;二维数组的首元素是第一行,a就是第一行的地址;加1后跳过第一行,计算的是第二行地址的大小
printf("%d\n",sizeof(*(a+1)));//16
对第二行地址解引用,拿到第二行一维数组的数组名,计算的是第二行的大小——等价于a[1]
printf("%d\n",sizeof(&a[0]+1));//4
对第一行的数组名取地址,拿到的是第一行的地址,加1后拿到的是第二行的地址
printf("%d\n",sizeof(*(&a[0]+1)));//16
对第二行地址解引用,拿到第二行一维数组的数组名,计算的是第二行的大小
printf("%d\n",sizeof(*a));//16
a表示首元素的地址,就是第一行的地址,对一行地址的解引用,拿到的就是第一行一维数组的数组名
printf("%d\n",sizeof(a[3]));//16
拿到的是第四行数组的数组名(如果有第四行),计算的是一行一维数组的大小
总结:数组名的意义
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。