c语言分析sizeof、strlen与数组、指针之间的运算关系

本文主要围绕C语言中sizeof、strlen与数组、指针的运算关系展开。详细分析了一维数组、不同形式的字符数组以及二维数组在指针指向不同位置时,使用sizeof和strlen计算大小和长度的情况,有助于加深对数组和指针的理解。

        在用sizeof、strlen来求出数组在指针指向不同位置的情况下的大小和长度时,并对此时的指针指向的位置,式子的含义做出分析,以便加深对数组和指针的理解。

目录

前言:

1、一维数组和sizeof

2、字符数组(数组里是单个字符形式)和sizeof、strlen

2.1 与sizeof的计算

2.2 与strlen的计算 

3、 字符数组(数组里字符串形式)和sizeof、strlen

3.1 与sizeof的计算

3.2 与strlen的计算 

4、 字符数组(char* 形式)和sizeof、strlen 

4.1 字符数组(char* 形式)和sizeof

 4.2 字符数组(char* 形式)和strlen

5、二维数组和sizeof 

结语


前言:

数组名理解为首元素的地址,但是有两种情况例外:

        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与数组、指针之间的运算关系的分析,如果本文对你起到了帮助,希望可以点赞👍+关注😎+收藏👌哦!如果有遗漏或者有误的地方欢迎大家在评论区补充~!!谢谢大家!!

(❁´◡`❁)

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安权_code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值