char* 赋值 const char* 释放_char *s和char s[]

本文探讨了C语言中`char*`与`const char*`类型的指针在赋值和释放时的区别,强调了字符串常量区的不可修改性。通过示例代码解释了指针变量与数组的区别,分析了不同赋值操作可能导致的段错误,并提醒读者注意指针操作的安全性。
摘要由CSDN通过智能技术生成

微信原文

你知道char *s和char s[]的区别吗?​mp.weixin.qq.com
cd3aca78627c999fa7a7955b00c26ab9.png

在一个夜深人静的晚上,有一个读者给我发了一个C语言题目。他问我,发哥,帮我看看这个代码有什么问题。我看了代码之后,心里一阵恐慌。我自认为我不是C语言高手。但是我确实是一个喜欢解决问题的男人。就是在这样的背景驱使下,我写下了这篇文章。

char *str1 = "hello";   
char str2[] = "hello";

我们看这两个定义。我们说这个是定义而不是声明,是因为定义在内存里面分配了房子。而声明,只给了个房产证却不给你分房子。

str1 这个类型是 char * 。它是一个指针,这个指针指向一个字符串。 str2 这个类型是 char [] 。它是一个数组,他代表了这堆内存空间。

“hello”字符串在内存中是这样存放的

e90c1f490803f786860cad9e980fdb1b.png

c4bf0e2d010dbe5e422858f1326475ec.png

我之前写过一个地址分配的文章,str1 str3都是指向字符串的指针,而且这个字符串是保存在字符串常量区的。这个常量区里面的东西是不能被修改的。编译器让他们指向了同一个地址。这个地址保存的东西是 “hello”这个字符串。

大家看看下面这个代码有什么问题?

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(void)
{
	char *str1 = "hello"; 
	char *str3 = "hello";
	char str2[] = "hello";
	
	memcpy(str3,"worldtest",strlen("worldtest")+1);

	printf("str1:%s str3:%s str2:%sn",str1,str3,str2);

	str3 = "world";
	printf("str1:%s str3:%s str2:%sn",str1,str3,str2);
	printf("hello,worldn");
	return (0);
}

如果改成这样的呢?应该输出什么结果呢?

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(void)
{
	char *str1 = "hello"; 
	char *str3 = "hello";
	char str2[] = "hello";
	
	//memcpy(str3,"worldtest",strlen("worldtest")+1);

	printf("str1:%s str3:%s str2:%sn",str1,str3,str2);

	str3 = "world";
	printf("str1:%s str3:%s str2:%sn",str1,str3,str2);
	printf("hello,worldn");
	return (0);
}

我之前在文章里面讨论一个问题,我们说指针的时候,要说指针变量。保存地址的是一个地址。这个地址保存的地址是可以变化的。只要类型符合。都可以保存起来。

3e5d037e1f15e9bec77552e98bdeb95e.png

同样的,在上面的例子中,如果我们尝试这样

str1[1] = 'a';

这样也是错误的。

试试下面这段代码

#include <stdio.h>
int main(){
   char* str1="Hello";
   printf("nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   str1 = "world";
   printf("nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   return 1;
}

输出

str1: Hello, address: 0000000000404000, sizeof(str1): 8
str1: world, address: 0000000000404031, sizeof(str1): 8
--------------------------------
Process exited after 0.0226 seconds with return value 1
请按任意键继续. . .

通过赋值运算后,str1的值也发生了改变。

但是str2情况会不一样,str2是一个数组。

b288ca096e4a5cb037b0bb27ca10099e.png

既然是数组,我们看看这段小代码

#include<stdio.h>
int main(){
 char str2[] = "hello";
 printf("nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 str2[2] = 'A';
 printf("nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 strcpy(str2, "world");
 printf("nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 return 1; 
}

输出日志

str2: hello, address: 000000000062FE10, sizeof(str2): 6
str2: heAlo, address: 000000000062FE10, sizeof(str2): 6
str2: world, address: 000000000062FE10, sizeof(str2): 6
--------------------------------
Process exited after 0.04063 seconds with return value 1
请按任意键继续. . .

送一个图

9dfe588ca4491f259d58d17f0202f818.png

晚上回来我写了一个小程序。大家看看

#include <stdio.h>
#include "stdlib.h"
#include "string.h"

const int a = 1;
const int a1 = 1;
char * s = "hello";

int main()
{
	const int b = 2;
	const int b1 = 2;
	char * s1 = "hello";
		
	printf("s:%p s1:%pn",s,s1);
	printf("a:%p a1:%p b:%p b1:%pn",&a,&a1,&b,&b1);
	
	return 1; 
}

输出如下:

s:0000000000404008 s1:0000000000404008
a:0000000000404000 a1:0000000000404004 b:000000000062FE14 b1:000000000062FE10

--------------------------------
Process exited after 0.03901 seconds with return value 1
请按任意键继续. . .

可以看到,s,s1,a,a1都是在一个内存区域。这个内存区域的内容是不允许改变的。如果你对这里的内存区域赋值,就会出现段错误。

但是b和b1这个内存区域大家看看。我们可以写个小代码测试一下。

#include <stdio.h>
#include "stdlib.h"
#include "string.h"

const int b = 2;

int main()
{
	const int b1 = 2;
	int *p = &b1; 
	printf("b1:%dn",b1);
	*p = 3;
	printf("b1:%dn",b1);
	
	return 1; 
}

输出:

b1:2
b1:3

--------------------------------
Process exited after 0.0403 seconds with return value 1
请按任意键继续. . .

但是我们写成这样呢?

#include <stdio.h>
#include "stdlib.h"
#include "string.h"

const int b = 2;

int main()
{
	const int b1 = 2;
	int *p = &b; 
	printf("b:%dn",b);
	*p = 3;
	printf("b:%dn",b);
	
	return 1; 
}

输出:

b:2

--------------------------------
Process exited after 3.743 seconds with return value 3221225477
请按任意键继续. . .

如果放到gcc下,可以看到,执行到代码

*p = 3;

会出现段错误。因为访问了不能访问的地址。这也就是我们很多时候给空指针赋值出现段错误的原因。操作了非法的地址。

好了,就瞎BB这么多,如果觉得有用,可以留言一起讨论下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值