什么是数组名
数组名是数组的首元素的地址
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9.10 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}}
两个例外
1.sizeof(数组名):这里的数组名不表示数组的首元素的地址,这里的数组名表示的是整个数组。所以sizeof(数组名)计算的是整个数组的大小,单位是字节。
2.&数组名:这里的数组名也表示的是整个数组的地址,&arr取出的是整个数组的地址。
#include<stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr);
printf("%d",sz);
return 0;
}
为啥sizeof(数组名)计算的结果是40字节呢?
因为这是int类型的数组,int类型的元素大小是4个字节,计算的结果也就是4*元素个数。
#include<stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
printf("%p\n",arr);
printf("%p\n",&arr)
return 0;
}
为啥&数组名和数组名的结果相同呢?
我们在举一个例子:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n",arr + 1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
}
从上面的程序中我们可以直观的看出:
arr+1比arr跳过了4个字节的空间,也就是1个整型的空间;
&arr+1跳过了40字节的空间,也就是当前整个数组的空间。
练习题
在进行练习之前,我们需要知道,地址的大小是4/8字节。
在32位机器上有32根地址线,每根地址线都会产生0/1这样的二进制数字,每个二进制数字的大小是1bit,组成32位长度的二进制序列,8个0/1组成一个字节,32个0/1的大小是4字节;
在64位机器上有64根地址线,同样的每根地址线都会产生0/1这样的二进制数字,每个二进制数字的大小的1bit,组成长度位64的二进制序列,8个0/1组成一个字节,64个0/1数字组成的二进制序列的大小是8字节。
sizeof -计算变量/数组大小的操作数
strlen -计算字符串长度的函数,需要向strlen参数部分需要传地址,需要string.h头文件
一维数组
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a)); //16 元素个数*元素类型
printf("%d\n", sizeof(a + 0)); //4/8 a是数组首元素的地址,a+0还是第一个元素的地址,地址的大小就是4/8字节
printf("%d\n", sizeof(*a)); //4 a表示数组首元素地址 *a表示数组第一个元素 sizeof(*a)就是数组第一个元素的大小
printf("%d\n", sizeof(a + 1)); //4/8 a是数组首元素的地址,地址+1指向第二个元素的地址,地址的大小是4/8个字节
printf("%d\n", sizeof(a[1])); //4 计算的是数组第二个元素的大小
printf("%d\n", sizeof(&a)); //4/8 &a取出的是数组的地址,数组的地址也是地址,是地址大小就是4/8字节
printf("%d\n", sizeof(*&a)); //16 &a取出的是数组的地址,*拿到整个数组的元素,求的是整个数组元素的大小
printf("%d\n", sizeof(&a + 1));//4/8 &a取出的是数组的地址,+1跳过整个数组,产生的是最后一个元素后面的地址 是地址,它的大小就是4/8,sizeof此时访问的是&arr+1的位置,属于数组越界,但sizeof只是看它的类型,并不会去进行访问arr+1后的空间
printf("%d\n", sizeof(&a[0])); //4/8 &a[0]取出的是第一个元素的地址
printf("%d\n", sizeof(&a[0] + 1));//4/8 数组第二个元素的地址
return 0;
}
这是在x32环境下运行的结果
字符数组
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr)); //6 sizeof只计算数组元素所占内存空间的大小,和\0无关
printf("%d\n", sizeof(arr + 0)); //4/8 首元素地址,地址的大小就是4/8字节
printf("%d\n", sizeof(*arr)); //1 arr没有单独放在sizeof内部,所以arr表示数组首元素地址,*arr后得到数组第一个元素的大小
printf("%d\n", sizeof(arr[1])); //1 这里表示的是数组第二个元素的大小
printf("%d\n", sizeof(&arr)); //4/8 &arr是数组的地址,地址的大小是4/8字节
printf("%d\n", sizeof(&arr + 1)); //4/8 &arr+1是从数组的地址开始向后跳过了整个数组的地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8 是数组第二个元素的地址
printf("%d\n", strlen(arr)); //随机值 arr数组中没有\0,会一直向后寻找
printf("%d\n", strlen(arr + 0)); //随机值 arr+0是数组首元素地址,但数组中没有\0,会一直向后寻找
// printf("%d\n", strlen(*arr)); //err arr是数组首元素地址,*a就是数组首元素,也就是'a',a的sacll码值是97,相当于传参的内容是97,告诉strlen函数从97地址处向后寻找\0并且统计字符个数,但我们字符数组的首元素的地址并不是97,访问的不是我们的空间,属于非法访问
// printf("%d\n", strlen(arr[1])); //err 同上
printf("%d\n", strlen(&arr)); //随机值 &arr取出的是整个数组的地址,是从首元素地址开始向后寻找\0
printf("%d\n", strlen(&arr + 1)); //随机值 数组地址+1意思是跳过整个数组,从最后一个元素后面开始寻找\0,因为是从&arr+1地址处开始寻找,所以随机值也就是&arr的随机值-arr的数组所占空间的大小
printf("%d\n", strlen(&arr[0] + 1));//随机值 &arr[0]取出的是第一个元素的地址,&arr[0]+1从第二个元素的地址开始向后寻找\0,产生的随机值比&arr的随机值少了1,因为是从&arr[0]+1开始寻找的
return 0;
}
同样是x32环境下的运行的结果
如果我们将下面两行代码放开,就会发生非法访问
printf(“%d\n”, strlen(arr));
printf(“%d\n”, strlen(arr[1]));
将0x 00 00 00 61这个16进制的地址转换为十进制地址是616+1=97,就是读取内存位置97时发生了非法访问。
因为用a,b,c,d,e,f初始化arr数组,arr数组又是局部变量,arr数组有是存放在栈区。
字符串
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";//[ a b c d e f \0 ]
//这里我们是用字符串初始化数组arr
printf("%d\n", sizeof(arr)); //7 sizeof计算的数组总大小,\0也是占内存空间的
printf("%d\n", sizeof(arr + 0)); //4/8 arr+0是首元素地址
printf("%d\n", sizeof(*arr)); //1 a-97 *arr是数组首元素
printf("%d\n", sizeof(arr[1])); //1 b-98 arr[1]数组的第二个元素
printf("%d\n", sizeof(&arr)); //4/8 &arr数组的地址,但是数组的地址依然是地址
printf("%d\n", sizeof(&arr + 1));//4/8 &arr+1跳过整个数组,是\0后面的地址,但是依然是地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8 是数组第二个元素的地址
printf("%d\n", strlen(arr)); //6 strlen函数统计的是\0之前元素的个数
printf("%d\n", strlen(arr + 0)); //6 依旧是首元素的地址,开始向后寻找\0
printf("%d\n", strlen(*arr)); //err 非法访问
printf("%d\n", strlen(arr[1])); //err 非法访问
printf("%d\n", strlen(&arr)); //6 取出的是整个数组的地址,但是是从首元素地址开始向后读取
printf("%d\n", strlen(&arr + 1));//随机值 &arr+1跳过整个数组,在arr数组后还有没有/0未知
printf("%d\n", strlen(&arr[0] + 1));//5 首元素地址+1是表示第二个元素的地址
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "abcdef";
//这里并不是将字符串abcdef整个的地址放到了指针变量p中,而是将字符串首元素'a'的地址放到了指针变量p中
printf("%d\n", sizeof(p)); //4/8 p是指针变量,计算的是指针变量的大小
printf("%d\n", sizeof(p + 1)); //4/8 p+1是字符‘b’的地址
printf("%d\n", sizeof(*p)); //1 *p - a
printf("%d\n", sizeof(p[0])); //1 p[0] -> *(p+0) -> *p
printf("%d\n", sizeof(&p)); //4/8 &p是指针变量p在内存中的地址 可以理解为char* *pp = &p;
printf("%d\n", sizeof(&p + 1)); //4/8 &p是跳过p之后的地址
printf("%d\n", sizeof(&p[0] + 1)); //4/8 &p[0]是a的地址,+1就是b的地址
printf("%d\n", strlen(p)); //6 从a的地址向后找\0
printf("%d\n", strlen(p + 1)); //5 从b的地址向后找\0
// printf("%d\n", strlen(*p)); //err
// printf("%d\n", strlen(p[0])); //err
printf("%d\n", strlen(&p)); //随机值 因为这里是从p的地址向后寻找\0
printf("%d\n", strlen(&p + 1)); //随机值 同上
printf("%d\n", strlen(&p[0] + 1)); //5 a的地址+1就是b的地址,从b向后数元素
return 0;
}
二维数组
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); //48 计算的是整个数组的大小,单位是字节3*4*4=16
printf("%d\n", sizeof(a[0][0])); //4 第一行第一个元素的大小
printf("%d\n", sizeof(a[0])); //16 二维数组的每一行可以认为是一个一维数组,那么a[0]可以理解为一维数组的数组名
printf("%d\n", sizeof(a[0] + 1)); //4/8 a[0]作为第一行的数组名,并没有单独放在sizeof内部,
//所以a[0]就是数组首元素的地址,就是第一行第一个元素的地址,所以a[0]+1就是第一行第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1))); //4/8 表示第一行第二个元素
printf("%d\n", sizeof(a + 1)); //4/8 a表示首元素地址,也就是第一行的地址,第一行的地址+1就是第二行的地址
printf("%d\n", sizeof(*(a + 1))); //16 对第二行的地址*就是访问到第二行 *(a+1) -> a[1]
printf("%d\n", sizeof(&a[0] + 1)); //4/8 a[0]是第一行的数组名,&就是取出第一行的地址,+1就是第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1))); //16 对第二行的地址*就是访问第二行的全部元素
printf("%d\n", sizeof(*a)); //16 a是首元素地址,等于第一行的地址,*就是访问第一行的所以元素
printf("%d\n", sizeof(a[3])); //16 sizeof不会去访问内存,而是根据类型判断大小,这里的类型是int类型,第四行的数组名
return 0;
}
总结:
数组名是首元素的地址
两个例外:
1.sizeof(数组名):这里的数组名是指整个数组,sizeof计算的空间大小是整个数组所占空间的大小;
2.&数组名:这里的数组名是指整个数组,&数组名取出的是整个数组的地址。
sizeof -是一个操作符
sizeof 计算的是对象所占内存空间的大小 -单位是字节
sizeof不在乎内存中存放的是什么,不会对内部存放的变量进行计算,只在乎存放的类型
strlen - 计算字符串长度的函数
从给定的地址向后访问字符,找到/0并且统计\0之前出现的字符个数
strlen参数部分需要传递地址
地址所占空间大小取决于当前机器是32位还是64位,32位机器下地址所占空间大小是4字节,64位机器下地址所占空间大小是8字节
非法访问:访问一块不属于你创建的空间或者molloc的空间
如果希望以上内容对您有所帮助!当然,如果文章出现错误,欢迎您在评论区或者私信我指出哦~