指针进阶之字符指针(超详细)

news2024/11/17 11:48:10

文章目录

  • 一、回顾
  • 二、字符指针
    • 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)]

有的小伙伴说,我输出的是2啊?

别急,我配置一下这个地方。

如图,打开配置管理器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hDE90dy1-1672633238658)(D:\Typora图片\clip_image004-16725360305467.jpg)]

将平台改为x64平台:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tih1PNAt-1672633238658)(D:\Typora图片\clip_image006-16725360305265.jpg)]

这时候,再次运行,发现结果就是2:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qvUB5YfU-1672633238659)(D:\Typora图片\clip_image008-16725360305041.jpg)]

简单分析一下:

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)]

第一种理解是错误的!

第二种理解是正确的。a的地址赋值给了p。(常量字符串有什么需要注意的地方,后边讲解。)

可以输出看一下,p指针解引用之后的结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j3cbZOzQ-1672633238660)(D:\Typora图片\image-20230101105010294.png)]

输出结果是a, p里面存放的是a的地址


再想一个问题:

既然p里面存放的是a的地址,那么如果打印的话,是否能打印出来abcdef呢?

不妨试一下:

printf("%s\n",p);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMf8EjHo-1672633238661)(D:\Typora图片\image-20230101105437952.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)]

3.内存布局

还是用上面的代码;

char* p="abcdef";

这行代码的意思,来探讨一下:

①将字符串"abcdef"存放在内存中某个位置。

"abcdef"是常量字符串。

既然"abcdef"字符串放在内存中,就会有它的起始地址。

②假设它的起始地址是:0x0012ff44,

那么字符指针变量p里面存放的就是该字符串的首字符地址,即0x0012ff44。

p能够通过该地址,找到该字符串。

如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JBrF6fjr-1672633238662)(D:\Typora图片\image-20230101110932300.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)]

②这里要用p

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z2NfjssZ-1672633238664)(D:\Typora图片\clip_image018-16725360305396.jpg)]


最后再强调一下,

字符串要赋给指针变量p,不是把字符串的内容赋给p,而是把这个字符串的首字母的地址赋给了p。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPlxZVsH-1672633238664)(D:\Typora图片\clip_image020-16725360305689.jpg)]

三、字符指针与字符串数组

可能上边大家会有点晕,这里梳理一下字符指针与字符串数组。

1.字符指针

还是这行代码:

char* p="abcdef";

之前我们说过,这里的"abcdef"常量字符串,常量字符串有什么需要注意的地方呢?

  • 可以通过字符指针输出字符串
int main(){
    char* p="abcdef";
    printf("%s",p);
    return 0;
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CfSMBG75-1672633238665)(D:\Typora图片\image-20230102105524204.png)]

也可以输出部分字符串:

int main(){
    char* p="abcdef";
    printf("%s",p+2);
    return 0;
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cyc9wUGu-1672633238665)(D:\Typora图片\image-20230102105621686.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)]


  • 不可以通过指针,改变常量字符串的任意字符。

既然p里面存放的是a的地址,那么*p就是a。

现在想把a改成w,这样写可以吗?

*p='w';

输出看一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tiukW93P-1672633238667)(D:\Typora图片\clip_image022.png)]

我们会发现,编译是没有问题的,但是运行是有问题的。

编译器崩溃:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iNxUNlAK-1672633238667)(D:\Typora图片\image-20230101114357337.png)]

调试看一下,出现异常:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvzJmK3P-1672633238668)(D:\Typora图片\image-20230101114626955.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)]

不修改,可以正常输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kd4Gwl2F-1672633238669)(D:\Typora图片\clip_image030.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)]

修改后的指针p并没有修改“abcdef”的值,而是指向了一个新的字符串。

2.字符串数组

  • 先输出看一下arr里面存的字符串。
int main(){
    char arr[]="abcdef";
    printf("arr=%s\n",arr);
    return 0;
}

输出看一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCeUX1Md-1672633238670)(D:\Typora图片\image-20230102103106690.png)]

可以输出整个字符串,也可以输出部分,比如:

int main(){
    char arr[]="abcdef";
    printf("%s\n",arr+2);
    return 0;
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzXyD1SU-1672633238670)(D:\Typora图片\image-20230102105116942.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)]

注意,arr[6]的值是0,如果没有值输出,就会输出问号,这个地方没有显示而已:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1sd6anF5-1672633238671)(D:\Typora图片\image-20230102104056686.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)]

也不能修改整个字符串:

int main(){
    char arr[]="abcdef";
    arr="ghty";
    printf("arr=%s\n",arr);
    return 0;
}

输出报错:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-53OIhUBF-1672633238672)(D:\Typora图片\image-20230102104758297.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)]

❓ 为什么结果是“haha”?

我们创建了两个数组,arr1arr2,它们在内存中一定是有两块空间的,两个数组的数组名当然是两个不同的首元素地址了。

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)]

❓ 现在打印的结果为啥是“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)]

②再看一下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)]

这里也能发现,if语句判断的是,两个指针指向的空间地址是否相同。而不是判断两个指针本身的地址。

4.补充

改变p1并不能改变p2

更何况p1和p2指向的常量字符串是不可修改的。

p1和p2是两个独立的空间,指向同一个地址:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uo9HQ37u-1672633238675)(D:\Typora图片\clip_image036-167253603056811.jpg)]


标准写法:

标准写法,需要给字符指针前面加上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)]

五、地址问题

关于上面的面试题,可能还有小伙伴不明白。

这里将它们的地址都打印出来,一起做个比较。

测试一段代码:

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)]

可以看到,地址大小:

“abcdef”==p1==p2==&(*p1)==&(*p2)

&arr1[0]==arr1

&arr2[0]==arr2

&p1!=&p2

内存图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmkHtEQ5-1672633238676)(D:\Typora图片\image-20230102112322060.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;

str4str2类似,共十一个字符,所以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.字符数组与字符串数组

讲之前,我们还是先来回顾一下关于sizeofstrlen的用法

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)]

sizeof打印的是所占空间的大小

arr1里面的元素是:'a''b''c',所以大小就是3个字节

arr2里面的元素是:abc\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)]

strlen求字符串长度的时候,关注的是\0

arr1里面没有\0,所以长度是未知的,是一个随机值15;

arr2里面有\0,所以计算\0前面的,也就是abc,所以长度为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博客

有什么问题,欢迎评论区留言。有时间看到我会回复。
如果有错误,欢迎指正。

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/133891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

普通索引和唯一索引,应该怎么选择?

在前面的基础篇文章中&#xff0c;我给你介绍过索引的基本概念&#xff0c;相信你已经了解了唯一索引和普通索引的区别。今天我们就继续来谈谈&#xff0c;在不同的业务场景下&#xff0c;应该选择普通索引&#xff0c;还是唯一索引&#xff1f; 假设你在维护一个市民系统&…

基于springboot+mybatis+mysql+html实现在线教育平台系统

基于springbootmybatismysqlhtml实现在线教育平台系统1. 技术介绍2.功能介绍3. 前端3.1 首页3.2 课程3.3 登入3.4 商品兑换3.5 课程发布4. 后端4.1 登录4.2 系统管理4.3 课程管理4.4 教师管理4.5 导航菜单4.6 轮播管理4.7 通知管理4.8 礼品管理1. 技术介绍 核心技术&#xff1…

【电工技术】期末复习题

1.电路是为实现人们的某种需求&#xff0c;由 电源 、中间环节和负载三部分按一定方式组合起来&#xff0c;使电流流通的整体。 2&#xff0e;在使用叠加定理对电路进行分析时&#xff0c;通常要对电源作除源处理&#xff0c;处理方法是将各个理想电压源 短接 …

ArcGIS基础实验操作100例--实验33计算栅格统计参数

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验33 计算栅格统计参数 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

2022年终总结与展望

2022年终总结 自2019年3月13日入驻CSDN&#xff0c;已经三年零九个月了。截至2022年12月31日&#xff0c;CSDN博客已发原创博文112篇&#xff0c;粉丝3616个&#xff0c;访问量超过157万次。 2019年12月31日数据情况&#xff1a; 2020年12月31日数据情况&#xff1a; 2021年1…

7-9 包装机

一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道&#xff0c;放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时&#xff0c;活塞向左推动&#xff0c;将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时&#xff0c;机械手将抓取筐顶部的一件物品&#x…

尚医通- Nacos服务注册 医院列表接口(二十一)

目录&#xff1a; &#xff08;1&#xff09;后台系统-医院管理-需求和Nacos启动 &#xff08;2&#xff09;医院列表-Nacos注册服务 &#xff08;3&#xff09;医院列表接口-初步实现 .&#xff08;1&#xff09;后台系统-医院管理-需求和Nacos启动 之前我们完成了数据相…

基于Java+Swing实现捕鱼达人游戏(含课程报告)

基于JavaSwing实现捕鱼达人游戏&#xff08;含课程报告&#xff09;一、系统介绍1、开发背景2、基本内容、实现方法及主要技术实现目标3实现目标二、功能展示三、其他系统一、系统介绍 1、开发背景 捕鱼达人这个项目是一个娱乐性的游戏开发&#xff0c;本次游戏的程序设计包含…

Spring6笔记4

十四、GoF之代理模式 14.1 对代理模式的理解 代理模式中有一个非常重要的特点&#xff1a;对于客户端程序来说&#xff0c;使用代理对象时就像在使用目标对象一样。【在程序中&#xff0c;目标需要被保护时】 业务场景&#xff1a;系统中有A、B、C三个模块&#xff0c;使用这…

移动Web【Flex布局模型构成 主轴对齐方式 侧轴对齐方式 伸缩比】

文章目录Flex布局Flex布局模型构成主轴对齐方式侧轴对齐方式伸缩比Flex布局 思考 多个盒子横向排列使用什么属性&#xff1f; 浮动 设置盒子间的间距使用什么属性&#xff1f; margin 需要注意什么问题&#xff1f; 浮动的盒子脱标 Flex布局/弹性布局&#xff1a; 是一种浏览…

06-07-SpringAop

介绍下AspectJ和AOP和关系 AspectJ是java编程语言的无缝的面向方面的扩展&#xff0c;可以在java代码的字节码中植入切面代码。 AspectJ 是静态代理的增强&#xff0c;所谓的静态代理就是 AOP 框架会在编译阶段生成 AOP 代理类&#xff0c;因此也称为编译时增强。 AspectJ 是…

手把手代码实现五级流水线CPU——第一篇:初级顺序流水线

文章目录指令系统编码格式一、基础&#xff1a;顺序结构1.取值阶段&#xff1a;2.译码阶段3.执行阶段4.访存阶段5.写回阶段6.更新PC阶段详细硬件结构指令在各个阶段完成的操作C代码实现指令系统 编码格式 一、基础&#xff1a;顺序结构 1.取值阶段&#xff1a; 根据icode还可以…

【FPGA开发】Verilog 基础

写在前面&#xff1a;本章将对 Verilog 进行简要介绍&#xff0c;并对其基本特性进行讲解说明。之后&#xff0c;我们将按步骤演示如何使用 Vivado 创建简单项目。手动实践部分将根据我们提供的 .v 和 .tb 代码&#xff0c;跟着步骤跑出 Simulation 结果即可。 Ⅰ. Verilog 基础…

Odoo 16 企业版手册 - 库存管理之产品追溯

产品追溯 Odoo提供的产品可追溯性功能将有助于跟踪和跟踪产品的每个组件。在库存移动的每个阶段跟踪产品对于控制所有操作是必要的。为了确保有效监控库存的走势&#xff0c;批号和序列号发挥着重要作用。从制造过程到交付操作&#xff0c;产品可追溯性将保持适当的跟踪&#x…

Mixlab 的自我介绍

‍‍‍‍2022在探索元宇宙落地过程中&#xff0c;走过不少弯路&#xff0c;本着 “孵化” 的初心&#xff0c;我们将继续探索面向未来的社区模式。1 / Mixlab 无界社区社区即服务&#xff0c;以此作为基础&#xff0c;孵化各种形态的产品/服务。在2022的白皮书记录了我们做社区…

数据结构与算法—链表之单链表

文章目录链表单链表结构和特点创建添加修改删除2023年的第一篇文章在开发过程中&#xff0c;选择合适的数据结构是很重要的&#xff0c;可以快速处理数据的存储及使用问题。计划有时间慢慢系统的学习《数据结构与算法》&#xff0c;看看视频&#xff0c;练习实践&#xff0c;最…

国产FPGA应用--易灵思Programming Mode完全解析

本文介绍易灵思的几种配置模式&#xff0c;方便大家参考。 一、易灵思下载模式&#xff1a; 二、下载模式选择&#xff1a; 1、SPI Active mode 时序图如下&#xff1a; 2、SPI Passive Mode 时序图如下&#xff1a; SPI Active using JTAG Bridge 实际项目中&#xff0c;SPI…

锥度张力控制(收卷应用)

收卷、放卷应用系列文章可以参看下面的文章链接: 变频器简单张力控制(线缆收放卷应用)_RXXW_Dor的博客-CSDN博客_收放卷应用张力控制的开闭环算法,可以查看专栏的其它文章,链接地址如下:PLC张力控制(开环闭环算法分析)_RXXW_Dor的博客-CSDN博客。https://blog.csdn.ne…

excel筛选技巧:不用函数公式也能快速多对多查找

说到excel中的筛选&#xff0c;想必大家早已是了如指掌&#xff0c;不过增强版的筛选&#xff0c;你听说过吗&#xff1f;它可比普通的筛选厉害多了&#xff0c;不仅能实现excel中的一对多查找&#xff0c;就连复杂的多对多查找也不在话下&#xff01; 其实是使用公式还是用其…

原子性 以及悲观锁, 乐观锁

1. 前言 今天这篇文章要详细的说说&#xff0c;什么叫原子性&#xff0c;以及如果不是原子性的话&#xff0c;怎么能保证原子性。 2. 原子性 先说下并发编程的三大特性&#xff1a;可见性, 有序性, 原子性。 无论是在什么语言&#xff0c;原子性都是非常重要的&#xff0c;既然…