在c语言中,我们通常使用sizeof和strlen来计算各种长度,如字符串长度,整形或者字符型所占字节等等。但当结合到指针以后,这些题目便显得略微复杂了。那么,要如何正确的利用好sizeof和strlen呢?下文,就是我的学习经历。
首先,sizeof是操作符,是不需要额外添加头文件的。sizeof它的工作是计算变量所占字节大小,它不关心变量内容,它只关心类型。
而strlen是从属与string.h的库函数,它的功能是求字符串长度。其原型如下:
size_t strlen(const char *str);
它的工作原理是从传入的地址出发,向后进行查询,直到找到\0,它会返回从初始位置到\0的所有数据的数量。当没找到\0时,它会返回一个随机值。
而利用sizeof与strlen,我们可以更好的理解数组与指针的相关细微知识点。
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
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[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(*&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]));
printf("%d\n", sizeof(&arr[0]+1));
return 0;
首先,我们先小试牛刀,利用一维数字数组来试试看。
第一行打印的是arr的大小,在这里,arr单独存在于sizeof内部,所以它计算的是数组所有字节加起来的大小。答案是40.
第二行打印的是(arr+1)的大小,在这里arr不是表示数组名的,而是表示数组首元素地址,但凡是地址,大小就是4/8个字节。
第三行打印的是(*arr)的大小,这里的arr是首元素地址,所以它是计算arr[0]的大小,arr[0]就是1,1是int类型的数据,答案就是4.
第四行打印的(arr+1)的大小,这里arr也表示数组首元素,所以它计算的是2这个数字的地址,地址大小是4/8
第五行打印的是arr[1]的大小,arr[1]是2,是int类型的数据,其大小就是4.
第六行打印的是&arr的大小,计算的是arr整个数组的地址,是地址就是4/8.
第七行打印的是*&arr,先取地址后又解引用,相当于没有进行操作,所以算的是arr的大小,答案是40.
第八行打印的是(&arr+1)的值,相当于arr的地址整个加一,跳过40字节,但是打印出来的依旧是一个地址,答案是4/8.
第九行打印的是(&arr[0]),就是取1的地址,,最终结果就是arr[0]的地址,答案是4/8
第十行打印的与第九行类似,依旧是计算地址,所以答案依旧是4/8.
综上,我们简单概括一下几点:
1:sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的字节大小
2:&数组名,这里的数组名表示的也是整个数组,取地址以后得到的就是整个数组的地址.
3:除此以外所有数组名都是表示首元素的地址,无论是多了个*或者是[].
一维字符数组字符的sizeof计算与上面类似,我们重点讲一下字符数组与strlen的关系.
char arr[] = { 'a','b','c','d','e' };
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));
return 0;
如图,这个字符数组并不包含\0,所以他会导致许多问题,只有arr是作为整个数组的地址出现的时候,他才能得到一个值.
第一个打印的是arr的地址,也是首元素地址,它从首元素到最后都没有找到\0,于是返回结果是随机值.
第二个打印的和第一个打印的一样.
第三个打印的是*arr,解引用以后得到的是'a',a的ascii值是97,相当于把97作为地址传给了strlen,相当于传递了一个野指针,代码有问题.
第四个打印的问题与第三个一样.传递过去'b'的ascii值.
第五个打印的与第一个类似.得到随机值x.
第六个打印的是取了arr数组的地址,加一以后跳过整个数组,得到的结果是x-6.
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));
这张图是字符串数组,其中大部分答案与上面字符数组类似,但是他的内部是自带\0的,所有当它是以首元素为初始地址往后计算字符串长度时,是有具体结果的,比如这个字符串,他的结果就是6.
而对于数组指针又是有些不同.
char * arr[] = { "abcdef"};
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));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
第一行打印的是从arr首元素地址往后数直到\0的长度,是个固定值6.
第二行打印的是从arr首元素地址往后加一,在数直到\0的长度,是5.
第三个打印的是从解引用arr首元素,得到的是'a',ascii值为97,地址为野指针.
第四个与第三个类似,得到也是一个野指针.
第五个取的是arr数组的二级指针,与原先的'abcdef'没什么关系,所以得到随机值.
第六个同第五个的理.
第七个取的是arr[0]的地址再加一,于是是从'2'的位置开始往后数得到的结果就是5.
关于一维数组的内容我们已经介绍完毕,那么,二维数组呢?
int arr[3][5] = {0};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 1));
printf("%d\n", sizeof(arr[0]));
printf("%d\n", sizeof(*(arr[0]+1)));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
printf("%d\n", sizeof(arr[0][0]));
printf("%d\n", sizeof(&arr[0]));
printf("%d\n", sizeof(*(&arr[0] + 1)));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(&arr[3]));
printf("%d\n", sizeof(arr[0] + 1));
这是一个二维数组,我们通过这个二维数组,能够较为清晰的总结二维数组的知识点与sizeof的知识点.
第一行求的arr整个数组的大小,答案是60.
第二行求的是(arr+1)的地址的大小,这里的arr指的是arr的首元素的地址,那么arr数组的首元素是多少呢?很多人会认为是0,但其实不是,是arr[0].但是由于所有类型的地址大小一样,都是4/8,所以最终答案是8.
第三行求的是arr[0]的大小,arr[0]就是第一行,他的大小是4*5=20.
第四行求的是解引用后(arr[0]+1)的大小,就是arr[1]
第五行求的是&arr的大小,本质是一个地址,大小就是4/8.
第六行与第五行本质一样.
第七行求(&arr[0]+1)的值,本质是一个地址,大小4/8.
第八行求的是arr[0][0]的大小,就是int的大小,答案为4.
第九行求的是&arr[0]的大小,就是地址大小,答案为4/8.
第十行求的是arr[1]的大小,答案是20
第十一行求的是*arr,也就是arr[0]的大小,答案是20.
最后两行也都是地址,答案也都是4/8
就此,sizeof与strlen的大部分区别都已经标出来了,谢谢观看.