🌈write in front :
🔍个人主页 : @啊森要自信的主页
✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!
欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。
文章目录
- 前言
- 1️⃣ sizeof和strlen的对⽐
- ➡️sizeof
- ➡️ ➡️ strlen
- ➡️ ➡️ ➡️sizeof 和 strlen的对⽐
- 2️⃣ 数组和指针笔试题解析
- 💯 ⼀维数组
- 🎈字符数组
- 🎈🎈 `sizeof`计算`字符`数组
- 🎈🎈🎈`strlen`计算字符数组
- 💮 字符串数组
- 💮 💮 `sizeof`计算`字符串`数组
- 💮 💮 💮 `strlen`计算`字符串`数组
- 🏄 指针变量
- 🏄🏄 `sizeof`计算指针变量
- 🏄🏄🏄`strlen`计算指针变量
- 3️⃣ 总结
前言
通过前几节我们学了前面五节指针和学习了sizeof
操作符知识,本小节,阿森继续和你一起做一维数组和指针笔试题,🏂当然还有关于指针运算的笔试题,干货满满!让我们开始做题😁 !(🌷当然,宝子们,天气变化大,记得多注意保暖🌷)
1️⃣ sizeof和strlen的对⽐
➡️sizeof
C语言中sizeof
不是一个函数,而是一个编译期计算类型大小的内置操作符,所以它没有函数原型。
sizeof没有函数原型,它的语法形式是:
sizeof(类型名)
或
sizeof 变量名
类型名需要括号,变量名可以不需要括号。直接写类型名后面会报错。
sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
int main()
{int a = 66;printf("%zd\n", sizeof(a));//4printf("%zd\n", sizeof(int));//4printf("%zd\n", sizeof a);//这里可以省略括号printf("%zd\n", sizeof int);//err,类型名本身不能直接跟在sizeof后面,如sizeof int是错误的return 0;
}
当然,sizeof
也可以求数组的大小
数组名就是数组⾸元素(第⼀个元素)的地址。
sizeof(数组名)---->sizeof
中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节.
&数组名(如&a),这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
int main()
{int arr1[4] = { 0 };char arr2[4] = { 0 };printf("%zd\n", sizeof(arr1));//16 //单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩printf("%zd\n", sizeof(int [4]));//16 //int占用4个字节,int[4]数组占用4 * 4 = 16字节printf("%zd\n", sizeof(arr2));//4 //单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩printf("%zd\n", sizeof(char [4]));//4 //arr2是char类型的数组,char占1字节,char[4]数组占用4 * 1 = 4字节。return 0;
}
➡️ ➡️ strlen
strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:
size_t strlen ( const char * str );
统计的是从
strlen
函数的参数str
中这个地址开始向后,\0
之前字符串中字符的个数。
strlen
函数会⼀直向后找\0
字符,直到找到为⽌,所以可能存在越界查找。
int main()
{char arr1[20] = "abcdef";size_t len = strlen(arr1);//不包含结尾'\0',所以长度是6。printf("len = %zd\n", len);size_t sz = sizeof(arr1);//arr1这个数组变量占用的内存大小,即20字节。printf("sz = %zd\n", sz);char arr2[] = { 'a', 'b','c' };printf("%zd\n", strlen(arr2));//随机值,因为找不到\0char arr3[6] = "abcdef";//err//因为"abcdef"包含7个字符及结尾'\0',大于arr3的空间6字节,会导致越界。return 0;
}
➡️ ➡️ ➡️sizeof 和 strlen的对⽐
2️⃣ 数组和指针笔试题解析
💯 ⼀维数组
数组名就是数组⾸元素(第⼀个元素)的地址。
sizeof(数组名)---->sizeof
中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节.
&数组名(如&a),这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
char* arr1[10]; //存放字符指针的指针数组
int* arr2[10]; //存放整型指针的指针数组
int(*arr3[5])[6] ;//存放数组指针的数组指针数组
int(*arr4[5])(int);//存放函数指针的函数指针数组
int main()
{int a[] = { 6,7,8,9,10 };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));
}
细解:
- printf(“%d\n”, sizeof(arr));//20
sizeof
中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节. - printf(“%zd\n”, sizeof(a + 0));4/8
a没有单独放在sizeof内部,也没有&
取地址,因此a表示的就是数组首元素的地址,a+0
还是首元素的地址 ,是地址,那么大小就是4/8
,地址大小只与环境有关,32位是4个字节,64位就是8个字节 - printf(“%zd\n”, sizeof(*a)); //4
a
表示的就是数组首元素的地址,*a
就是首元素,首元素是6
,6
的类型是int
,大小就是4个字节 - printf(“%zd\n”, sizeof(a + 1));//4/8
a表示的就是数组首元素的地址,a+1就是第二个元素的地址,这里的计算的是第二个元素的地址的大小,地址大小只与环境有关,32位是4个字节,64位就是8个字节4/8 - printf(“%zd\n”, sizeof(a[1]));//4
a[1]
是数组的第二个元素(7),大小是4个字节 - printf(“%zd\n”, sizeof(&a));//4/8
&a - 取出的是数组的地址,但是数组的地址也是地址,是地址,大小就是4/8个字节 - printf(“%zd\n”, sizeof(*&a));//20
两种方法:1.&
和*
抵消
2.&a
的类型是数组指针,int(*)[5]
,*&a
就是对数组指针解引用访问一个数组的大小,是20个字节 - printf(“%zd\n”, sizeof(&a + 1));//4/8
&a+1是跳过整个数组后的一个地址,是地址,大小就是4/8个字节 - printf(“%zd\n”, sizeof(&a[0]));//4/8
&a[0]
是数组第一个元素的地址,是地址,大小就是4/8个字节 - printf(“%zd\n”, sizeof(&a[0] + 1));//4/8
&a[0] + 1
是第二个元素的地址,大小就是4/8个字节
🎈字符数组
🎈🎈 sizeof
计算字符
数组
int main()
{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));return 0;
}
细解:
- printf(“%d\n”, sizeof(arr)); //6
sizeof
中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节.,6个字节 - printf(“%d\n”, sizeof(arr + 0));// 4/8
arr+0
是数组第一个元素的地址,是地址,大小就是4/8个字节 - printf(“%d\n”, sizeof(* arr));// 1*
*arr
是首元素,计算的是首元素的大小,字符a
的类型是char
,是1个字节 - printf(“%d\n”, sizeof(arr[1]));// 1
arr[1]
是第二个元素字符b
,类型是char
是1个字节 - printf(“%d\n”, sizeof(&arr));//4/8
&arr
取得是整个数组的地址,是地址,大小就是4/8个字节。 - printf(“%d\n”, sizeof(&arr + 1));//4/8
&arr
取得是整个数组的地址,&arr+1跳
过整个数组,跳过了6个数组的元素,指向f后面,也是地址,大小就是4/8个字节。
🎈🎈🎈strlen
计算字符数组
int main()
{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));}
- printf(“%d\n”, strlen(arr));//随机值
arr
为数组名,也就是数组首元素的地址,但是字符数组中没有\0
,strlen
将会继续查找\0
,但是\0
是不知道在什么位置出现,所以无法计算,为随机值。 - printf(“%d\n”, strlen(arr + 0));//随机值
arr+0
也是数组首元素的地址,但是字符数组中没有\0
,strlen
将会继续查找\0
,但是\0
是不知道在什么位置出现,所以无法计算,为随机值。并且与前面的随机值一样 - printf(“%d\n”, strlen(*arr));//非法访问
//'a'-97//printf("%d\n", strlen(*arr));//err// //'b'-98//printf("%d\n", strlen(arr[1]));//err
注意
*arr
取出来的是字符a
,字符a对应的ASCII码值为97
,而97
为内存空间里的一个地址,
size_t strlen ( const char * str );,内存空间这块97地址传给strlen
,strlen
能直接访问这块不属于他的空间吗?
答案是不可以,因为它不属于strlen的作用域==一旦访问了就成非法访问了。(当然,arr[1]
也是如此)
-
printf(“%d\n”, strlen(arr[1]));//非法访问
注意
*arr1[1]
取出来的是字符b
,字符a对应的ASCII码值为98
,而98
为内存空间里的一个地址,
size_t strlen ( const char * str );,内存空间这块97地址传给strlen
,strlen
能直接访问这块不属于他的空间吗?
答案是不可以,因为它不属于strlen的作用域一旦访问了就成非法访问了,编译器就会报错–>访问冲突。
-
printf(“%d\n”, strlen(&arr));//随机值
&arr
虽然是数组的地址,但是也是指向数组的起始位置,那就是从数组首元素开始找嘛,没有\0
,找不到,那就是随机值了 -
printf(“%zd\n”, strlen(&arr + 1));//随机值-6
&arr+1
跳过整个数组,也就是跳过6个char
类型的元素从f后面的地址开始查找\0
,因此相比从头开始找少了6
个元素
-
printf(“%d\n”, strlen(&arr[0] + 1));//随机值-1
&a[0] + 1
是第二个元素的地址,比随机值少一个元素a
💮 字符串数组
💮 💮 sizeof
计算字符串
数组
int main()
{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));return 0;
}
解析:char arr[] = “abcdef\0
”//字符串别忘记有\0,
也占用一个char
空间
- printf(“%zd\n”, sizeof(arr));//7
数组名arr
单独放,计算的是整个数组的大小,7
个字节 - printf(“%zd\n”, sizeof(arr + 0));//4/8
arr+0
是数组首元素的地址,地址的大小是4/8个字节 - printf(“%zd\n”, sizeof(*arr));//1
*arr是数组的首元素,这里计算的是首元素(a)
的大小 ,类型为char
,大小为1
- printf(“%zd\n”, sizeof(arr[1]));//1
*arr是数组的首元素,这里计算的是第二个元素(b)
的大小 ,大小为1
- printf(“%zd\n”, sizeof(&arr));//4/8
&arr
- 是数组的地址,数组的地址也是地址,是地址就是4/8个字节 - printf(“%zd\n”, sizeof(&arr + 1));//4/8
&arr+1
,跳过整个数组,指向了数组的后边,4/8 - printf(“%zd\n”, sizeof(&arr[0] + 1));//4/8
&arr[0] + 1
是第二个元素的地址 是地址,那就是4/8<
/kbd>
小结
sizeof
计算变量或类型的大小,单位是字节(byte)
。%zd
格式说明符用于打印size_t
类型的值,这也是sizeof
的返回类型。- 字符串常量
"abcdef"
实际上是一个char数组,最后一个元素是'\0'
。所以sizeof(arr)
算出的是整个字符串占用的空间,包含结束符,即7
个字节。- 当
sizeof
操作数是数组时,它计算的是整个数组占用的字节数。当操作数是指针时,它计算的是指针变量本身占用的字节数,与它指向的对象大小无关。
💮 💮 💮 strlen
计算字符串
数组
int main()
{char arr[] = "abcdef";printf("%zd\n", strlen(arr));//arr也是数组首元素的地址 6printf("%zd\n", strlen(arr + 0));//arr + 0是数组首元素的地址,6//printf("%zd\n", strlen(*arr));//?传递是'a'-97,//err//printf("%zd\n", strlen(arr[1]));//?'b'-98//errprintf("%zd\n", strlen(&arr));//6, &arr虽然是数组的地址,但是也是指向数组的起始位置printf("%zd\n", strlen(&arr + 1));//随机值printf("%zd\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址 - 5return 0;
}
-
printf(“%zd\n”, strlen(arr));// 6
arr
也是数组首元素的地址,从a
地址开始,直到\0
停止,并且\0
不计算在内。 -
printf(“%zd\n”, strlen(arr + 0));//6
arr + 0
是数组首元素的地址,也是从a
地址开始,直到\0
停止,并且\0
不计算在内。 -
printf(“%zd\n”, strlen(*arr));//访问冲突
*arr传递是'a'
-97,字符a对应的ASCII码值为97
,而97
为内存空间里的一个地址,不属于数组arr的空间,那么就会访问冲突 -
printf(“%zd\n”, strlen(arr[1]));//访问冲突
注意:
(同样在字符串中,该结论同样适用)arr[1]
,因为arr[1]取出来的是字符'b',
字符'b'
的ASCII码值98同样是一个地址,但不是字符串起始地址。
传递*arr
或arr[1]
给strlen
,strlen
是无法直接访问这些地址处的内存空间的,因为这些地址都不属于strlen
的作用域。
而arr
名本身,以及arr
地址&arr
,都是字符串的起始地址,所以可以作为strlen
函数的参数。
📌小结:
strlen的参数必须是字符串的起始地址,才能正确计算长度。
arr
和arr+0
都是数组首元素的地址,传给strlen
计算长度都是6*arr
和arr[1]
访问到的是字符'a'
和'b'
,传给strlen
会报错&arr
虽然是数组的地址,但也指向数组第一个元素,所以strlen(&arr)
可以正确计算长度&arr+1
会指向字符串的其他位置,传给strlen
会产生随机值或者错误结果
🏄 指针变量
🏄🏄 sizeof
计算指针变量
int main()
{char* p = "abcdef";printf("%zd\n", sizeof(p));printf("%zd\n", sizeof(p + 1));printf("%zd\n", sizeof(*p));printf("%zd\n", sizeof(p[0]));printf("%zd\n", sizeof(&p));printf("%zd\n", sizeof(&p + 1));printf("%zd\n", sizeof(&p[0] + 1));return 0;
}
- printf(“%zd\n”, sizeof§);//4/8
p
是char*
类型的指针变量,存放的是a
的地址,是地址,那就是4或8字节。
- printf(“%zd\n”, sizeof(p + 1));4/8
p+1
计算的是'b'
字符的地址,依然是地址,大小也是4/8个字节。
- printf(“%zd\n”, sizeof(*p));// 1字节
p
访问的是'a'
字符,sizeof
计算的是字符类型大小,是1
字节。
- printf(“%zd\n”, sizeof(p[0]));//1字节
p[0]等价于*(p+0),(p+0)也等价pp[0]-- > *(p+0) - >*p
也是访问'a'
字符是1
字节。
- printf(“%zd\n”, sizeof(&p));//4/8
&p
是p指针变量的地址,是地址,大小也是4/8个字节。
- printf(“%zd\n”, sizeof(&p + 1));//4/8个字节
&p + 1
是指向p指针变量后面的空间,也是地址,是4/8个字节
- printf(“%zd\n”, sizeof(&p[0] + 1));//4/8
&p[0]+1
访问'b'
字符的地址,是地址就是4/8
个字节。
小结:
sizeof运算符计算:
- 指针变量时,计算的是指针变量本身占用的内存空间,4或8字节。
- 字符或整数类型时,计算的是该类型变量占用的内存大小,如char是1字节。
- 地址时,地址也是指针类型,计算的还是指针类型占用的内存大小,4或8字节。
🏄🏄🏄strlen
计算指针变量
int main()
{char* p = "abcdef";printf("%zd\n", strlen(p));printf("%zd\n", strlen(p + 1));//printf("%zd\n", strlen(*p));//printf("%zd\n", strlen(p[0]));printf("%zd\n", strlen(&p));printf("%zd\n", strlen(&p + 1));printf("%zd\n", strlen(&p[0] + 1));return 0;
}
运行该代码,打印strlen的结果解释:
-
printf(“%zd\n”, strlen(p ));//6
因为p
指向字符串"abcdef"
的首地址,strlen计算字符串长度就是6
。 -
printf(“%zd\n”, strlen(p + 1));//5
结果是5,
因为p+1指向从'b'
开始的字符串,长度是5
。 -
printf(“%zd\n”, strlen(*p));//访问冲突
*p
是'a'
字符,size_t strlen ( const char * str )
;strlen
接受一个地址,‘a’`字符不是地址,如果是的话,那又是访问ASCII码值然后报错。 -
printf(“%zd\n”, strlen(p[0])); //访问冲突
同理,p[0]
也是字符,不能用strlen。 -
printf(“%zd\n”, strlen(&p));随机值
&p是指针p
的地址,strlen
无法识别,结果是随机值。 -
printf(“%zd\n”, strlen(&p + 1))随机值;
同理,&p+1
找的是p
后面地址,然后开始在p
后面不断找\0
,也是随机值。
-
printf(“%zd\n”, strlen(&p[0] + 1));//5
因为&p[0]+1
指向从'b'
开始的字符串。
strlen
只能计算字符串常量或以'\0'
结束的字符串长度,其他情况如字符,地址都无法识别长度,可能导致随机值或报错。
3️⃣ 总结
本小节我们学习了sizeof和strlen对一维字符数组,字符串数组和指针变量进行练习,我们应该对指针有了更多的理解,但是他们都离不开我们以下的知识点。sizeof
用于计算变量或类型占用的内存空间(以字节为单位),它是编译期就能确定的常量。
strlen
用于计算字符串长度,但仅限于以'\0'
作为字符串结束标志的字符串。它需要在运行期扫描字符串计算长度,他接收地址,不能接收数值,否则就会访问编译器就会报错,造成访问冲突。
数组名就是数组⾸元素(第⼀个元素)的地址。
sizeof(数组名)---->sizeof
中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节.
&数组名(如&a),这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
如果你看到这里,让我们把掌声送给我们自己
感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘