一个 c 风格字符串与指针问题

2017-05-09 15:27:09 +08:00
 di94sh
char *s1=“ hello ”;
char *s2=“ xello ”;
*s2= *s1 ;
这样为什么不行呢。
我希望 printf s2 输出一个 hello

这样编译可以,运行出错。环境试了 gcc 与 vs2010
4216 次点击
所在节点    C
54 条回复
xinglp
2017-05-09 15:33:45 +08:00
char s1[] = “ hello ”;
char s2[] = “ xello ”;
*s2 = *s1 ;
di94sh
2017-05-09 15:35:44 +08:00
@xinglp 那样可以我是知道的,但是指针不是指向字符串头地址也就是 s2 的指针指向 x 吗。为什么这样操作不行呢
choury
2017-05-09 15:38:02 +08:00
s1 是指针,*s1 是 h
你应该用 s2=s1
wevsty
2017-05-09 15:40:25 +08:00
@di94sh *s2 是指向 x 没错,但是“ xello ”是一个字符串常量,字符串常量在编译的时候是保存在一些不可修改的区域,所以你下改动理所当然的会失败。
coderluan
2017-05-09 15:41:52 +08:00
再好好看看书,问这个问题说明你没理解指针:
指针只是指向一块内存,并不会开辟内存,你这个只是指向了文字常量区的数据而已。
coderluan
2017-05-09 15:44:37 +08:00
看了 2L,说你没理解 C 语言内存分配更准确些。
czzhengkw
2017-05-09 15:48:31 +08:00
C 语言没有字符串赋值操作,要用 strncpy 或者 memcpy 函数……

字符串其实是字符数组
paradoxs
2017-05-09 15:51:40 +08:00
#include <stdio.h>

int main(int argc, const char * argv[]) {
char *s1= "hello";
char *s2= "xello";
s1= s2 ;
printf("%s\n",s1);
return 0;
}
msg7086
2017-05-09 15:53:56 +08:00
*s2 的确是 x,但是是常量 x 不是变量 x。
修改常量,我不记得是一定会炸还是未定义行为了。
eoyx
2017-05-09 16:04:27 +08:00
你应该往更底层学,当你学了 32 位汇编之后就知道是怎么回事了
在 c 这个层面的解释都是不准确的,什么狗屁常量区,不懂装懂,根本就没有这个概念

x86 内存管理->保护模式->分段保护模式->数据段描述符->存储段可写位
jinhan13789991
2017-05-09 16:10:51 +08:00
java 程序员瑟瑟发抖
buf1024
2017-05-09 16:13:30 +08:00
@wevsty 正解。
jiankangxin
2017-05-09 16:17:53 +08:00
@jinhan13789991 哈哈哈
drlalll
2017-05-09 16:24:12 +08:00
https://www.drlalll.com/2017/03/01/cyu-yan-bian-cheng-zhi-zhen-wei-shi-yao-bu-neng-gei-zi-fu-chuan-fu-zhi-xiang-jie/
正好我前段时间研究了下,主要来说还是常量变量的原因。
drlalll
2017-05-09 16:26:19 +08:00
@drlalll s1=s2 是可以的,主要是*s1 和*s2 的值都是常量
bombless
2017-05-09 16:26:20 +08:00
说 strcpy 或者 memcpy 没看完问题吧……
这个其实是因为在常见的设计中匿名数组位于一个不可写的位置。
在操作系统中这些位置在内存不足的时候可以丢掉,需要时再从新读出来,甚至不用占据虚拟内存(顺便说下这套机制称为是文件内存映射,Linux 和 Windows 都用的这样的机制来执行程序)
drlalll
2017-05-09 16:27:28 +08:00
@drlalll 有时候对指针不明白可以把它的内存地址打印出来做做参考
bombless
2017-05-09 16:33:34 +08:00
至于说 po 主说的怎样修改的问题
在 Windows 下可以通过 VirtualProtect 把这段不可写内存重新设为可写 https://msdn.microsoft.com/en-us/library/windows/desktop/aa366898
在 Linux 下是 mprotect,http://man7.org/linux/man-pages/man2/mprotect.2.html
pright
2017-05-09 16:51:34 +08:00
其实很简单,楼主这个试图修改指向常量字符串指针的操作在 C 语言规范里面是未定义行为,就是说你这样做了不保证会发生任何事,可能在这个平台的实现上正常工作,也可能在另个平台的实现上导致你电脑爆炸,楼上那些扯到什么 32 位汇编什么的完全就是不知所云。

The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type ''pointer to char'' and initializes it to point to an object with type ''array of char'' with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

http://port70.net/~nsz/c/c99/n1256.html#6.7.8p32
eoyx
2017-05-09 17:02:53 +08:00
@pright 傻逼不懂就谦虚点,别像个畜生一样愚昧无知还这么张狂
本质就是 32 位汇编对于分段管理机制的表现,18L 都给出了修改方法

你这个弱智的傻逼没学过不代表它就不可能
大庭广众说话前先要点逼脸,当众秀无知不能提高你家族的智力水平

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/360139

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX