0%

char* 与 char []的区别

char* 与 char []的区别

起源于一次写处理字符串的函数时,使用了char*创建字符串,然后编译运行通过,但是有warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings],然后查了相关资料把这个问题搞懂了。

指针常量与常量指针

首先,我们需要搞懂指针常量与常量指针的区别

指针常量

指针类型的常量

语法:char* const p;

这里的指针p就是一个指针常量,其特点是

  • p的指向是不可以修改的
  • p指向的值是可以修改的

也就是说const是作用在p上的

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
char ch = 'a';
char c = 'b';
char* const p = &ch;
printf("ch : '%c', address : %0x\n",ch,&ch);
printf("*p : '%c', address : %0x\n",*p,p);
//不可以修改p的指向
// p = &c; //会报错是不可修改的 error: assignment of read-only variable 'p'
//但是我们可以直接修改p指向的值
*p = 'm';
printf("ch : '%c', address : %0x\n",ch,&ch);
printf("*p : '%c', address : %0x\n",*p,p);

printf("c : '%c', address : %0x\n",c,&c);
return 0;
}
/*输出
ch : 'a', address : 6ffe17
*p : 'a', address : 6ffe17
ch : 'm', address : 6ffe17
*p : 'm', address : 6ffe17
c : 'b', address : 6ffe16
*/

常量指针

指向“常量”的指针

语法:const char *p;或者char const *p;

这里的指针p就是一个常量指针,其特点是

  • p的指向是可以修改的
  • p指向的值是不可以修改的

也就是说const是作用在*p上的
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
char ch = 'a';
char c = 'b';
const char* p = &ch;
printf("ch : '%c', address : %0x\n",ch,&ch);
printf("*p : '%c', address : %0x\n",*p,p);
//可以修改p的指向
p = &c;
printf("p的指向修改后\n");
//不可以修改p指向的值
// *p = 'm'; //会报错提示我们表达式必须是可修改的左值
printf("ch : '%c', address : %0x\n",ch,&ch);
printf("*p : '%c', address : %0x\n",*p,p);
printf("c : '%c', address : %0x\n",c,&c);
return 0;
}
/*输出
ch : 'a', address : 6ffe17
*p : 'a', address : 6ffe17
p的指向修改后
ch : 'a', address : 6ffe17
*p : 'b', address : 6ffe16
c : 'b', address : 6ffe16
*/

字符串常量保存在哪?

先看例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
static int num = 10;
char *s = "test";
void a(){
char* sa = "test";
printf("指针sa的地址: 0x%0x\n", &sa);
printf("指针sa指向的字符串的地址: 0x%0x\n", sa);
}
int main()
{
cout<<"static num address: "<<&num<<endl;
printf("指针s的地址: 0x%0x\n", &s);
printf("指针s指向的字符串的地址: 0x%0x\n", s);
a();
char* sb = "test";
printf("指针sb的地址: 0x%0x\n", &sb);
printf("指针sb指向的字符串的地址: 0x%0x\n", sb);

char* sc = "test";
printf("指针sc的地址: 0x%0x\n", &sc);
printf("指针sc指向的字符串的地址: 0x%0x\n", sc);
return 0;
}
/*输出结果
static num address: 0x469010
指针s的地址: 0x469018
指针s指向的字符串的地址: 0x47e001
指针sa的地址: 0x6ffdd8
指针sa指向的字符串的地址: 0x47e001
指针sb的地址: 0x6ffe18
指针sb指向的字符串的地址: 0x47e001
指针sc的地址: 0x6ffe10
指针sc指向的字符串的地址: 0x47e001
*/

说明:在这个程序中,我们在不同的地方都创建了字符串"test",全局指针变量s,函数a()内的临时指针变量samain()函数中的指针变量sbsc,但是通过输出地址发现它们都指向了同一块内存空间。

而且结合上面的结果和c++中的内存分区模型,我们可以看出,变量nums,和"test"都被放在了全局区里面。而sa,sb,sc都放在栈区里面。

因此,从上面这个程序我们可以看出

一旦有字符串常量在运行期间被创建出来,就会在内存中一直保持到程序结束,当使用相同的字符串常量的时候,不会再创建字符串常量,而是指向之前创建的那个。因此字符串常量是贯穿整个程序的生命周期的。

字符串变量的保存在哪?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
const char *s = "test";
char ss[] = "test";
void a(){
char ssa[] = "test";
const char* sa = "test";
printf("指针sa的地址: 0x%0x\n", &sa);
printf("指针sa指向的字符串的地址: 0x%0x\n", sa);
printf("ssa的地址: 0x%0x\n", &ssa);
}
int main()
{

printf("指针s的地址: 0x%0x\n", &s);
printf("指针s指向的字符串的地址: 0x%0x\n", s);
printf("ss的地址: 0x%0x\n", &ss);
cout<<"---"<<endl;
// printf("ss指向的字符串的地址: 0x%0x\n", ss);
a();
char ssb[] = "test";
const char* sb = "test";
cout<<"---"<<endl;
printf("指针sb的地址: 0x%0x\n", &sb);
printf("指针sb指向的字符串的地址: 0x%0x\n", sb);
printf("ssb的地址: 0x%0x\n", ssb);
return 0;
}
/*输出
指针s的地址: 0x46a010
指针s指向的字符串的地址: 0x47f001
ss的地址: 0x46a018
---
指针sa的地址: 0x6ffdb8
指针sa指向的字符串的地址: 0x47f001
ssa的地址: 0x6ffdc0
---
指针sb的地址: 0x6ffe08
指针sb指向的字符串的地址: 0x47f001
ssb的地址: 0x6ffe10
*/

这里就可以看出变量和字符串常量的区别了。尽管ss,ssa,ssb它们在内容上都是一样的,但是因为是变量,所以都需要单独开辟空间储存。而不能像常量*s*sa*sb一样只用一块儿空间。

关于char *

先看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
char *s = "1234";
//warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
//我们也可以通过改为 const char *s = "1234";变为常量指针来解决
cout<<s<<endl;
printf("%0x\n",s);
// s[0] = 'a';
// 有人可能会尝试这样来修改某一个位置上的元素,毕竟我们知道一个字符串的名字就是其字符串的首地址
// 然而这样做会直接导致程序中断,因为我们的"1234"是常量,而常量是不可以修改的
cout<<s<<endl;
char ch = 'a';
s = &ch;
cout<<*s<<endl;
printf("%0x\n",s);
return 0;
}
/*输出
1234
4aa031
1234
a
73fe17
*/

关于char []

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
char s[] = "1234";
// 作用上相当于 char * const s; 我们可以修改s指向的值,但不能修改s的指向
cout<<s<<endl;
printf("%0x\n",s);
s[0] = 'a';

cout<<s<<endl;
char ch = 'a';
// s = &ch; //会报错,这是不允许的
cout<<*s<<endl;
printf("%0x\n",s);
return 0;
}
/*输出
1234
6ffe10
a234
a
6ffe10
*/

总结

目前两种使用方式:

  • const char* p = "abc";

p可改,*p不可改

  • char s[] = "abc";

s不可改,s[]中的内容可改

-------------本文结束感谢您的阅读-------------