搜索

首页  >  问答  >  正文

字符串 - C++中字符常量有什么用?

刚学C++,看书上说几种常量,数值常量我能理解,PI是个好例子。但是字符常量又要作何解?转义字符这个倒还好理解,有个实际用处单独定义出来。但是还有普通的字符常量,这个我就非常理解不能了,请问大家能不能给个例子证明这个有什么用?而且只能单引号什么的其实也挺纠结的。
另外,C++是不是强语言,每个变量都必须定义类型什么的?没办法,从PHP转过去的,挺纠结这些基本问题的╮(╯▽╰)╭...
再来就是定义字符串常量查到好几种方法:

#include<string>
string url = "segmentfault.com";
const char url[] = "segmentfault.com";
const char *url = "segmentfault.com";
const char* url = "segmentfault.com";

请问哪个好点?另外最后两个的*号做何解...新手问题还望大家要淡定,别凌乱就好。。。。

伊谢尔伦伊谢尔伦2807 天前735

全部回复(3)我来回复

  • 大家讲道理

    大家讲道理2017-04-17 11:04:23

    先说说这几个例子的区别吧:
    1、

    #include<string>
    string url = “segmentfault.com”;

    url是一个string对象。为了更加容易地操纵字符串,cpp为我们定义了一个string类(string并不是cpp的关键字),你可以通过它来定义字符串对象,然后通过调用它的方法来获取该字符串的信息,例如获取它的长度:
    url.length()
    又或者对它进行操纵,例如拼接:

    string scheme = “http://”
    cout << scheme+url << endl; //输出http://segmentfault

    2、
    下面的三种写法都可以看作是一种:

    const char* url = “segmentfault”;

    因为 const char url[](字符数组),数组名url在编译时会被隐式转为为指针char*,指向字符串的首个字符's'。至于*号的位置,有人喜欢把它放到靠近类型,有人喜欢把它放到靠近变量名,这里有一个关于这个问题讨论的topic

    http://topic.csdn.net/u/20101117/10/f...

    又因为是常量字符串,所以你不能对它进行修改

    url[0]='x';//错误,不可以进行修改,就算没有用const来修饰,也不可以

    但是在string中却可以

    string url = “segmentfault.com”;
    url[0] = 'x';//OK

    这是因为string为我们承担了管理内存的任务。如果你想要对它进行拼接,你需要自己写一个函数,又或者调用cstring库中的strcat或strncat函数。

    在c/cpp中,*有两种作用,一种是用来定义指针类型,char* 就是字符指针。另外一种就是取值,取指针指向的值,想上面所说的

    const char *url = “segmentfault”;

    url是指向字符串的首个字符,所以你对指针url取值,得到的就是字符's'

    cout << *url << endl;//输出's'

    所以,总的来说,string用起来会比较方便,常量字符串在操纵起来就有点麻烦,也可以说是灵活吧,什么时候用哪个,就需要你自己衡量了。至于性能上,我想我还没有能力来分析!

    回复
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 11:04:23

    补充一下 @Henry 的答案
    字符串数组和指针,虽然两个很相似,数组可以在使用时退化成指针使用,但是两个概念上就不一样。
    关键的一点在于,指针存放的是一个地址
    举个例子:

    const char str[] = "segmentfault.com";
    const char *str_ptr = "segmentfault.com";
    
    // sizeof(str) == 17
    // sizeof(str_ptr), 平台相关, x86的目标文件一般为4(32位), x86_64的目标文件一般为
    //   8(4位)

    EDIT:

    利用这点可以在编译时就确定出字符串的长度。

    理解了指针是地址之后,下面的错误就不会犯了:

    define.c

    // 定义该字符串常量
    const char str[] = "segmentfault.com";

    main.c:

    // 错误的声明
    extern const char *str;
    // 正确的声明
    //extern const char str[];
    
    int main()
    {
        // 产生段错误
        // 原因: str本来是数组,但是声明为了指针
        //   假设目标文件是32位 x86 小端格式
        //   则实际访问的错误地址是 0x6d676573 (刚好就是segm这4个字符的ASCII码)
        printf("%s\n", str);
        return 0;
    }

    回复
    0
  • 高洛峰

    高洛峰2017-04-17 11:04:23

    由于历史原因,c++兼容c的字符串。c风格字符串使用char[]或者const char *来表示。字符串字面值也被编译器推导为const char *

    windows环境下,字符串编译后被存在.rsrc区段中(区段是可以随意改名的,不同编译器实现也可能不同,可以打开peid去查)。这个区段是只读的,你如果强行写入程序会崩溃,所以为了保险起见给你const char *

    但是现代的c++编程不提倡用c风格字符串(就像obj-c也不提倡使用c风格字符串,而是NSString),所以你只要记住上面那一点,并且使用std::string就好了。遇到c风格字符串,如果你要使用,应该马上用string的构造函数转换为string

    记住,你写的是c++,不是c!

    构造函数调用有两种形式,一种是函数形式,比如string url("segmentfault.com")。但是,特别地,如果构造函数只有一个参数,可以写成赋值形式,即:

    #include<string>
    string url = "segmentfault.com";

    只要这是对象的初始化,而且存在相应的构造函数,就会编译成构造函数的调用。而不是先创建string,再调用operator =。上面那句话的实际作用是拿const char *来构造string

    或者如果你想让编译器推断为string类型,在它后面加个s。

    auto url = "segmentfault.com"s;

    你如果用char []保存字符串,那它是存在栈上的。

    是因为原生数组的名字,可以被编译器推导为低一级的指针,指向数组起始位置,比如char[]在使用时会被当作char *

    char[]和别的数组不同的地方还在于可以用字符串字面值初始化。

    如果你这样写:

    char str[] = "segmentfault.com";

    就相当于

    char str[] = {'s','e','g','m','e','n','t','f','a','u','l','t','.','c','o','m','\0'};

    回复
    0
  • 取消回复