目录
1. sizeof和strlen的对比
1.1 sizeof
首先我们要明确一点,sizeof是操作符,不是函数。是操作符!是操作符!是操作符!重要的事情说三遍。sizeof用于计算变量所占内存空间大小,单位是字节,如果操作数是类型的话,计算的是适用类型创建的变量所占内存空间的大小。
sizeof只关注占用空间的大小,不在乎内存中存放什么数据。
让我们上几个列子来给大伙体验下。
int a = 3;
int b = 114514;
char c = 'a';
char d = "Lebron";
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof(b));
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(c));
printf("%zd\n", sizeof(d));
printf("%zd\n", sizeof(char));
我们可以看到,sizeof并不会管你存放入什么数据,它在乎的只有你的数据的类型以及它所占空间的大小。
而且:
对于上面代码中出现的%zd可能会有些小伙伴觉得陌生,在这里我们做一个小小的补充。
C语言中的"%zd"是一种格式化输出的格式制符,用于输出带符号的整数类型变量。
具体来说,"%zd"用于输出带有"%d"格式的带符号数类型变量,其中"z"表示该整数类型的长度与指针类型相同。
在C语言中,"%zd"通常用于输出size_t类型的变量,size_t是一种无符号整数类型,用于表示内存大小或数组长度等非负整数值
还有最后一点要注意,关于求字符串的大小的,我们 时刻记住字符串的结尾计算机默认是给\0,而这个也会占一个字节。所以我们用sizeof操作一个字符串,其输出结果应该是字符个数+1。
1.2sizeof中的表达式不参与计算
如果sizeof的括号中有表达式的话,其表达式是不会参与计算的。
让我们来看一组代码:
int main()
{
int a = 8;
short b = 4;
printf("%zd\n", sizeof(b = a + 2));
printf("%d\n", b);
return 0;
}
求其输出的结果。这时候可能就会有同学的认为,哦a是8,8 + 2 = 10,所以b是10。而表达式b = a + 2最后由b说了算,b是short类型,其大小是2。所以最后输出的结果就是2和10。真的是这样吗?让我们揭晓答案。
结果是2和4,对了一半,其实别忘了我们小标题是什么——sizeof括号内的表达式不会参与计算。
接下来要讲的内容会涉及到一点点计算机编程原理上的内容,未来有机会我在单独发一篇博客大家一块块学习,我们一起从计算机的角度来看看这段代码。
- sizeof是如何看待b = a + 2的呢?前面说过sizeof只在乎你数据的类型,
- 首先识别出a是int类型,然后2也是int类型,所以a + 2其最后的结果10也是int类型。
- 但我们将其赋给的b却是一个short类型。short类型的大小只有2个字节,而int却有4个字节,这时候就会发生截断。
- 我们表达式最后不还是由b说了算吗?既然b是short类型只有2个字节,那就截断成只剩下2个字节。
- 所以sizeof(b = a + 2)最后的结果就是2个字节。
为什么sizeof中的表达式不计算呢?
- C语言是编译型语言
- 当我们创建test.c的源文件后,要经过 编译——>链接——>test.exe(可执行程序)——>运行 的这么一个过程。
- 而sizeof是在编译阶段就开始执行
- 但是我们的表达式是在生成可执行程序后才进行运算的。
- 也就是说,sizeof在编译阶段就已经开始执行识别出b是short类型,其大小为2,来到这一步后原先是sizeof(b = a + 2)的位子上便被2取代。
- 所以最后当程序进行到运行这个阶段时,代码压根就不存在b = a + 2这个表达式,所以就不会进行运算了。
- 上面讲的内容可能会有点难以理解,但请大家先记住就是这么一回事就行。待学到计算机原理的时候再回过头来看这一段内容时相信大家一定会有恍然大悟的感觉。
1.3 strlen
strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:
size_t strlen ( const char * str );
strlen 函数的统计是从参数 str 的首元素地址开始向后, \0 之前字符串中字符的个数。strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。
继续上代码
char arr2[] = "abc";
char arr3[] = "abcd";
char arr4[] = "abcde";
printf("%d\n", strlen(arr2));
printf("%d\n", strlen(arr3));
printf("%d\n", strlen(arr3));
输出结果:
这里很明显就能看出strlen跟sizeof的不同啦 ,sizeof会连同\0一起算进去,strlen函数则不会,遇到\0则不会。同时也要注意一点,就是strlen遇到人为添加的\0也会停下来。参考下图:
我们还要特别注意两种不同表现形式的字符数组所求出的字符串的长度的不同。
我们看到arr2所求出的长度3是符合预期的,但是arr1的长度却是匪夷所思的35.这是为什么呢?这是因为arr1在内存中的存储方式是如下这般
strlen是遇\0停下,而正如上图所示,c后面紧接着的不一定是\0,所以strlen函数会一直执行下去,直到找到\0才停下来。因此strlen(arr1)的结果是一个随机值。
1.4 sizeof与strlen的比较
sizeof | strlen |
|
|
2. 一些数组和指针的题目以及解析
从第一章开始到现在我i们已经学了不少知识点了,让我们最后再通过一些题目来继续学习和巩固吧。
2.1 ⼀维数组
int a[] = {1,2,3,4};
printf("%zd\n",sizeof(a));
printf("%zd\n",sizeof(a+0));
printf("%zd\n",sizeof(*a));
printf("%zd\n",sizeof(a+1));
printf("%zd\n",sizeof(a[1]));
printf("%zd\n",sizeof(&a));
printf("%zd\n",sizeof(*&a));
printf("%zd\n",sizeof(&a+1));
printf("%zd\n",sizeof(&a[0]));
printf("%zd\n",sizeof(&a[0]+1));
代码解析:
2.2 字符数组
arr = { }型
代码一(sizeof)
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", sizeof(arr));
printf("%zd\n", sizeof(arr + 0));
printf("%zd\n", sizeof(*arr));
printf("%zd\n", sizeof(arr[1]));
printf("%zd\n", sizeof(&arr));
printf("%zd\n", sizeof(&arr + 1));
printf("%zd\n", sizeof(&arr[0] + 1));
代码解析:
代码二 (strlen)
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", strlen(arr));
printf("%zd\n", strlen(arr + 0));
printf("%zd\n", strlen(*arr));
printf("%zd\n", strlen(arr[1]));
printf("%zd\n", strlen(&arr));
printf("%zd\n", strlen(&arr + 1));
printf("%zd\n", strlen(&arr[0] + 1))
代码解析:
arr = “ ”型
代码三(sizeof)
char arr[] = "abcdef";
printf("%zd\n", sizeof(arr));
printf("%zd\n", sizeof(arr + 0));
printf("%zd\n", sizeof(*arr));
printf("%zd\n", sizeof(arr[1]));
printf("%zd\n", sizeof(&arr));
printf("%zd\n", sizeof(&arr + 1));
printf("%zd\n", sizeof(&arr[0] + 1));
代码解析:
代码四 (strlen)
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));
代码解析:
char* p = “ ”型
代码五 (sizeof)
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))
代码解析:
代码六 (strlen)
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));
代码解析:
2.3二维数组
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]));
代码解析:
3. 总结
以上就是我要介绍的指针的全部内容了,我们指针这个专题就到此告一段落了,未来如果还有其他新的想法或者新的知识点我都会第一时间进行补充。
总的来说,指针是非常非常重要的一个知识点,是一个重难点。但我相信,再难的东西也是人想出来的,只要肯努力去学习,去熟悉,还是可以学好C语言的。
希望指针这个专题讲到的知识点对正在学习的你能真正有所帮助。感谢每个看到这里的人。
有任何的不足与错误也请多多包涵并不吝指出。
完