文章目录
前言
由于最近正在学习c,展示一下学习成果,巩固一下知识点,梳理一下自己对c语言常用的两个关键字,sizeof,strlen的认识
一、sizeof是干什么的?
首先sizeof是c语言提供的一个关键字,它的作用是用来计算某种类型的表达式的字节大小,比如定义一个变量,int a=0;此时sizeof(int)==sizeof(a)==4,所以sizeof()里面可以直接填类型名,可以是变量名
直接看例子:
1.表达式为整型的一维数组
下面的是源码
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
首先a作为数组名在,除了单独放在sizeof里面和&a的地址时表示的是整个数组,其它情况都表示数组首元素的地址(这是一个重点);
以下分析都是在32位操作台的情况:
1,sizeof(a):此时a单独放在sizeof里面则表示整个数组,所以sizeof(a)计算的是整个数组的大小,4个元素,每个元素为int型,则总的为16个字节。
2,sizeof(a + 0):此时a没有上面的两种情况,则表示首元素地址,a+0还是表示指向首元素的地址,32位操作台每个地址由32位地址线表示,所以每个地址的大小都是4个字节,64位操作台加倍。所以此时表达式计算的是一个地址的大小,为4个字节
3,sizeof(*a):同上,a没有单独放进sizeof表示首元素地址,*对其解引用,得到第一个元素,类型为int,则结果为4个字节。
4,sizeof(a + 1):a为首元素的地址,a+1指向下一个元素的地址,计算第二个元素地址的大小,结果为4。
5,sizeof(a[1]):a[1]表示第二个元素,计算第二个元素大小,结果为4。
6,sizeof(&a):&a表示整个数组的地址,但是它还是一个地址,地址的大小就是4个字节。
7,sizeof(*&a):&a表示整个数组的地址,但是值还是第一个元素地址,但是此时解引用得到的是整个数组,所以结果为16.
8,sizeof(&a + 1):&a表示整个数组的地址,所以加1的时候应该跳过整个数组,指向数组末尾结束的地址,因为还是一个地址,所以大小也是4.
9,sizeof(&a[0]):&a[0]取第一个元素的地址,地址大小为4.
10,sizeof(&a[0] + 1):&a[0]取第一个元素的地址,加1表示的是第二个元素的地址,大小为4.
下图为运行结果:
2.字符类型的一维数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
1,sizeof(arr):arr单独放在sizeof表示整个数组,char类型每个大小为一个字节,所以总的为6个字节。
2,sizeof(arr + 0):首元素地址加0还是表示首元素地址,地址大小为4字节。
3,sizeof(*arr):对首元素地址解引用得到第一个元素,char类型的变量为1个字节,结果为1。
4,sizeof(arr[1]):arr[1]表示数组第二个元素,也是char类型,大小为1个字节。
5,sizeof(&arr):&arr表示整个数组的地址,地址大小为4个字节。
6,sizeof(&arr + 1):&arr表示整个数组的地址,加1跳过整个数组,还是一个地址,指向数组末端的一个地址,大小为4。
7,sizeof(&arr[0] + 1):首元素地址加1,指向第二个元素,还是一个地址,大小为4。
运行图:
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
此时数组默认以‘\0’结尾,会自己在末尾加上‘\0’,所以数组应该有七个元素分别为:a,b,c,d,e,f,\0
1,sizeof(arr):同上,arr表示整个数组,7个元素,char类型,总的为7个字节。
2,sizeof(arr+0):第一个元素地址,大小为4.
3,sizeof(*arr):第一个元素解引用,char类型,大小为1.
4,sizeof(arr[1]):arr[1]表示第二个元素,所以大小也为1.
5,sizeof(&arr):&arr表示整个数组的地址,地址大小为4.
6,sizeof(&arr+1):&arr表示整个数组的地址,加1跳过整个数组,是指向数组末尾的一个地址,大小为4.
7,sizeof(&arr[0]+1):首元素地址加1,指向第二个元素,还是一个地址,大小为4.
运行图:
char* p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
由p指向字符串的首地址
1,sizeof§:指针变量p存放的是地址,p指向首元素,地址大小为4.
2,sizeof(p + 1):p+1指向第二个元素,还是地址,大小为4.
3,sizeof(p):解引用首元素的地址p,得到首元素,char类型,大小为1.
4,sizeof(p[0]):p[0]可以理解为*(p+0),也可以将p看为数组的数组名,所以应该为首元素的大小,结果为1.
5,sizeof(&p):取p的地址,类型为char*,但是还是一个地址,大小为4.
6,sizeof(&p + 1):&p的地址加1,指向指针变量p地址后面的地址,还是地址,不过是指针变量的地址,地址大小为4.
7,sizeof(&p[0] + 1):p[0]表示首元素,&p[0]表示首元素的地址,首元素地址加1,是存放第二个元素的地址,大小为4.
运行图:
3.二维数组
此时数组名除了单独放在sizeof里面和&a的地址时表示的是整个数组,其它表示第一行的元素的地址,二维数组又可以看成多个一维数组,行数是这些一维数组的数组名,如:a[0]表示第一行的数组名,表示整个第一行数组。
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
1,sizeof(a):a为数组名单独放在sizeof,表示整个数组,整个数组12个元素,int类型,大小为4*12=48.
2,sizeof(a[0][0]):a[0][0]表示首元素,类型为int,所以大小也为4.
3,sizeof(a[0]):a[0]作为数组名代表第一行这整个一维数组,所以大小一个为16.
4,sizeof(a[0]+1):a[0]作为数组名,代表第一行首元素的地址,加1表示第一行第二个元素的地址,地址大小为4.
5,sizeof(*(a[0]+1)):a[0]作为数组名代表第一行首元素的地址,加1表示第一行第二个元素地址,指向第一行第二个素,此时解引用得到的是第一行的第二个元素,类型为int ,大小为4.
6,sizeof(a+1):数组名表示第一行元素的地址,加1指向第二行的首元素,表示第二行元素的地址,大小为4.
7,sizeof(*(a+1)):解引用(a+1)得到第二行数组,大小为16.
8,sizeof(&a[0]+1):a[0]作为数组名,&a[0]得到整个第一行的地址,加1表示第二行的地址,指向第二行的首元素,大小为4.
9,sizeof(*(&a[0]+1)):第一行的地址加1,表示第二行的地址,指向第二行的首元素,解引用得到第二行的元素,大小为16.
10,sizeof(*a):a表示第一行的地址,解引用得到第一行的元素,大小为16.
11,sizeof(a[3]):a[3]作为数组名表示第三行的整个数组,大小为16.
运行图:
二、strlen是干什么的?
strlen是对字符串进行操作的一个关键字,它的作用是用来计算一个字符串的长度,比如:char a[]=“abcdef”;此时计算的是字符串的字符个数为6,它以’\0’为一个字符串的结束标志,所以不将’\0’计算在内。
strlen的参数为一个指针变量或是地址。
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
此时arr数组内有六个元素:a,b,c,d,e,f
1,strlen(arr):arr为首地址,但是因为此数组没有’\0‘,而strlen是以’\0’为结束的标志,此时它的查找不知道在什么地方停止,所以会返回一个随机值。
2,strlen(arr + 0):arr为首元素地址,加0还是指向首元素,同上,返回随机值。
3,strlen(*arr):本义是会将’a‘的ASCII码值当做一个地址来向后查找,但是参数的类型不对,所以会报错
4,strlen(arr[1]):本义是会将’b‘的ASCII码值当做一个地址来向后查找,但是参数的类型不对,所以会报错
5,strlen(&arr):&arr表示整个数组的地址,但是还是指向首元素,还是没有结尾,返回随机值
6,strlen(&arr + 1):表示指向’\f’后面的那个地址,往后查找’\0’,还是返回随机值
7,strlen(&arr[0] + 1):&arr[0]表示首元素地址,加1表示第二个元素的地址,从第二个元素向后找,返回随机值。
运行图:
因为3,4会报错所以屏蔽掉
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
此时数组内部有七个元素:a,b,c,d,e,f,’\0‘
1,strlen(arr):arr为首地址,以’\0’结尾但’\0’不计数,从首元素查找,结果为6.
2,strlen(arr + 0):arr为首元素地址,加0还是指向首元素,同上,结果为6.
3,strlen(*arr):本义是会将’a‘的ASCII码值当做一个地址来向后查找,但是参数的类型不对,所以会报错
4,strlen(arr[1]):本义是会将’b‘的ASCII码值当做一个地址来向后查找,但是参数的类型不对,所以会报错
5,strlen(&arr):&arr表示整个数组的地址,但是还是指向首元素,从第一个往后找,结果为6.
6,strlen(&arr + 1):表示指向’\0’后面的那个地址,往后查找’\0’,还是返回随机值
7,strlen(&arr[0] + 1):&arr[0]表示首元素地址,加1表示第二个元素的地址,从第二个元素向后找,结果为5.
运行图:
char* p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
此时p存放首元素地址
1,strlen§:p为首元素地址,向后查找’\0’,结果为6.
2,strlen(p + 1):p为首元素地址,加1表示指向第二个元素,从第二个向后查找’\0’,返回结果为5.
3,strlen(*p):解引用得到第一个元素,本义将’a‘的ASCII码值当作地址向后找,返回随机值,但是参数类型不符合调用规则,报错。
4,strlen(p[0]):p[0]可以写为*(p+0),同3。
5,strlen(&p):以指针变量p的地址向后查找,此地址与a数组的地址无关,返回随机值。
6,strlen(&p + 1):以指针变量p后面的地址向后查找,此地址与a数组的地址无关,返回随机值。
7,strlen(&p[0] + 1):&p[0]表示取首元素地址,加1代表指向第二个元素,所以从第二个往后找,结果为5.
运行图:
总结
重要的事说三遍:
数组首元素的各种意义
数组首元素的各种意义
数组首元素的各种意义
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
最后,希望这篇文章可以帮助到读者 [狗头保命]