在用sizeof、strlen来求出数组在指针指向不同位置的情况下的大小和长度时,并对此时的指针指向的位置,式子的含义做出分析,以便加深对数组和指针的理解。
目录
2、字符数组(数组里是单个字符形式)和sizeof、strlen
3、 字符数组(数组里字符串形式)和sizeof、strlen
4、 字符数组(char* 形式)和sizeof、strlen
前言:
数组名理解为首元素的地址,但是有两种情况例外:
1.sizeof(数组名),这里的数组名表示整个数组,求出整个数组的大小,单位字节
2.&数组名,这里的数组名也表示整个数组,即取出数组整组的地址,即+1跳过整个数组
此外,但凡不是以上两种情况,数组都表示的是首元素地址。
地址的大小只与机器的位数有关,32为机器下地址大小为4字节,64位机器下地址大小为8字节。
1、一维数组和sizeof
对整形数组和指针指向的不同位置进行以下细致分析:
#include<stdio.h>
int main()
{
//一维数组
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));//当sizeof里面只有数组名时,
//即sizeof求的是整个数组的大小,4*4=16字节
printf("%zd\n", sizeof(a + 0));//sizeof里面不止有数组名,因此这里的数组名表示首元素地址,
//+0表示首元素地址向后移动了0位,还是求首元素地址的大小,
//地址的大小只与机器位数有关,大小因此是4/8字节
printf("%zd\n", sizeof(*a));//数组名即为首元素地址,对其解引用得到首元素的值,
//因为是int类型数组,因此每个元素的空间是一个int类型,也就是4字节
printf("%zd\n", sizeof(a + 1));//a表示首元素地址,a+1表示第二个元素的地址,
//也就是数组元素2的地址,
//地址大小跟机器位数有关,因此等于4/8字节
printf("%zd\n", sizeof(a[1]));//a[1]表示数组a中第二个元素,
//元素大小跟数组类型有关,因此是4字节
printf("%zd\n", sizeof(&a));//sizeof(&a)这里的a是表示整个数组,取出数组a的地址,
//即拿到数组整组的地址,地址大小只与机器位数有关,大小因此是4/8字节
printf("%zd\n", sizeof(*&a));//取了a的地址,又对其进行解引用,
//因此*&a=a,sizeof(a)就是求整个数组的大小,4*4=16字节
printf("%zd\n", sizeof(&a + 1));//&a是取出数组a的整组地址,+1步长是整个数组,
//即跳过整个数组后的地址,但因为其还是一个地址,地址大小只与机器位数有关,大小因此是4/8字节
printf("%zd\n", sizeof(&a[0]));//a[0]表示第一个元素,&a[0]即为取出a[0]的地址,
//因此表达是首元素地址,地址大小只与机器位数有关,大小因此是4/8字节
printf("%zd\n", sizeof(&a[0] + 1));//a[0]表示第一个元素,&a[0]即为取出a[0]的地址,
//+1表示指向第二个元素的地址,地址大小只与机器位数有关,大小因此是4/8字节
return 0;
}
运行结果:

2、字符数组(数组里是单个字符形式)和sizeof、strlen
2.1 与sizeof的计算
在siezof下,对字符数组和指针指向不同位置进行以下细致分析:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", sizeof(arr));//sizeof(数组名)求出的是整组的大小,该数组有6个元素,
//因为是char类型数组,每个元素大小为1字节,因此整组元素大小为6*1=6字节
printf("%zd\n", sizeof(arr + 0));//sizeof里面不止有数组名,因此这里的数组表示首元素地址,
//+0表示首元素地址向后移动了0位,还是求首元素地址的大小,为4/8字节
printf("%zd\n", sizeof(*arr));//这里arr表示数组首元素地址,解引用后表示首元素的值,
//因为是char类型数组,每个元素大小为1字节
printf("%zd\n", sizeof(arr[1]));//arr[1]表示第二个元素的值,
//因为是char类型数组,每个元素大小为1字节
printf("%zd\n", sizeof(&arr));//sizeof(&arr),此时arr表示的是整个数组,
//因此是取出整个数组的地址,步长为整个数组,因为还是地址,因此大小为4/8字节
printf("%zd\n", sizeof(&arr + 1));//表示取数arr数组的整组地址,+1跳过整组地址后的地址,
//因为终究还是一个地址,因此大小为4/8字节
printf("%zd\n", sizeof(&arr[0] + 1));//arr[0]表示第一个元素,&arr[0]为首元素地址,
//+1表示第二个元素的地址,也就是‘b’的地址,地址大小还是4/8字节
return 0;
}
运行结果:

2.2 与strlen的计算
在strlen下,对字符数组和指针指向不同位置进行以下细致分析,strlen是遇到'\0'才会停下来,因此是计算'\0'之前的长度。且strlen函数的形参类型必须是指针。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", strlen(arr));//arr是首元素地址,所以从首元素开始向后数,
//数到'\0'停下来,但是这个数组没有'\0',因此strlen会一直向后数,知道遇到'\0'
//后面不知道什么时候遇到'\0',因此是一个随机值。
printf("%zd\n", strlen(arr + 0));//这里的数组表示首元素地址,
//+0表示首元素地址向后移动了0位,还是指向首元素,所以从首元素开始向后数,
//数到'\0'停下来,但是这个数组没有'\0',因此strlen会一直向后数,知道遇到'\0'
//后面不知道什么时候遇到'\0',因此也是一个随机值。
printf("%d\n", strlen(*arr));//对首元素地址解引用得到首元素的值,但是
//给strlen参数必须是指针,这里把a的ascii值97给到了strlen,strlen会把他当成一个地址,
//于是就会从97开始访问'\0',但是97这个地址不属于我们能访问的地址,就会出现非法访问了
printf("%d\n", strlen(arr[1]));//arr[1]表示第二个元素’b',传给strlen的也是一个值,
//情况同上
printf("%zd\n", strlen(&arr));//&arr是取出数组arr的整组地址,并且传给strlen,
//虽然其传的是整组地址,但是整组地址的地址号跟数组首元素的地址号是一样的,
//只是他们的+1之后的步长不一样而已,而strlen不会在乎传过来的地址步长是多少
//他依然会从该地址向数组的后面寻找'\0',因此长度还是一个随机值
printf("%zd\n", strlen(&arr + 1));//&arr + 1表示跳过整个数组,指向数组后面的地址,
//但是数组的后面什么时候遇到'\0',我们是不知道的,因此长度还是一个随机值
printf("%zd\n", strlen(&arr[0] + 1));//&arr[0]表示首元素的地址,+1意为第二个元素的地址
//因此是从第二个元素的地址还是往后找'\0',还是不知道什么时候遇到'\0',因此还是随机值
//或者可以说是从第一个元素向后找的随机值数-1
return 0;
}
运行结果:

3、 字符数组(数组里字符串形式)和sizeof、strlen
3.1 与sizeof的计算
在siezof下,对字符数组和指针指向不同位置进行以下细致分析:
#include<stdio.h>
int main()
{
char arr[] = "abcdef";//字符串末尾自动加'\0':[a b c d e f '\0']
printf("%zd\n", sizeof(arr));//sizeof(arr)意为整个数组的大小,'\0'也算一个元素,
//则总共7个元素,因为是char类型数组,因此每个元素大小1字节,7*1=7字节
printf("%zd\n", sizeof(arr + 0));//arr在这里表示首元素地址,
//+0表示首元素地址向后移动了0位,还是指向首元素地址,地址大小为4/8字节
printf("%zd\n", sizeof(*arr));//对首元素地址解引用得到首元素的值,即‘a',
//因为是char类型数组,因此每个元素大小1字节,因此’a'大小为1字节
printf("%zd\n", sizeof(arr[1]));//arr[1]表示第二个元素的值,即‘b',
//因为是char类型数组,因此每个元素大小1字节,因此’b'大小为1字节
printf("%zd\n", sizeof(&arr));//&arr表示取出arr的整组数组的地址,地址的大小始终为4/8
printf("%zd\n", sizeof(&arr + 1));//表示取出arr的整组数组的地址+1向后跨越了整个数组,
//指向了整个数组后边的地址,因为还是计算地址的大小,所以为4/8字节
printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]表示首元素,+1指向第二个元素的地址,
//还是计算地址的大小,所以为4/8字节
return 0;
}
运行结果:

3.2 与strlen的计算
在strlen下,对字符数组和指针指向不同位置进行以下细致分析:
#include<stdio.h>
int main()
{
char arr[] = "abcdef";//字符串末尾自动加'\0':[a b c d e f '\0']
printf("%d\n", strlen(arr));//arr是首元素地址,所以从首元素开始向后数,
//数到'\0'停下来,取前面元素个数的值,这里'\0'前面有6个元素,因此长度为6
printf("%d\n", strlen(arr + 0));//这里的数组表示首元素地址,
//+0表示首元素地址向后移动了0位,还是指向首元素,所以从首元素开始向后数,
//数到'\0'停下来,取前面元素个数的值,这里'\0'前面有6个元素,因此长度为6
printf("%d\n", strlen(*arr));//对首元素地址解引用得到首元素的值a,但是
//给strlen参数必须是指针,这里把a的ascii值97给到了strlen,strlen会把他当成一个地址,
//于是就会从97开始访问'\0',但是97这个地址不属于我们能访问的地址,就会出现非法访问了
printf("%d\n", strlen(arr[1]));//同上也为非法访问,arr[1]表示第二个元素的值
printf("%d\n", strlen(&arr));//&arr取出arr数组的整组地址,并且传给strlen,
//虽然其传的是整组地址,但是整组地址的地址号跟数组首元素的地址号是一样的,
//只是他们的+1之后的步长不一样而已,而strlen不会在乎传过来的地址步长是多少
//他依然会从该地址向数组的后面寻找'\0',因此长度是6
printf("%d\n", strlen(&arr + 1)); //&arr + 1表示跳过整个数组,指向数组后面的地址,
//但是数组的后面什么时候遇到'\0',我们是不知道的,因此长度还是一个随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0]首元素地址,+1指向第二个元素的地址,
//因此从第二个元素的地址开始往后数,长度为5
return 0;
}
运行结果:

4、 字符数组(char* 形式)和sizeof、strlen
4.1 字符数组(char* 形式)和sizeof
在sizeof下,对字符数组和指针指向不同位置进行以下细致分析:
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "abcdef";//字符串末尾自动加'\0':[a b c d e f '\0']
printf("%zd\n", sizeof(p));//注意这里p不是数组,是一个指针,并且指向首元素的地址,
//指针p的大小是根据机器的位数决定的,因此p的大小是4/8字节
printf("%zd\n", sizeof(p + 1));//p是指向首元素的地址,+1向右移动一位指向第二个元素’b',
//但是他依然是一个指针,因此大小是4/8之间
printf("%zd\n", sizeof(*p));//对指向首元素的指针p解引用,得到‘a'的值,
//因为是char*类型的指针,因此访问的大小是1字节
printf("%zd\n", sizeof(p[0]));//p[0]表示的也是第一个元素’a',因此也是1个字节的大小
printf("%zd\n", sizeof(&p));//对指针p取其地址,是地址就是4/8字节,
//这里他的类型是char**,也就是二级指针
printf("%zd\n", sizeof(&p + 1));//&p表示的是指针变量p的地址,+1表示指向p后面一个地址
//是地址就是4/8个字节
printf("%zd\n", sizeof(&p[0] + 1));//表示首元素的地址+1,指向第二个元素的地址,
//是地址就是4/8个字节
return 0;
}
运行结果:

4.2 字符数组(char* 形式)和strlen
在strlen下,对字符数组和指针指向不同位置进行以下细致分析:
#include<stdio.h>
int main()
{
char* p = "abcdef";//字符串末尾自动加'\0':[a b c d e f '\0']
printf("%zd\n", strlen(p));//p指向首元素a,从a开始向后数到'\0'停止,
//长度为6
printf("%zd\n", strlen(p + 1));//p+1指向第二个元素b,因此从b开始向后数,
//长度为5
printf("%zd\n", strlen(*p)); //对首元素地址解引用得到首元素的值,但是
//给strlen参数必须是指针,这里把a的ascii值97给到了strlen,strlen会把他当成一个地址,
//于是就会从97开始访问'\0',但是97这个地址不属于我们能访问的地址,就会出现非法访问了
printf("%zd\n", strlen(p[0]));//同上,也是非法访问
printf("%zd\n", strlen(&p));//取出指针变量p的本身的地址,从该地址向后访问,
//直到遇到'\0'停下来,但是我们不知道p的地址具体内容是什么,后面什么时候遇到'\0',
//因此长度是一个随机值
printf("%zd\n", strlen(&p + 1));//同上,取出指针变量p的本身的地址,
//+1访问到p后面的地址,我们不知道p的地址后面什么时候遇到'\0',
//因此长度是一个随机值
printf("%zd\n", strlen(&p[0] + 1));//首元素地址+1,指向第二个元素的地址
//因此从第二个元素开始向后面访问,直到遇到'\0',长度为5
return 0;
}
&p与&p+1示意图:

运行结果:
![]()
5、二维数组和sizeof
对整形二维数组和指针指向的不同位置进行以下细致分析。
在二维数组中,二维数组的数组名为首元素的地址。因为二维数组是由多个一维数组组成的,所以可以把二维数组的首元素地址看成是二维数组中第一行(第一个一维数组)的地址,二维数组第二个元素地址即二维数组中第二行(第二个一维数组)的地址。
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };//二维数组,里面元素都是0
printf("%zd\n", sizeof(a));//计算的是整个二维数组的大小,即3*4*4=48字节
printf("%zd\n", sizeof(a[0][0]));//a[0][0])为二维数组的首元素,该数组为int型数组,
//因此数组元素的大小为4字节
printf("%zd\n", sizeof(a[0]));//a[0]表示二维数组首行数组的首元素地址,即第一行的数组名,
//上文提过,sizeof(数组名)表示的是整个数组的大小,因此这里是求第一行数组的大小,
//一行4元素,大小为4*4=16字节
printf("%zd\n", sizeof(a[0] + 1));//a[0]表示第一行首元素地址,+1表示该行第二个元素地址,
//地址的大小都为4/8字节
printf("%zd\n", sizeof(*(a[0] + 1)));//a[0] + 1是第一行第二个元素的地址,
//对其解引用得到第一行第二个元素的值,该数组为int型数组,
//因此数组元素的大小为4字节
printf("%zd\n", sizeof(a + 1));//a表示二维数组的首行地址,+1后得到第二行的地址,
//也就是二维数组a中第二个一维数组的地址,地址的大小是4/8字节
printf("%zd\n", sizeof(*(a + 1))); //a + 1表示二维数组a中第二个一维数组的地址,
//对其进行解引用得到第二行首元素的地址,也就是第二行的数组名,*(a + 1)=a[1],
//因此sizeof(数组名)的结果是整组数组的大小,即第二个一维数组的大小,即4*4=16字节
printf("%zd\n", sizeof(&a[0] + 1));//&a[0]对首元素取地址,得到首行的地址,
//首行的地址+1步长为整个一维数组的步长,因此+1得到第二个一维数组的地址,即第二行地址,
//地址的大小始终为4/8字节
printf("%zd\n", sizeof(*(&a[0] + 1)));//&a[0] + 1是第二行地址,那么对其进行解引用,
//得到的是第二行的首元素地址,即第二行的数组名a[1],
//因此sizeof(数组名)的结果是整组数组的大小,即第二个一维数组的大小,即4*4=16字节
printf("%zd\n", sizeof(*a));//a在这里是第一个一维数组的地址(首行地址),
//对其进行解引用得到首元素地址,即第一行的数组名,
//因此sizeof(数组名)的大小是16字节
printf("%zd\n", sizeof(a[3]));//这里a[3]看似以及越界访问了,但是sizeof不会真的去计算内存,
//sizeof只需要其类型就能确认出大小是多少,而这个数组的类型是int [4],
//因此a[3]的大小逻辑与a[2] a[1]是一样的,他们大小都是16字节
return 0;
}
运行结果:

结语
以上就是sizeof、strlen与数组、指针之间的运算关系的分析,如果本文对你起到了帮助,希望可以点赞👍+关注😎+收藏👌哦!如果有遗漏或者有误的地方欢迎大家在评论区补充~!!谢谢大家!!
(❁´◡`❁)
本文主要围绕C语言中sizeof、strlen与数组、指针的运算关系展开。详细分析了一维数组、不同形式的字符数组以及二维数组在指针指向不同位置时,使用sizeof和strlen计算大小和长度的情况,有助于加深对数组和指针的理解。
6355





