一.基础知识:
①一般情况下数组名arr代表首元素地址,除了两个情况:
Ⅰ.sizeof(数组名)表示整个数组的大小
Ⅱ.&(数组名)表示取出整个数组的地址
②strlen是库函数,是求字符串长度的,关注的是字符串中的'\0',计算的是'\0'之前出现的字符的个数,strlen
的参数必须是一个指向字符串的指针(const char*
),而不是单个字符或整数。
③sizeof是操作符,只关注占用内存空间的大小,不在乎内存中放了什么
④地址的内存大小占4/8个字节
二.基于这些我们来练习一下下面这些题
Ⅰ.char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));由基础知识——①——Ⅰ和③知这里计算的是整个数组占用内存空间的大小,有6个字符,每个字符是1个字节,所以是6
printf("%d\n", sizeof(arr+0));arr不是单独在sizeof里面,所以表示首元素'a'的地址,+0还是首元素的地址,是4/8
printf("%d\n", sizeof(*arr));对首元素的地址解引用,表示'a'的大小,a是字符,占1个字节
printf("%d\n", sizeof(arr[1]));是第二个元素占用内存空间的大小,也就是b的大小,占1个字节
printf("%d\n", sizeof(&arr));由基础知识——①——Ⅱ和③、④知这里计算的是整个数组的地址占用内存空间的大小,地址内存是4/8
printf("%d\n", sizeof(&arr+1));&arr表示取出整个数组的地址,+1表示跳过整个数组,指向数组最后一个元素'f'后面的地址,地址内存是4/8
printf("%d\n", sizeof(&arr[0]+1));&arr[0]表示取出第一个元素的地址,+1——>第二个元素的地址,地址为4/8
printf("%d\n", strlen(arr));由基础知识——②,因为不知道这个数组的'\0'在哪里,所以'\0'之前出现的字符的个数是随机值
printf("%d\n", strlen(arr+0));arr不是单独在sizeof里面,所以表示首元素'a'的地址,和strlen(arr)一样
printf("%d\n", strlen(*arr));报错,表示对数组首元素地址解引用,为strlen('a'),由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(arr[1]));报错,表示strlen('b'),由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(&arr));取出整个数组的地址,也是从数组首元素开始向后数到'\0'字符的个数,由基础知识——②,因为不知道这个数组的'\0'在哪里,所以'\0'之前出现的字符的个数是随机值
printf("%d\n", strlen(&arr+1));比上一个随机值小6,因为跳过了一整个数组的地址,从'f'后面的地址开始向后数到'\0'结束
printf("%d\n", strlen(&arr[0]+1));比上面第一个随机值小1取出首元素的地址,+1表示第二个元素的地址,即从'b'向后,为随机值
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));整个数组的大小,字符串后面隐藏的\0,所以一共有7个字符,每个字符1个字节,共7个字节
printf("%d\n", sizeof(arr + 0));arr不是单独在sizeof里面,所以表示首元素a的地址,+0还是首元素地址,地址是4/8
printf("%d\n", sizeof(*arr));首元素地址解引用,是字符a,大小是1个字节
printf("%d\n", sizeof(arr[1]));是第二个元素b的大小,1个字节
printf("%d\n", sizeof(&arr));取出整个数组的地址,地址是4/8
printf("%d\n", sizeof(&arr + 1));跳过整个数组,指向'\0'后面的元素的地址,地址就是4/8
printf("%d\n", sizeof(&arr[0] + 1));第二个元素b的地址,地址就是4/8
printf("%d\n", strlen(arr));从首元素向后数直到'\0'结束,有6个字符
printf("%d\n", strlen(arr + 0));从首元素向后数直到'\0'结束,有6个字符
printf("%d\n", strlen(*arr));报错,表示对数组首元素地址解引用,为strlen('a'),由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(arr[1]));报错,表示strlen('b'),由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(&arr));取出整个数组的地址,也就是首元素的地址,即首元素往后数字符个数直到'\0'结束,是6
printf("%d\n", strlen(&arr + 1));跳过整个数组,指向'\0'后面的元素的地址,从这开始往后数字符个数直到'\0'结束,由基础知识——②,因为不知道后面的'\0'在哪里,所以'\0'之前出现的字符的个数是随机值
printf("%d\n", strlen(&arr[0] + 1));取出首元素地址,+1表示第二个元素的地址,从这里向后直到'\0'有5个字符
char* p = "abcdef";将首元素a的地址方p中
printf("%d\n", sizeof(p));p是指针变量,本质是地址,4/8
printf("%d\n", sizeof(p + 1));若p是0x0012ff40,那么p+1就是0x0012ff41,是地址,4/8
printf("%d\n", sizeof(*p));对地址p解引用,表示指针指向的a,字符a的大小是1个字节
printf("%d\n", sizeof(p[0]));——> *(p+0)——>*p
printf("%d\n", sizeof(&p));取出p的地址,而p是指针变量,所以&p是二级指针,也是地址,4/8
printf("%d\n", sizeof(&p + 1));取出p的地址,+1表示指向p的下一个内存空间的地址,地址就是4/8
printf("%d\n", sizeof(&p[0] + 1));&p[0]是a的地址,+1表示b的地址,地址是4/8
printf("%d\n", strlen(p));p存a的地址,所以是从a的地址向后数直到'\0'之间的字符个数,为6
printf("%d\n", strlen(p + 1));a的地址+1,就是b的地址,所以是从b的地址向后数直到'\0'之间的字符个数,为5
printf("%d\n", strlen(*p));报错,对a的地址解引用,为a,由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(p[0]));报错,为a,由基础知识——②知直接调用 strlen('a')
是不合法的,会导致编译错误或未定义行为。
printf("%d\n", strlen(&p));是取p的地址,p的地址我们不知道是多少,所以'\0'在哪也不清楚,是随机值 注意p的地址和p存的a的地址不一样
printf("%d\n", strlen(&p + 1));p是个指针变量,是4个字节,取出p的地址再+1,表示p的地址的第4个字节后面的地址向后数到'\0'之间的字符个数,后面的'\0'在哪也不清楚,是随机值 ,而我们不知道这4个字节中有无'\0'所以不能判断这个随机值和上一个随机值的联系
printf("%d\n", strlen(&p[0] + 1));&p[0]是a的地址,+1是指向b的地址,所以是从b的地址向后数直到'\0'之间的字符个数,为5
int a[3][4] = { 0 };二维数组
printf("%d\n", sizeof(a));整个二维数组的大小,是3×4×4=48
printf("%d\n", sizeof(a[0][0]));是第一行第一列元素的大小,为4
printf("%d\n", sizeof(a[0]));a[0]是第一行这个一维数组的数组名,单独放sizeof内部表示第一行这整个一维数组,它的大小为4×4=16
printf("%d\n", sizeof(a[0]+1));不是单独在sizeof中和在&后面,所以是首元素地址,就是第一行这个一维数组的第一列元素的地址,arr[0]
会自动转换为指向第一行首元素的指针,类型是 int*。arr[0] + 1
指向的地址是第一个元素 1
的地址加上 sizeof(int),
表示第一行第二个元素的地址,地址是4/8
printf("%d\n", sizeof(*(a[0]+1)));由上一条知a[0]+1是第一行第二个元素的地址,解引用就是第一行第二个元素,int类型大小是4
printf("%d\n", sizeof(a+1));arr
会自动转换为指向数组首元素的指针。对于二维数组,首元素是一个一维数组(int[4]
),因此 arr
会自动转换为指向一维数组的指针,类型是 int (*)[4]
。arr + 1
指向的地址是第一行的地址加上 sizeof(int[4])
,即加上一行的大小。地址是4/8
printf("%d\n", sizeof(*(a+1)));对第二行地址解引用,得到第二行。按指针运算来说*(a+1)=a[1],为4×4=16
printf("%d\n", sizeof(&a[0]+1));对第一行数组名取地址,+1得第二行地址,地址是4/8
printf("%d\n", sizeof(*(&a[0]+1)));对第二行地址解引用得到第二行,为4×4=16
printf("%d\n", sizeof(*a));a二维数组首元素的地址,即第一行地址,对第一行解引用得到第一行,为4×4=16
printf("%d\n", sizeof(a[3]));第4行,虽然这个数组没有4行,但是每行有4个int类型,sizeof其实是根据类型分析的,不是真的访问第4行,为4×4=16
sizeof根据类型访问:
eg:int a=10;sizeof(int)=sizeof(a)=4