文章目录
- 一、回顾
- 二、字符指针
- 1.基本用法
- 2.误区
- (1)字符指针存放字符串首元素地址
- (2)输出问题
- 3.内存布局
- 三、字符指针与字符串数组
- 1.字符指针
- 2.字符串数组
- 四、面试题
- 1.One
- 2.Two
- 3.探究
- 4.补充
- 五、地址问题
- 六、字符数组与字符串数组
- 1.sizeof与strlen
- 含义
- 示例一
- 示例二
- 说明
- 代码三
- 代码四
- 总结
- 2.字符数组与字符串数组
- 示例一
- 示例二
- 总结
一、回顾
指针的主题,我们在(2条消息) C语言基础–初识指针_雨翼轻尘的博客-CSDN博客已经接触过了。我们知道了指针的概念:
1、 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2、 指针的大小是固定的4/8个字节(32平台/64平台)。
3、 指针有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
4、 指针的运算。
这一章节,我们继续探讨。
首先再来说明一下指针大小的问题。
看如下代码,输出结果是多少呢?
#include<stdio.h>
void test(int arr[]) {
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
}
int main() {
int arr[10] = { 0 };
test(arr);
}
分析一下这个函数:
void test(int arr[]) {//arr是指针变量
int sz = sizeof(arr) / sizeof(arr[0]);
//sizeof(arr)求指针大小-->4个字节(32平台)
//sizeof(arr[0])是求一个元素的大小,整型-->4个字节
//于是:sizeof(arr)/sizeof(arr[0])=4/4=1
printf("%d\n", sz);
}
经过分析,输出结果是1。
在编辑器里面运行也是1:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C0okbY2w-1672633238655)(D:\Typora图片\clip_image002-16725360305042.jpg)]](https://img-blog.csdnimg.cn/d6846a096ece4072bdaedeef411c26f4.png)
有的小伙伴说,我输出的是2啊?
别急,我配置一下这个地方。
如图,打开配置管理器:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hDE90dy1-1672633238658)(D:\Typora图片\clip_image004-16725360305467.jpg)]](https://img-blog.csdnimg.cn/72a6e008e1fc40e580a411bd074bf6bb.png)
将平台改为x64平台:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tih1PNAt-1672633238658)(D:\Typora图片\clip_image006-16725360305265.jpg)]](https://img-blog.csdnimg.cn/bdcaa869bf944c6f8dc215aaa91a9d93.png)
这时候,再次运行,发现结果就是2:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qvUB5YfU-1672633238659)(D:\Typora图片\clip_image008-16725360305041.jpg)]](https://img-blog.csdnimg.cn/0223ce233b6d45848bd76c4c903cb832.png)
简单分析一下:
void test(int arr[]) {//arr是指针变量
int sz = sizeof(arr) / sizeof(arr[0]);
//sizeof(arr)求指针大小-->8个字节(64平台)
//sizeof(arr[0])是求一个元素的大小,整型-->4个字节
//于是:sizeof(arr)/sizeof(arr[0])=8/4=2
printf("%d\n", sz);
}
二、字符指针
在指针类型中我们知道有一种指针类型为字符指针char*。
1.基本用法
之前我们初识指针的时候,说过用法。
如下定义:
char ch = 'w'; //字符变量ch
char* pc=&ch; //将字符变量ch的地址取出来,存在pc中。pc就被称为字符指针,类型就是char*
字符指针是一个指针变量,里面存放一个字符的地址。
将字符指针解引用,可以找到字符。
*pc = 'w';
2.误区
(1)字符指针存放字符串首元素地址
看如下代码:
int main(){
char* pstr="hello";
printf("%s\n",pstr);
return 0;
}
看第一行代码。
❓ 这里,是把一个字符串**“hello”**存放到pstr指针变量里面了吗?
🚗注意
代码char* pstr="hello";,
特别容易让我们以为是把字符串hello放到了字符指针pstr里面。
但本质是把字符串hello的首字母地址存放到了pstr中。
其实一般这里有两种理解:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CI5mb5gG-1672633238660)(D:\Typora图片\image-20230101103933536.png)]](https://img-blog.csdnimg.cn/a60d07da48a146aa81e7329463f4aa2a.png)
第一种理解是错误的!
第二种理解是正确的。a的地址赋值给了p。(常量字符串有什么需要注意的地方,后边讲解。)
可以输出看一下,p指针解引用之后的结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j3cbZOzQ-1672633238660)(D:\Typora图片\image-20230101105010294.png)]](https://img-blog.csdnimg.cn/67b1600da3924b4f80b8ae8b0c398dc6.png)
输出结果是a, p里面存放的是a的地址!
再想一个问题:
既然p里面存放的是a的地址,那么如果打印的话,是否能打印出来abcdef呢?
不妨试一下:
printf("%s\n",p);
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMf8EjHo-1672633238661)(D:\Typora图片\image-20230101105437952.png)]](https://img-blog.csdnimg.cn/69c6856ae62b4767a2cc5fb9d15171e9.png)
🍰总结
将字符串赋值给一个字符指针变量p,不是把字符串的内容赋值给p,而是把字符串首字符的地址赋给了p。
后边讲内存布局的时候,给大家补充一下为何输出结果是这样的。
(2)输出问题
举个例子:
int main() {
char arr[] = "abcdef"; //字符串存入arr数组里面
char* pc=arr;//pc字符指针存放数组名,即首元素地址。
printf("%s\n", arr);
printf("%s\n", pc);
return 0;
}
上面代码打印结果是多少呢?
因为将arr存给pc了,所以打印结果都是abcdef。
看一下输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J31avL3r-1672633238662)(D:\Typora图片\clip_image010-16725360305043.jpg)]](https://img-blog.csdnimg.cn/1c93c9f0c63d47beb2f4548e0855d64c.png)
3.内存布局
还是用上面的代码;
char* p="abcdef";
这行代码的意思,来探讨一下:
①将字符串"abcdef"存放在内存中某个位置。
"abcdef"是常量字符串。
既然"abcdef"字符串放在内存中,就会有它的起始地址。
②假设它的起始地址是:0x0012ff44,
那么字符指针变量p里面存放的就是该字符串的首字符地址,即0x0012ff44。
p能够通过该地址,找到该字符串。
如下图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JBrF6fjr-1672633238662)(D:\Typora图片\image-20230101110932300.png)]](https://img-blog.csdnimg.cn/fd411b3ae1c54ec5b9b0758da4d40a17.png)
③这时候将p打印出来
printf("%s\n",p);
遇到\0就停止打印,所以就可以打印出来整个字符串。
📖补充
有的小伙伴可能不太理解为何打印整个字符串,这里解释一下:
-
打印一个字符,用
%c,p里面存的是a的地址,*p就是a。 -
打印整个字符,遇到**“\0”**停止,用
%s,p里面存的就是a的地址。直接把p放在后面,就从p存的地址处开始打印一个字符串,就能打印出“abcdef”。
给大家看一下:
①这里要用*p:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qgWRqKCk-1672633238663)(D:\Typora图片\clip_image015.png)]](https://img-blog.csdnimg.cn/59d6922b91ac470098be6a588122402d.png)
②这里要用p:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z2NfjssZ-1672633238664)(D:\Typora图片\clip_image018-16725360305396.jpg)]](https://img-blog.csdnimg.cn/4dfd62469a264456b6c1c49d64d3471b.png)
最后再强调一下,
字符串要赋给指针变量p,不是把字符串的内容赋给p,而是把这个字符串的首字母的地址赋给了p。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPlxZVsH-1672633238664)(D:\Typora图片\clip_image020-16725360305689.jpg)]](https://img-blog.csdnimg.cn/b8175e9796684399a1da9dffb628ac8c.png)
三、字符指针与字符串数组
可能上边大家会有点晕,这里梳理一下字符指针与字符串数组。
1.字符指针
还是这行代码:
char* p="abcdef";
之前我们说过,这里的"abcdef"是常量字符串,常量字符串有什么需要注意的地方呢?
- 可以通过字符指针输出字符串
int main(){
char* p="abcdef";
printf("%s",p);
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CfSMBG75-1672633238665)(D:\Typora图片\image-20230102105524204.png)]](https://img-blog.csdnimg.cn/3b5e5262373e43ee88ac2758b237c534.png)
也可以输出部分字符串:
int main(){
char* p="abcdef";
printf("%s",p+2);
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cyc9wUGu-1672633238665)(D:\Typora图片\image-20230102105621686.png)]](https://img-blog.csdnimg.cn/ae15c8dd78ee4b59bccdab3177537719.png)
- 字符指针里面存放的是常量字符串首字符的地址,可以通过地址找到字符串每个字符。
比如我们可以输出看一下:
int main(){
int i=0;
char* p="abcdef";
for(i=0;i<7;i++){
printf("%c",*(p+i));
}
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FMkcZVdm-1672633238666)(D:\Typora图片\image-20230102110126255.png)]](https://img-blog.csdnimg.cn/bc95944024604d039ffb921138e64fac.png)
- 不可以通过指针,改变常量字符串的任意字符。
既然p里面存放的是a的地址,那么*p就是a。
现在想把a改成w,这样写可以吗?
*p='w';
输出看一下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tiukW93P-1672633238667)(D:\Typora图片\clip_image022.png)]](https://img-blog.csdnimg.cn/3c09aa2987a646ec955f75c2ff8d4bf0.png)
我们会发现,编译是没有问题的,但是运行是有问题的。
编译器崩溃:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iNxUNlAK-1672633238667)(D:\Typora图片\image-20230101114357337.png)]](https://img-blog.csdnimg.cn/d353c7f07cbf4a359655dd84f0adc81a.png)
调试看一下,出现异常:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvzJmK3P-1672633238668)(D:\Typora图片\image-20230101114626955.png)]](https://img-blog.csdnimg.cn/236e0366cf044ebbb6dc302c5d856226.png)
如果在Linux系统下会出现Segmentation fault(段错误)的错误。
写入访问权限冲突,访问非法内存。
🚘号外
当时在栈溢出的时候介绍了一个网站: www.stackoverflow.com
今天再介绍一个网站:SegmentFault 思否
再回到刚才报错的代码:
**“abcdef”**是一个常量字符串,常量字符串里面的东西不能被修改!
这里正确的写法,是需要给char* p之前加一个const。
const修饰的是*p,即p所指向的内容不能被修改,P指向的字符串不能被修改。
const char* p="abcdef";
如果要修改,就会报错:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFOiTC31-1672633238669)(D:\Typora图片\clip_image029-16725360305608.jpg)]](https://img-blog.csdnimg.cn/7f355ba8b05440e897754c3769a356ff.png)
不修改,可以正常输出:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kd4Gwl2F-1672633238669)(D:\Typora图片\clip_image030.png)]](https://img-blog.csdnimg.cn/666122a44f6b471b9de0347be478d8c7.png)
- 可以改变指针指向的字符串
这儿的“abcdef”是字符串常量,指针指向了放在只读内存区中的常量,只读区域不允许改变。
而w是字符常量,要是一个字符串,就可以。
字符串数组,赋初值的时候,系统就分配好了内存,这儿的内存在只读区域中。
如果想要修改,只能这样:(让p指针指向其他字符串)
int main(){
const char* p="abcdef";
printf("%s\n",p);
p="abc";//让p指针指向其他字符串
printf("%s\n",p);
return 0;
}
看一下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BxrcrKQF-1672633238669)(D:\Typora图片\image-20230101162518747.png)]](https://img-blog.csdnimg.cn/78f3cea5bcac446083af6fdcb885e462.png)
修改后的指针p并没有修改“abcdef”的值,而是指向了一个新的字符串。
2.字符串数组
- 先输出看一下arr里面存的字符串。
int main(){
char arr[]="abcdef";
printf("arr=%s\n",arr);
return 0;
}
输出看一下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCeUX1Md-1672633238670)(D:\Typora图片\image-20230102103106690.png)]](https://img-blog.csdnimg.cn/8b36da5138aa47c083dee800b7be177c.png)
可以输出整个字符串,也可以输出部分,比如:
int main(){
char arr[]="abcdef";
printf("%s\n",arr+2);
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzXyD1SU-1672633238670)(D:\Typora图片\image-20230102105116942.png)]](https://img-blog.csdnimg.cn/4093dfd259d7456896aa2e8f15a6a8f3.png)
- 常量字符串存放进数组,内存中是一个字符一个字符的存进去的。
比如“abcdef”存进去就是"abcdef\0"。
可以分别输出看一下:
int main() {
int i = 0;
char arr[] = "abcdef";
for (i = 0; i < 7; i++) {
printf("arr[%d]=%c\n", i,arr[i]);
}
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lIR15FPW-1672633238671)(D:\Typora图片\image-20230102103849025.png)]](https://img-blog.csdnimg.cn/8bc649554bae428fa503be563f870fab.png)
注意,arr[6]的值是0,如果没有值输出,就会输出问号,这个地方没有显示而已:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1sd6anF5-1672633238671)(D:\Typora图片\image-20230102104056686.png)]](https://img-blog.csdnimg.cn/b80f5ff80b9f4828a1477aed7714d1c6.png)
- 字符串既然是一个一个存放进数组,就可以修改字符串里面的字符。
比如,现在想修改第二个字符为h。
int main() {
char arr[] = "abcdef";
arr[1] = 'h';
printf("%c\n", arr[1]);
printf("%s", arr);
return 0;
}
输出:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01eMoHeo-1672633238672)(D:\Typora图片\image-20230102104517029.png)]](https://img-blog.csdnimg.cn/259aef3128fb45d2a6708b6f9d7238d2.png)
也不能修改整个字符串:
int main(){
char arr[]="abcdef";
arr="ghty";
printf("arr=%s\n",arr);
return 0;
}
输出报错:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-53OIhUBF-1672633238672)(D:\Typora图片\image-20230102104758297.png)]](https://img-blog.csdnimg.cn/01fb5ade45ca42708f5315b5727c5821.png)
四、面试题
1.One
有这样一道面试题:
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char* p1 = "abcdef";
char* p2 = "abcdef";
if (arr1==arr2) {
printf("hehe\n");
}
else {
printf("haha\n");
}
return 0;
}
这个面试题输出结果是多少呢?
看一下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nBh3A0vJ-1672633238673)(D:\Typora图片\clip_image032-167253603056810.jpg)]](https://img-blog.csdnimg.cn/c9a0202ff2a54dd58d01d57874f4228e.png)
❓ 为什么结果是“haha”?
我们创建了两个数组,arr1和arr2,它们在内存中一定是有两块空间的,两个数组的数组名当然是两个不同的首元素地址了。
即arr1不等于arr2的地址。所以打印“haha”。
2.Two
我们再换一个代码看看:(注意if语句里面的判断)
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char* p1 = "abcdef";
char* p2 = "abcdef";
if (p1 == p2) {
printf("hehe\n");
}
else {
printf("haha\n");
}
return 0;
}
打印输出看一下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mPUbHWs6-1672633238673)(D:\Typora图片\clip_image034-167253603059013.jpg)]](https://img-blog.csdnimg.cn/1be5699a73884a39b2fb2eb74142e61d.png)
❓ 现在打印的结果为啥是“hehe”?
常量字符串不能被修改。
两个字符串既然一模一样,又是常量字符串,各自又不能修改,没有必要再在内存中存两份。只需要拿去用,不能改它。
为了在内存中节省空间,这两个“abcdef”只存了一份。(这一点非常重要)
不管是p1还是p2,都指向同一块空间的起始位置。
而第一次没有修改代码之前,是创建两个不同的数组,地址是不一样的。
3.探究
①不妨输出看一下p1与p2指向的地址,看一下是否相同:
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char* p1 = "abcdef";
char* p2 = "abcdef";
printf("%p\n",p1);
printf("%p\n",p2);
return 0;
}
看一下结果,是一样的:(注意是它们指向的地址相同,这两个指针本身的地址是不一样的)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssLn9YBt-1672633238674)(D:\Typora图片\image-20230101123640164.png)]](https://img-blog.csdnimg.cn/d8d5eac11ea34dc08cea415d1f500d1b.png)
②再看一下p1与p2本身的地址:
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char* p1 = "abcdef";
char* p2 = "abcdef";
printf("%p\n",&p1);
printf("%p\n",&p2);
return 0;
}
输出看一下,结果是不一样的:(两个指针的本身地址不同)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t4UvfLUY-1672633238674)(D:\Typora图片\image-20230101130135040.png)]](https://img-blog.csdnimg.cn/786f7262b19e40a7891454194b894fde.png)
这里也能发现,if语句判断的是,两个指针指向的空间地址是否相同。而不是判断两个指针本身的地址。
4.补充
改变p1并不能改变p2。
更何况p1和p2指向的常量字符串是不可修改的。
p1和p2是两个独立的空间,指向同一个地址:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uo9HQ37u-1672633238675)(D:\Typora图片\clip_image036-167253603056811.jpg)]](https://img-blog.csdnimg.cn/b76ffe536b5147a0aa8f933ff8072130.png)
标准写法:
标准写法,需要给字符指针前面加上const:
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
const char* p1 = "abcdef";
const char* p2 = "abcdef";
return 0;
}
p1与p2指向的地址就是字符串的地址,如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MlCdWnDq-1672633238675)(D:\Typora图片\image-20230101194800156.png)]](https://img-blog.csdnimg.cn/4a1895c999d94d6983631d89d73d127b.png)
五、地址问题
关于上面的面试题,可能还有小伙伴不明白。
这里将它们的地址都打印出来,一起做个比较。
测试一段代码:
int main() {
char arr1[] = "abcdef";
char arr2[] = "abcdef";
char* p1 = "abcdef";
char* p2 = "abcdef";
printf("abcdef=%p\n","abcdef");
printf("&arr1[0]=%p\n", &arr1[0]);
printf("&arr2[0]=%p\n", &arr2[0]);
printf("arr1=%p\n", arr1);
printf("arr2=%p\n", arr2);
printf(" &p1=%p\n", &p1);
printf("&p2=%p\n", &p2);
printf("p1=%p\n", p1);
printf("p2=%p\n", p2);
printf("&(*p1)=%p\n", &(*p1));
printf("&(*p2)=%p\n", &(*p2));
return 0;
}
输出结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNCwMz9J-1672633238676)(D:\Typora图片\image-20230102093316040.png)]](https://img-blog.csdnimg.cn/cbd5b6a194974346ab0c5da0a2b756fd.png)
可以看到,地址大小:
“abcdef”==p1==p2==&(*p1)==&(*p2)
&arr1[0]==arr1
&arr2[0]==arr2
&p1!=&p2
内存图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmkHtEQ5-1672633238676)(D:\Typora图片\image-20230102112322060.png)]](https://img-blog.csdnimg.cn/031f8e804492408fb8f271723672183c.png)
六、字符数组与字符串数组
上边写到了字符串数组,这里提一嘴字符数组与字符串数组。
和指针无关,可自行跳过。
1.sizeof与strlen
含义
sizeof()是运算符,在头文件的类型为unsigned int,其运算值在编译时就计算好了,参数可以是指针、数组、类型、对象和函数等;
strlen()是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化为指针了。该函数完成的功能是从代表该字符串的第一个地址开始遍历的,直到遇到结束符NULL。返回的长度大小不包括NULL。
示例一
#include <stdio.h>
#include <string.h> //strlen要引头文件
int main()
{
char str[20] = "hello";
printf("strlen=%d\n", strlen(str));
printf("sizeof=%d\n", sizeof(str));
return 0;
}
结果显示为:
strlen = 5
sizeof = 20
这时的 strlen=5,sizeof=20
因为strlen计算的是字符串的长度,以\0为字符串结束标志;
而sizeof计算的是分配的数组str[20]所占的内存空间的大小,不受里面存储的内容影响。
示例二
#include <stdio.h>
int main()
{
char *str1 = "abcde";
char str2[] = "abcde";
char str3[8] = {'a'};
char str4[] = "0123456789";
printf("sizeof(str1)=%d\n", sizeof(*str1));
printf("sizeof(str2)=%d\n", sizeof(str2));
printf("sizeof(str3)=%d\n", sizeof(str3));
printf("sizeof(str4)=%d\n", sizeof(str4));
return 0;
}
结果显示为:
sizeof(str1) = 4
sizeof(str2) = 6
sizeof(str3) = 8
sizeof(str4) = 11
str1是一个指针,只是指向了字符串"abcde"而已。所以sizeof(*str1)不是字符串占的空间,也不是字符数组占的空间,而是一个指针所占的空间。在C/C++中一个指针占四个字节。(32平台)
str2是一个字符型数组,对于一个数组,返回这个数组所占的总空间,所以sizeof(str2)取得的是字符串"abcde"的总空间。"abcde"中,共有a b c d e \0六个字符,所以str2数组的长度时6。·
str3已经定义成了长度为8的数组,所以sizeof(str3)为8;
str4和str2类似,共十一个字符,所以str4所占的空间是11.
说明
示例二里面列举了一个指针,如果你验证我的代码的话,可能会是sizeof(str1) = 8
那是因为32位机器上指针大小是4个字节,64位机器上是8个字节
因为32位机器的寻址地址空间是4G,每个地址是32位,恰好是4个字节。即指针大小是4个字节。
而64位机器的每个地址是64位,是8个字节,因此指针是8个字节。
代码三
子函数中,sizeof 会把从主函数中传进来的字符数组当作是指针来处理。
指针的大小又是由机器来决定,而不是人为的来决定的。
void size_of(char str[])
{
printf("sizeof = %d\n", sizeof(str));
}
int main()
{
char str[20] = "hello";
size_of(str);
return 0;
}
结果显示为:
sizeof = 4
具体而言,当参数分别是如下时,sizeof返回的值表示的含义如下:
数组:编译时分配的数组空间的大小;
指针:存储该指针所用的空间的大小(存储该指针的地址的长度,是长整型,应该是4);
类型:该类型所占的空间的大小;
对象:对象的实际占用空间大小;
函数:函数的返回类型所占的空间大小。函数的返回类型不能是void。
代码四
#include <stdio.h>
#include <string.h>
int main()
{
char *str = "0123456789";
printf("sizeof(str) = %d\n", sizeof(str));
printf("sizeof(*str) = %d\n", sizeof(*str));
printf("strlen(str) = %d\n", strlen(str));
return 0;
}
结果显示为:
sizeof(str) = 4
sizeof(*str) = 1
strlen(str) = 10
sizeof(str): str是指向是字符串常量的字符指针,sizeof获得的是第一个指针所占的空间,应该是长整型,所以是4;
sizeof(\*str): *str是第一个字符,其实就是获得了字符串的第一位’0’所占的内存空间,是char类型的,占了1位。
strlen(str):如果要获得这个字符串的长度,则一定要用strlen。
总结
sizeof 是运算符,测量的是字符的分配大小
strlen是函数,测量的是字符的实际长度,以\0结束,所以只要strlen碰到\0就结束
2.字符数组与字符串数组
讲之前,我们还是先来回顾一下关于sizeof和strlen的用法
strlen:
- 是一个库函数;
- 计算的是字符串的长度,并且只针对字符串;
- 关注的字符串中是否有
\0,计算的是\0之前的字符个数;
sizeof:
- 是一个操作符(运算符);
sizeof是用来计算变量所占内存空间大小的,任何类型都可以使用;- 只关注空间大小,不在乎内存中是否存在
\0;
示例一
' ':表示一个字符;
" ":表示一个字符串;
- arr1里面的元素是字符,表示用字符初始化字符数组;
- arr2里面的元素是字符串,表示用字符串初始化字符数组;
#include <stdio.h>
int main()
{
char arr1[] = { 'a', 'b', 'c'};
printf("%d\n", sizeof(arr1));
char arr2[] = { "abc" };
printf("%d\n", sizeof(arr2));
return 0;
}
123456789101112
运行结果:
3
4
12
解析:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1TLztJF-1672633238682)(D:\Typora图片\watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6aOe5ZCR5pif55qE5a6i5py6,size_20,color_FFFFFF,t_70,g_se,x_16.png)]](https://img-blog.csdnimg.cn/5327de6d3e674c2586d0f67352993ed4.png)
sizeof打印的是所占空间的大小
arr1里面的元素是:'a'、'b'、'c',所以大小就是3个字节
arr2里面的元素是:a、b、c、\0,所以大小就是4个字节
示例二
#include <stdio.h>
int main()
{
char arr1[] = { 'a', 'b', 'c'};
printf("%d\n", strlen(arr1));
char arr2[] = { "abc" };
printf("%d\n", strlen(arr2));
return 0;
}
123456789101112
运行结果:
15
3
12
解析:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pzVtFkw8-1672633238683)(D:\Typora图片\watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6aOe5ZCR5pif55qE5a6i5py6,size_20,color_FFFFFF,t_70,g_se,x_16-16726254989671.png)]](https://img-blog.csdnimg.cn/a6bf24464b144bd0a73a24812c76bc06.png)
strlen求字符串长度的时候,关注的是\0;
arr1里面没有\0,所以长度是未知的,是一个随机值15;
arr2里面有\0,所以计算\0前面的,也就是a,b,c,所以长度为3;
总结
char arr1[] = { 'a', 'b', 'c' };
//arr1有三个元素,数组的大小是3个字节;
printf("%d\n", sizeof(arr1));
printf("%d\n", strlen(arr1));//长度为随机值;
char arr2[] = { "abc" };
//arr2有四个元素,数组的大小是4个字节;
printf("%d\n", sizeof(arr2));
printf("%d\n", strlen(arr2));//长度为3;
📑 参考文章:
【C语言深度剖析】深入理解字符数组和字符串数组_Albert Edison的博客-CSDN博客_c语言字符数组和字符串数组
(1条消息) 【C语言深度剖析】详解strlen与sizeof的区别及用法_Albert Edison的博客-CSDN博客
有什么问题,欢迎评论区留言。有时间看到我会回复。
如果有错误,欢迎指正。


















