字符串常量初始化指针

今天写个小文说一说字符串地址和字符串常量。

在C/C++中,一个字符串常量表示的是该字符串第一个元素的地址,就跟char指针名,char数组名表示的是字符串第一个元素的地址一样。

想要打印一个地址,用一个简单的 cout << 地址; 语句就可以搞定;

但是下面这两条语句将打印整个字符串

char a[20] = "1234";
cout << a << endl;

char *p = a;
cout << p << endl;

这也是字符数组 与其他数组不同的一个地方,那么该如何得到该字符串的地址呢?

下面有两种方法可供参考

cout << (int*)a << endl;
cout << &a << endl;

这两种方法都可以正确打印出“字符串的地址”,但是有细微区别之处

在字符数组a中,a表示第一个字符的地址,a+1表示第二个字符的地址;

在第一条打印地址的语句中,(int*)a只是起到了一个强制类型转换的作用,换句话说,a表示第一个字符的地址,但是cout <<a;输出的是整个字符串,这是因为这个地址是char*类型的,cout识别到char*类型的地址将会自动打印从该地址指向的空间开始直到遇到‘\0‘的字符串内容,所以这里我们只需要进行一个强制类型转换(这里举例强制转换为int*,可以转换为其他类型的指针,只要不是char*,哪怕是double*也可以正确打印地址)。所以如果想要第二个字符的地址呢,cout << (int*)(a+1);就可以啦

第二条打印地址的语句中,直接使用了&a;这里需要强调的是,不论任何数组,数组名表示的都是第一个元素的地址,&数组名表示的才是该数组的地址,虽然二者打印出来是同一地址,但是如果进行指针运算则天差地别,看一下下面这段代码和效果

int a[10];
cout << "a  is: " << a << " a+1  is: " << a+1 << endl;
cout << "&a is: " << &a << " &a+1  is: " << &a+1 << endl; 

有图有真相,a+1只是向后移动了4个字节,而&a+1直接向后移动了40个字节,所以&数组名表示的才是整个数组的地址。所以同理用&字符数组名也可以打印出字符串地址。

下面说一说字符串常量,首先字符串存储在静态存储区,其次,不可修改。

于是就产生了下面几条语句

char a[20] = "1234";
char * p = "1234";
const char * p = "1234";

第一条语句不用说,很常用了,正确,那么二三条语句哪个对哪个错呢。

刚开始我还觉得加不加const无所谓,反正都是错的,后来细思极恐,果然还是知识贫穷限制了想象力;

一开始我认为后面两句错的原因是因为 没见过,看着像是给*p赋了个"1234",可又不是,这是个什么东西,总之就是看着怪怪的;

所以这里就牵扯到开头提到的一个知识点了;在C/C++中,一个字符串常量表示的是该字符串第一个元素的地址,就跟char指针名,char数组名表示的是字符串第一个元素的地址一样

所以这回就明白了,看着是"1234",其实本质上是"1234"第一个字符的地址,那么将 char*型的指针p指向“1234”就没有问题啦,地址对地址嘛,但是编译后出错了,理由是"1234"是一个常量,所以加上了const限定。

关于这里为什么要加const限定才正确,如果不加的话类型也是匹配的,为什么会报错呢,所以这里需要再强调一下,"1234"是字符串常量,常量不允许被修改,如果char * p = "1234";编译成功,那就意味着"1234"有可能被修改,而这是不被允许的,所以必须乖乖听话加上const限定符让系统安心才是嘛。

咦?常量不允许被修改,要加const限定符才可以,那为什么我们一直用的第一条语句是正确的而且从来没有报错过呢?

这就要说说第一条语句和第三条语句的区别啦,"1234"是字符串常量,常量存储在静态存储区,有地址

第三条语句是让一个常量指针直接指向静态存储区的"1234"的地址,因为是直接指向本尊地址,所以要加上const限定符

而第一条语句则是将静态存储区的"1234"的副本拿出来复制到字符数组a中,所以这样初始化可以在后面随意更改副本"1234",这样并不会影响到真正的"1234";

是真地址假地址cout一下就知道了

1 char a[20] = "1234";
2 const char * p = "1234";
3 cout << &a << endl; // 获取字符数组a的地址
4 cout << &"1234" << endl; // 获取 "1234"在静态存储区的地址
5
6 //再来验证一下字符串常量为该字符串第一个元素的地址
7 cout << *"1234" << endl;
8 cout << *("1234"+1) << endl;

OK,明显副本”1234“与本尊”1234“的地址不同,而且差了很多很多地址位,肯定是跨内存区了的,最后面两行想要的结论也得到了验证,实践出真知,真是不枉我熬夜到12点。

原文地址:https://www.cnblogs.com/GuoYuying/p/11391981.html

时间: 2024-11-02 06:07:44

字符串常量初始化指针的相关文章

返回“字符串常量的指针”和“返回数组名”的区别

char*getmemory(void) { char p[]=”hello world”; return p; } void test(void) { char *str=NULL; str=getmemory(); printf(str); } 问:运行Test 函数会有什么样的结果? 由于数组p是栈上数据,返回数组名就是返回栈内存即动态数据区的地址,函数结束会被释放,所以返回的地址也就指向了不确定的位置了,str就成了乱码! 如果改成: char*getmemory(void) { cha

字符型指针与字符串常量

字符串常量在编译时系统给定存储位置,可以赋值给字符指针:此时可以通过下标进行访问,但不可以通过下标修改字符串的值. 字符指针指向字符数组时可以修改字符串的值. #include <stdio.h> #include <string.h> int main() { char a[26]; char *b = "abc"; //定义时初始化 b="123"; //可以被重新赋值 //b[1] = 'v'; //不可以被修改 a[1] = b[1]

指针和字符串和字符串常量、用gdb来获取非法内存中的信息

例程1 #include<stdio.h> int main(void) { char *s="hello"; printf("%s\n", s); s[0]="H" //因为s指针指向的字符串"hello"是字符串常量,所以不能通过指针进行更改,所以这里会产生段错误 printf("%s\n", s); return 0; } 例程2 #include<stdio.h> #incl

指针和字符串常量

指针和字符串常量 首先比较两段代码 代码1 char ch1[] = "hello"; *ch1 = 'H'; //OK ch1[0] = 'H'; //OK printf("%s\r\n",ch1); 代码2 char *ch2 = "world"; *ch2 = 'W'; //运行时错误 ch2[0] = 'W'; //运行时错误 printf("%s\r\n",ch2); 这里的"world"是字符串

字符数组,字符指针,字符串常量,以及sizeof的一些总结

1.以字符串形式出现的,编译器都会为该字符串自动添加一个\0作为结尾 如在代码中写"abc",编译器帮你存储的是"abc\0". 2.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的,如char s1[3]和char s2[4],s1的类型就是char[3],s2的类型就是char[4] 字符串常量的类型可以理解为相应字符常量数组的类型,如"abc"的类型可以看成是const char[4] 3.字符数组和指针的区别 (1)把&qu

字符串常量强制转换为字符指针

一.实验代码 #include <stdio.h> void print(char s[]); int main() { print((char *)"abcdef"); return 0; } void print(char s[]) { printf("%s\n",s); } 二.实验结果 输出:abcdef 三.调试现象 三.结论 字符串常量强制转换为字符指针,是将字符串常量的地址作为这个指针值.至于这个常量的位置还不太确定.

字符串常量与 字符指针,字符数组

1. 字符串的定义(1) char buf[10] = "hello"; //定义了10个字节的数组,但只用了6个字节存放字符串(2) char *str = "hello"; //此处hello是字符串常量,存储在长常量区,把首地址传给指针变量 sts(3) char *s = "hello"; // 指针s 与 指针str的内容都是指向字符串常量“hello” 其值相等:(4) char buff[] = "hello";

static关键字以及字符串常量的理解

一.作用域.链接属性以及存储类型: 1.      作用域:常见作用域有代码块.文件.函数以及原型作用域(只适用于在函数原型中声明的参数名). 2.      链接属性: a)        链接可以将多个目标文件链接生成最后的目标文件.链接属性则是决定如何处理在不同文件中出现的标识符. b)        链接属性总共有三种:external(外部).internal(内部)以及none(无).默认情况下标识符一般是外部或者无属性,但是,通过static关键字,则可以改变标识符的属性,将外部属

C语言中字符串常量到底存在哪了?

常量存储总结局部变量.静态局部变量.全局变量.全局静态变量.字符串常量以及动态申请的内存区 1.局部变量存储在栈中2.全局变量.静态变量(全局和局部静态变量)存储在静态存储区3.new申请的内存是在堆中4.字符串常量也是存储在静态存储区 补充说明:1.栈中的变量内存会随着定义所在区间的结束自动释放:而对于堆,需要手动free,否则它就一直存在,直到程序结束:2.对于静态存储区,其中的变量常量在程序运行期间会一直存在,不会释放,且变量常量在其中只有一份拷贝,不会出现相同的变量和常量的不同拷贝. =