当前位置:   article > 正文

关于字符串常量与指针 - 快速记录暂时未整理_数组名是个常量为什么不是保存在.rodata区域

数组名是个常量为什么不是保存在.rodata区域

字符串常量储存在.rodata,只读数据区

char* a = "Hello";
// 或者
const char* a = "Hello"
printf("Hello");
// 这里两个Hello的地址都是同样的 通过反汇编可知

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

1.char* a这种写法是C语言时代的
2.const char* a是CPP语言的
在CPP中使用第一种写法会报错,在C中并不会报错,所以即使修改值也不会引发编辑器报错,但是在运行时会报错,因为修改了只读区域,产生了异常控制流,强制停止进程运行。
所以我个人觉得CPP对此进行了改进,在编辑器层面避免了这种不必要的写法(修改了就一定出问题的写法,肯定得从编译时就抹杀掉。。),因此字符串变成了字符串常量const char*

char b[] = "Hello"
  • 1

字符串数组是可以修改的,因为是储存在栈中的,在上面的反汇编中可以看出,它也是中只读区域将Hello复制到栈中的。所以这就是为什么const char* 的可以赋值给 char []。

const char*a = "Hello";
a = "World";
  • 1
  • 2

在这里插入图片描述
若想改变a的值,那就得赋予它同样的类型,就是得同样是只读区域的值(地址),因此想要单独修改某个字符是做不到的。

// a[i] = 'd';
// a+1 = 'c';
类似这种操作都是行不通的,类型不符合的同时操作也非法,修改只读区域
  • 1
  • 2
  • 3

同时注意一点,一个变量它是有两个属性的,一个是值,一个是地址。
在这里插入图片描述

一般VS不会标识出地址

地址和值都可以被打印出来。
一般来讲,值是地址的内容。但是不可以认为值就是数值之类的东西例如(1,2,3,a,b),有时候值也会是一个地址。就如同上面的char a*它值就是一个地址。
而且一般值是数值之类的东西的话,会直接放在寄存器上,所以它也就没有了地址。例如

int a = 1;
  • 1

这个时候a是没有地址的,但是如果你去打印a的地址时,它就会把a的内容放到内存上(栈上),所以a就有了地址。有点像量子你观测我我就存在。。。但其实不是的哈,只是设计如此,只有需要地址时,函数内局部变量才会被放到栈上,或者寄存器不够用的时候也会将超出的变量放置在栈上。

更多介绍
字符串常量引起的思考

指针

一个变量它是有两个属性的,一个是值,一个是地址

接着上说讲,我们在vs中见到的都是值,这个值其实都是存放在栈中或者直接存放在寄存器中的,也如同上面所说的,如果我们不去打印地址,那么它一般不会将我们的值存放到栈上的。还有一种情况就算寄存器用完了,也会放到栈上。以下的讨论我们默认都认为我们的值是直接放在寄存器中的。明白了这一点,那么我们对指针的操作就会简单很多。
其实好像也没有什么不同,毕竟寄存器的值都是从内存上读取的。

int* a1 = (int*)malloc(4);
int* a2 = (int*)malloc(4);
*a1 = 1;
*a2 = 2;
											  // 假设 a1的值为0x00000000000000a1,a2的值为0x00000000000000a2。为了简写后面我省略一下。
__int64 * bp1 = (__int64*)malloc(16);         // 首先我们申请两个可以容纳地址大小的空间
*bp1 = (__int64)a1;                           // *bp1,寻址,找到*bp1地址处,然后设置为a1的值,因为a1的值是个地址,且地址处的值是1。(__int64)a1,强制将a1的值表示为 __int64 整数类型,这样才可以设置进入内存。
__int64* bp2 = (__int64*)(*bp1);              // 将我们的值转化为地址。(*bp1)先是将值取出,此时值为0x00a1。(__int64*)(*bp1)强制将值当作地址对待。0x00a1值是一个__int64类型的整数,编译器无法识别,所以我们要告诉它。
printf("a1 = %d\n", *bp2);                    // *bp2,寻址,找到*bp2地址处的值,然后显示出来。
//printf("a1 = %d\n", *(__int64*)(*bp1));
bp1 = bp1 + 1;                                // 寄存器上的值移动一个__int64单位字节
*bp1 = (__int64)a2;
printf("a2 = %d\n", *(__int64*)(*bp1));

// 结果
//a1 =1 
//a2 = 2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

1-4行
在堆上申请了两个存放数值的空间,a1/a2的值是堆的地址。然后我们寻址,找到a1地址处,然后设置这个地址处的内容,也就是*a1表示的意思了。

6-13行
这个是为了验证上面所提的,一个变量两个属性。

下面这个是个简单版本

int* a1 = (int*)malloc(4);
int* a2 = (int*)malloc(4);
*a1 = 1;
*a2 = 2;


int** bp = (int**)malloc(16);
*bp = a1;
printf("a1 = %d\n", **bp);
bp = bp + 1;
*bp = a2;
printf("a2 = %d\n", **bp);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

个人觉得这个表示的不是很清晰,就是后面在去看,可能就有些看不懂了,得捋一下。当然了,平常写代码肯定是简单版本。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/319509
推荐阅读
相关标签
  

闽ICP备14008679号